xref: /haiku/headers/private/net/ProtocolUtilities.h (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /*
2  * Copyright 2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Hugo Santos, hugosantos@gmail.com
7  */
8 #ifndef PROTOCOL_UTILITIES_H
9 #define PROTOCOL_UTILITIES_H
10 
11 
12 #include <lock.h>
13 #include <Select.h>
14 #include <util/AutoLock.h>
15 #include <util/DoublyLinkedList.h>
16 
17 #include <AddressUtilities.h>
18 #include <net_buffer.h>
19 #include <net_protocol.h>
20 #include <net_socket.h>
21 #include <net_stack.h>
22 
23 
24 class BenaphoreLocking {
25 public:
26 	typedef benaphore Type;
27 	typedef BenaphoreLocker AutoLocker;
28 
29 	static status_t Init(benaphore *lock, const char *name)
30 		{ return benaphore_init(lock, name); }
31 	static void Destroy(benaphore *lock) { benaphore_destroy(lock); }
32 	static status_t Lock(benaphore *lock) { return benaphore_lock(lock); }
33 	static status_t Unlock(benaphore *lock) { return benaphore_unlock(lock); }
34 };
35 
36 
37 extern net_buffer_module_info *gBufferModule;
38 extern net_stack_module_info *gStackModule;
39 
40 class NetModuleBundleGetter {
41 public:
42 	static net_stack_module_info *Stack() { return gStackModule; }
43 	static net_buffer_module_info *Buffer() { return gBufferModule; }
44 };
45 
46 
47 class ProtocolSocket {
48 public:
49 	ProtocolSocket(net_socket *socket);
50 
51 	status_t Open();
52 
53 	SocketAddress LocalAddress()
54 		{ return SocketAddress(fDomain->address_module, &fSocket->address); }
55 	ConstSocketAddress LocalAddress() const
56 		{ return ConstSocketAddress(fDomain->address_module, &fSocket->address); }
57 
58 	SocketAddress PeerAddress()
59 		{ return SocketAddress(fDomain->address_module, &fSocket->peer); }
60 	ConstSocketAddress PeerAddress() const
61 		{ return ConstSocketAddress(fDomain->address_module, &fSocket->peer); }
62 
63 	net_domain *Domain() const { return fDomain; }
64 	net_address_module_info *AddressModule() const
65 		{ return fDomain->address_module; }
66 
67 protected:
68 	net_socket *fSocket;
69 	net_domain *fDomain;
70 };
71 
72 
73 inline ProtocolSocket::ProtocolSocket(net_socket *socket)
74 	: fSocket(socket), fDomain(NULL) {}
75 
76 
77 inline status_t
78 ProtocolSocket::Open()
79 {
80 	fDomain = fSocket->first_protocol->module->get_domain(
81 		fSocket->first_protocol);
82 
83 	if (fDomain == NULL || fDomain->address_module == NULL)
84 		return EAFNOSUPPORT;
85 
86 	return B_OK;
87 }
88 
89 
90 template<typename LockingBase = BenaphoreLocking,
91 	typename ModuleBundle = NetModuleBundleGetter>
92 class DatagramSocket : public ProtocolSocket {
93 public:
94 	DatagramSocket(const char *name, net_socket *socket);
95 	virtual ~DatagramSocket();
96 
97 	status_t InitCheck() const;
98 
99 	status_t Enqueue(net_buffer *buffer);
100 	net_buffer *Dequeue(bool clone);
101 	status_t BlockingDequeue(bool clone, bigtime_t timeout,
102 		net_buffer **_buffer);
103 	void Clear();
104 
105 	status_t SocketEnqueue(net_buffer *buffer);
106 	status_t SocketDequeue(uint32 flags, net_buffer **_buffer);
107 
108 	ssize_t AvailableData() const;
109 
110 	void WakeAll();
111 
112 	net_socket *Socket() const { return fSocket; }
113 
114 protected:
115 	virtual status_t _SocketStatus() const;
116 
117 	status_t _Enqueue(net_buffer *buffer);
118 	status_t _SocketEnqueue(net_buffer *buffer);
119 	net_buffer *_Dequeue(bool clone);
120 	void _Clear();
121 
122 	status_t _Wait(bigtime_t timeout);
123 	void _NotifyOneReader(bool notifySocket);
124 
125 	bool _IsEmpty() const { return fBuffers.IsEmpty(); }
126 	bigtime_t _SocketTimeout(uint32 flags) const;
127 
128 	typedef typename LockingBase::Type LockType;
129 	typedef typename LockingBase::AutoLocker AutoLocker;
130 	typedef DoublyLinkedListCLink<net_buffer> NetBufferLink;
131 	typedef DoublyLinkedList<net_buffer, NetBufferLink> BufferList;
132 
133 	sem_id fNotify;
134 	BufferList fBuffers;
135 	size_t fCurrentBytes;
136 	mutable LockType fLock;
137 };
138 
139 
140 #define DECL_DATAGRAM_SOCKET(args) \
141 	template<typename LockingBase, typename ModuleBundle> args \
142 	DatagramSocket<LockingBase, ModuleBundle>
143 
144 
145 DECL_DATAGRAM_SOCKET(inline)::DatagramSocket(const char *name,
146 	net_socket *socket)
147 	: ProtocolSocket(socket), fCurrentBytes(0)
148 {
149 	status_t status = LockingBase::Init(&fLock, name);
150 	if (status < B_OK)
151 		fNotify = status;
152 	else
153 		fNotify = create_sem(0, name);
154 }
155 
156 
157 DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket()
158 {
159 	_Clear();
160 	delete_sem(fNotify);
161 	LockingBase::Destroy(&fLock);
162 }
163 
164 
165 DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const
166 {
167 	return fNotify;
168 }
169 
170 
171 DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer *buffer)
172 {
173 	AutoLocker _(fLock);
174 	return _Enqueue(buffer);
175 }
176 
177 
178 DECL_DATAGRAM_SOCKET(inline status_t)::_Enqueue(net_buffer *buffer)
179 {
180 	if (fSocket->receive.buffer_size > 0
181 		&& (fCurrentBytes + buffer->size) > fSocket->receive.buffer_size)
182 		return ENOBUFS;
183 
184 	fBuffers.Add(buffer);
185 	fCurrentBytes += buffer->size;
186 
187 	_NotifyOneReader(true);
188 
189 	return B_OK;
190 }
191 
192 
193 DECL_DATAGRAM_SOCKET(inline status_t)::SocketEnqueue(net_buffer *_buffer)
194 {
195 	AutoLocker _(fLock);
196 	return _SocketEnqueue(_buffer);
197 }
198 
199 
200 DECL_DATAGRAM_SOCKET(inline status_t)::_SocketEnqueue(net_buffer *_buffer)
201 {
202 	if (_buffer->flags & MSG_BCAST) {
203 		// only deliver datagrams sent to a broadcast address
204 		// to sockets with SO_BROADCAST on.
205 		if (!(fSocket->options & SO_BROADCAST))
206 			return B_OK;
207 	}
208 
209 	net_buffer *buffer = ModuleBundle::Buffer()->clone(_buffer, false);
210 	if (buffer == NULL)
211 		return B_NO_MEMORY;
212 
213 	status_t status = _Enqueue(buffer);
214 	if (status < B_OK)
215 		ModuleBundle::Buffer()->free(buffer);
216 
217 	return status;
218 }
219 
220 
221 DECL_DATAGRAM_SOCKET(inline net_buffer *)::Dequeue(bool clone)
222 {
223 	AutoLocker _(fLock);
224 	return _Dequeue(clone);
225 }
226 
227 
228 DECL_DATAGRAM_SOCKET(inline net_buffer *)::_Dequeue(bool clone)
229 {
230 	if (fBuffers.IsEmpty())
231 		return NULL;
232 
233 	if (clone)
234 		return ModuleBundle::Buffer()->clone(fBuffers.Head(), false);
235 
236 	net_buffer *buffer = fBuffers.RemoveHead();
237 	fCurrentBytes -= buffer->size;
238 
239 	return buffer;
240 }
241 
242 
243 DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool clone,
244 	bigtime_t timeout, net_buffer **_buffer)
245 {
246 	AutoLocker _(fLock);
247 
248 	bool waited = false;
249 	while (fBuffers.IsEmpty()) {
250 		status_t status = _SocketStatus();
251 		if (status < B_OK)
252 			return status;
253 
254 		if ((status = _Wait(timeout)) < B_OK)
255 			return status;
256 		waited = true;
257 	}
258 
259 	*_buffer = _Dequeue(clone);
260 	if (clone && waited) {
261 		// we were signalled there was a new buffer in the
262 		// list; but since we are cloning, notify the next
263 		// waiting reader.
264 		_NotifyOneReader(false);
265 	}
266 
267 	if (*_buffer == NULL)
268 		return B_NO_MEMORY;
269 
270 	return B_OK;
271 }
272 
273 
274 DECL_DATAGRAM_SOCKET(inline status_t)::SocketDequeue(uint32 flags,
275 	net_buffer **_buffer)
276 {
277 	return BlockingDequeue(flags & MSG_PEEK, _SocketTimeout(flags), _buffer);
278 }
279 
280 
281 DECL_DATAGRAM_SOCKET(inline void)::Clear()
282 {
283 	AutoLocker _(fLock);
284 	_Clear();
285 }
286 
287 
288 DECL_DATAGRAM_SOCKET(inline void)::_Clear()
289 {
290 	BufferList::Iterator it = fBuffers.GetIterator();
291 	while (it.HasNext())
292 		ModuleBundle::Buffer()->free(it.Next());
293 	fCurrentBytes = 0;
294 }
295 
296 
297 DECL_DATAGRAM_SOCKET(inline ssize_t)::AvailableData() const
298 {
299 	AutoLocker _(fLock);
300 	status_t status = _SocketStatus();
301 	if (status < B_OK)
302 		return status;
303 
304 	return fCurrentBytes;
305 }
306 
307 
308 DECL_DATAGRAM_SOCKET(inline status_t)::_SocketStatus() const
309 {
310 	return B_OK;
311 }
312 
313 
314 DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout)
315 {
316 	LockingBase::Unlock(&fLock);
317 	status_t status = acquire_sem_etc(fNotify, 1, B_CAN_INTERRUPT
318 		| B_ABSOLUTE_TIMEOUT, timeout);
319 	LockingBase::Lock(&fLock);
320 
321 	return status;
322 }
323 
324 
325 DECL_DATAGRAM_SOCKET(inline void)::WakeAll()
326 {
327 	release_sem_etc(fNotify, 0, B_RELEASE_ALL);
328 }
329 
330 
331 DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket)
332 {
333 	release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
334 		| B_DO_NOT_RESCHEDULE);
335 
336 	if (notifySocket)
337 		ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ,
338 			fCurrentBytes);
339 }
340 
341 
342 DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const
343 {
344 	bigtime_t timeout = fSocket->receive.timeout;
345 
346 	if (flags & MSG_DONTWAIT)
347 		timeout = 0;
348 	else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
349 		timeout += system_time();
350 
351 	return timeout;
352 }
353 
354 #endif
355