1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef UNIX_FIFO_H
6#define UNIX_FIFO_H
7
8#include <Referenceable.h>
9
10#include <condition_variable.h>
11#include <lock.h>
12#include <util/AutoLock.h>
13#include <util/DoublyLinkedList.h>
14
15#include <net_buffer.h>
16
17
18#define UNIX_FIFO_SHUTDOWN_READ		1
19#define UNIX_FIFO_SHUTDOWN_WRITE	2
20
21#define UNIX_FIFO_SHUTDOWN			(B_ERRORS_END + 1)
22	// error code returned by Read()/Write()
23
24#define UNIX_FIFO_MINIMAL_CAPACITY	1024
25#define UNIX_FIFO_MAXIMAL_CAPACITY	(128 * 1024)
26
27
28enum class UnixFifoType {
29	Stream,
30	Datagram
31};
32
33
34struct ring_buffer;
35
36class UnixRequest : public DoublyLinkedListLinkImpl<UnixRequest> {
37public:
38	UnixRequest(const iovec* vecs, size_t count,
39			ancillary_data_container* ancillaryData,
40			struct sockaddr_storage* address);
41
42	off_t TotalSize() const			{ return fTotalSize; }
43	off_t BytesTransferred() const	{ return fBytesTransferred; }
44	off_t BytesRemaining() const	{ return fTotalSize - fBytesTransferred; }
45
46	void AddBytesTransferred(size_t size);
47	bool GetCurrentChunk(void*& data, size_t& size);
48
49	ancillary_data_container* AncillaryData() const	 { return fAncillaryData; }
50	void SetAncillaryData(ancillary_data_container* data);
51	void AddAncillaryData(ancillary_data_container* data);
52
53	struct sockaddr_storage* Address() const	{ return fAddress; }
54
55private:
56	const iovec*					fVecs;
57	size_t							fVecCount;
58	ancillary_data_container*		fAncillaryData;
59	off_t							fTotalSize;
60	off_t							fBytesTransferred;
61	size_t							fVecIndex;
62	size_t							fVecOffset;
63	struct sockaddr_storage*		fAddress;
64};
65
66
67class UnixBufferQueue {
68public:
69	UnixBufferQueue(size_t capacity, UnixFifoType type);
70	~UnixBufferQueue();
71
72	status_t Init();
73
74	size_t	Readable() const;
75	size_t	Writable() const;
76
77	status_t Read(UnixRequest& request);
78	status_t Write(UnixRequest& request);
79
80	size_t Capacity() const				{ return fCapacity; }
81	status_t SetCapacity(size_t capacity);
82
83private:
84	struct AncillaryDataEntry : DoublyLinkedListLinkImpl<AncillaryDataEntry> {
85		ancillary_data_container*	data;
86		size_t						offset;
87	};
88
89	typedef DoublyLinkedList<AncillaryDataEntry> AncillaryDataList;
90
91	struct DatagramEntry : DoublyLinkedListLinkImpl<DatagramEntry> {
92		struct sockaddr_storage	address;
93		size_t	size;
94	};
95
96	typedef DoublyLinkedList<DatagramEntry> DatagramList;
97
98	ring_buffer*		fBuffer;
99	size_t				fCapacity;
100	AncillaryDataList	fAncillaryData;
101	DatagramList		fDatagrams;
102	UnixFifoType		fType;
103};
104
105
106class UnixFifo : public BReferenceable {
107public:
108	UnixFifo(size_t capacity, UnixFifoType type);
109	~UnixFifo();
110
111	status_t Init();
112
113	bool Lock()
114	{
115		return mutex_lock(&fLock) == B_OK;
116	}
117
118	void Unlock()
119	{
120		mutex_unlock(&fLock);
121	}
122
123	void Shutdown(uint32 shutdown);
124
125	bool IsReadShutdown() const
126	{
127		return (fShutdown & UNIX_FIFO_SHUTDOWN_READ);
128	}
129
130	bool IsWriteShutdown() const
131	{
132		return (fShutdown & UNIX_FIFO_SHUTDOWN_WRITE);
133	}
134
135	ssize_t Read(const iovec* vecs, size_t vecCount,
136		ancillary_data_container** _ancillaryData,
137		struct sockaddr_storage* address, bigtime_t timeout);
138	ssize_t Write(const iovec* vecs, size_t vecCount,
139		ancillary_data_container* ancillaryData,
140		const struct sockaddr_storage* address, bigtime_t timeout);
141
142	size_t Readable() const;
143	size_t Writable() const;
144
145	status_t SetBufferCapacity(size_t capacity);
146
147private:
148	typedef DoublyLinkedList<UnixRequest> RequestList;
149
150private:
151	status_t _Read(UnixRequest& request, bigtime_t timeout);
152	status_t _Write(UnixRequest& request, bigtime_t timeout);
153	status_t _WriteNonBlocking(UnixRequest& request);
154	size_t _MinimumWritableSize(const UnixRequest& request) const;
155
156private:
157	mutex				fLock;
158	UnixBufferQueue		fBuffer;
159	RequestList			fReaders;
160	RequestList			fWriters;
161	off_t				fReadRequested;
162	off_t				fWriteRequested;
163	ConditionVariable	fReadCondition;
164	ConditionVariable	fWriteCondition;
165	uint32				fShutdown;
166	UnixFifoType		fType;
167};
168
169
170typedef AutoLocker<UnixFifo> UnixFifoLocker;
171
172
173#endif	// UNIX_FIFO_H
174