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