btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / private / net / ProtocolUtilities.h
blob0423d0565f27d83a619f06b494d818863ff760e4
1 /*
2 * Copyright 2007-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Hugo Santos, hugosantos@gmail.com
7 */
8 #ifndef PROTOCOL_UTILITIES_H
9 #define PROTOCOL_UTILITIES_H
12 #include <lock.h>
13 #include <Select.h>
14 #include <util/AutoLock.h>
15 #include <util/DoublyLinkedList.h>
17 #include <AddressUtilities.h>
18 #include <net_buffer.h>
19 #include <net_protocol.h>
20 #include <net_socket.h>
21 #include <net_stack.h>
24 class MutexLocking {
25 public:
26 typedef mutex Type;
27 typedef MutexLocker AutoLocker;
29 static status_t Init(mutex* lock, const char* name)
30 { mutex_init_etc(lock, name, MUTEX_FLAG_CLONE_NAME); return B_OK; }
31 static void Destroy(mutex* lock) { mutex_destroy(lock); }
32 static status_t Lock(mutex* lock) { return mutex_lock(lock); }
33 static status_t Unlock(mutex* lock) { mutex_unlock(lock); return B_OK; }
37 extern net_buffer_module_info* gBufferModule;
38 extern net_stack_module_info* gStackModule;
41 class NetModuleBundleGetter {
42 public:
43 static net_stack_module_info* Stack() { return gStackModule; }
44 static net_buffer_module_info* Buffer() { return gBufferModule; }
48 class ProtocolSocket {
49 public:
50 ProtocolSocket(net_socket* socket);
52 status_t Open();
54 SocketAddress LocalAddress()
55 { return SocketAddress(
56 fDomain->address_module,
57 &fSocket->address); }
58 ConstSocketAddress LocalAddress() const
59 { return ConstSocketAddress(
60 fDomain->address_module,
61 &fSocket->address); }
63 SocketAddress PeerAddress()
64 { return SocketAddress(
65 fDomain->address_module,
66 &fSocket->peer); }
67 ConstSocketAddress PeerAddress() const
68 { return ConstSocketAddress(
69 fDomain->address_module,
70 &fSocket->peer); }
72 net_domain* Domain() const { return fDomain; }
73 net_address_module_info* AddressModule() const
74 { return fDomain->address_module; }
76 net_socket* Socket() const { return fSocket; }
78 protected:
79 net_socket* fSocket;
80 net_domain* fDomain;
84 inline
85 ProtocolSocket::ProtocolSocket(net_socket* socket)
87 fSocket(socket),
88 fDomain(NULL)
93 inline status_t
94 ProtocolSocket::Open()
96 fDomain = fSocket->first_protocol->module->get_domain(
97 fSocket->first_protocol);
99 if (fDomain == NULL || fDomain->address_module == NULL)
100 return EAFNOSUPPORT;
102 return B_OK;
106 template<typename LockingBase = MutexLocking,
107 typename ModuleBundle = NetModuleBundleGetter>
108 class DatagramSocket : public ProtocolSocket {
109 public:
110 DatagramSocket(const char* name,
111 net_socket* socket);
112 virtual ~DatagramSocket();
114 status_t InitCheck() const;
116 status_t Enqueue(net_buffer* buffer);
117 status_t EnqueueClone(net_buffer* buffer);
119 status_t Dequeue(uint32 flags, net_buffer** _buffer);
120 net_buffer* Dequeue(bool clone);
121 status_t BlockingDequeue(bool peek, bigtime_t timeout,
122 net_buffer** _buffer);
124 void Clear();
126 bool IsEmpty() const { return fBuffers.IsEmpty(); }
127 ssize_t AvailableData() const;
129 void WakeAll();
130 void NotifyOne();
132 protected:
133 virtual status_t SocketStatus(bool peek) const;
135 private:
136 status_t _Enqueue(net_buffer* buffer);
137 net_buffer* _Dequeue(bool peek);
138 void _Clear();
140 status_t _Wait(bigtime_t timeout);
141 void _NotifyOneReader(bool notifySocket);
143 bigtime_t _SocketTimeout(uint32 flags) const;
145 protected:
146 typedef typename LockingBase::Type LockType;
147 typedef typename LockingBase::AutoLocker AutoLocker;
148 typedef DoublyLinkedListCLink<net_buffer> NetBufferLink;
149 typedef DoublyLinkedList<net_buffer, NetBufferLink> BufferList;
151 sem_id fNotify;
152 BufferList fBuffers;
153 size_t fCurrentBytes;
154 mutable LockType fLock;
158 #define DECL_DATAGRAM_SOCKET(args) \
159 template<typename LockingBase, typename ModuleBundle> args \
160 DatagramSocket<LockingBase, ModuleBundle>
163 DECL_DATAGRAM_SOCKET(inline)::DatagramSocket(const char* name,
164 net_socket* socket)
166 ProtocolSocket(socket), fCurrentBytes(0)
168 status_t status = LockingBase::Init(&fLock, name);
169 if (status != B_OK)
170 fNotify = status;
171 else
172 fNotify = create_sem(0, name);
176 DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket()
178 _Clear();
179 delete_sem(fNotify);
180 LockingBase::Destroy(&fLock);
184 DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const
186 return fNotify >= 0 ? B_OK : fNotify;
190 DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer* buffer)
192 AutoLocker _(fLock);
193 return _Enqueue(buffer);
197 DECL_DATAGRAM_SOCKET(inline status_t)::EnqueueClone(net_buffer* _buffer)
199 AutoLocker _(fLock);
201 net_buffer* buffer = ModuleBundle::Buffer()->clone(_buffer, false);
202 if (buffer == NULL)
203 return B_NO_MEMORY;
205 status_t status = _Enqueue(buffer);
206 if (status != B_OK)
207 ModuleBundle::Buffer()->free(buffer);
209 return status;
213 DECL_DATAGRAM_SOCKET(inline status_t)::Dequeue(uint32 flags,
214 net_buffer** _buffer)
216 return BlockingDequeue((flags & MSG_PEEK) != 0, _SocketTimeout(flags),
217 _buffer);
221 DECL_DATAGRAM_SOCKET(inline net_buffer*)::Dequeue(bool peek)
223 AutoLocker _(fLock);
224 return _Dequeue(peek);
228 DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool peek,
229 bigtime_t timeout, net_buffer** _buffer)
231 AutoLocker _(fLock);
233 bool waited = false;
234 while (fBuffers.IsEmpty()) {
235 status_t status = SocketStatus(peek);
236 if (status != B_OK) {
237 if (peek)
238 _NotifyOneReader(false);
239 return status;
242 status = _Wait(timeout);
243 if (status != B_OK)
244 return status;
246 waited = true;
249 *_buffer = _Dequeue(peek);
250 if (peek && waited) {
251 // There is a new buffer in the list; but since we are only peeking,
252 // notify the next waiting reader.
253 _NotifyOneReader(false);
256 if (*_buffer == NULL)
257 return B_NO_MEMORY;
259 return B_OK;
263 DECL_DATAGRAM_SOCKET(inline void)::Clear()
265 AutoLocker _(fLock);
266 _Clear();
270 DECL_DATAGRAM_SOCKET(inline ssize_t)::AvailableData() const
272 AutoLocker _(fLock);
273 status_t status = SocketStatus(true);
274 if (status < B_OK)
275 return status;
277 return fCurrentBytes;
281 DECL_DATAGRAM_SOCKET(inline void)::WakeAll()
283 release_sem_etc(fNotify, 0, B_RELEASE_ALL);
287 DECL_DATAGRAM_SOCKET(inline void)::NotifyOne()
289 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
290 | B_DO_NOT_RESCHEDULE);
294 DECL_DATAGRAM_SOCKET(inline status_t)::SocketStatus(bool peek) const
296 if (peek)
297 return fSocket->error;
299 status_t status = fSocket->error;
300 fSocket->error = B_OK;
302 return status;
306 DECL_DATAGRAM_SOCKET(inline status_t)::_Enqueue(net_buffer* buffer)
308 if (fSocket->receive.buffer_size > 0
309 && (fCurrentBytes + buffer->size) > fSocket->receive.buffer_size)
310 return ENOBUFS;
312 fBuffers.Add(buffer);
313 fCurrentBytes += buffer->size;
315 _NotifyOneReader(true);
317 return B_OK;
321 DECL_DATAGRAM_SOCKET(inline net_buffer*)::_Dequeue(bool peek)
323 if (fBuffers.IsEmpty())
324 return NULL;
326 if (peek)
327 return ModuleBundle::Buffer()->clone(fBuffers.Head(), false);
329 net_buffer* buffer = fBuffers.RemoveHead();
330 fCurrentBytes -= buffer->size;
332 return buffer;
336 DECL_DATAGRAM_SOCKET(inline void)::_Clear()
338 BufferList::Iterator it = fBuffers.GetIterator();
339 while (it.HasNext())
340 ModuleBundle::Buffer()->free(it.Next());
341 fCurrentBytes = 0;
345 DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout)
347 LockingBase::Unlock(&fLock);
348 status_t status = acquire_sem_etc(fNotify, 1, B_CAN_INTERRUPT
349 | (timeout != 0 ? B_ABSOLUTE_TIMEOUT : B_RELATIVE_TIMEOUT), timeout);
350 LockingBase::Lock(&fLock);
352 return status;
356 DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket)
358 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
359 | B_DO_NOT_RESCHEDULE);
361 if (notifySocket) {
362 ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ,
363 fCurrentBytes);
368 DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const
370 if (ModuleBundle::Stack()->is_restarted_syscall())
371 return ModuleBundle::Stack()->restore_syscall_restart_timeout();
373 bigtime_t timeout = fSocket->receive.timeout;
374 if ((flags & MSG_DONTWAIT) != 0)
375 timeout = 0;
376 else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
377 timeout += system_time();
379 ModuleBundle::Stack()->store_syscall_restart_timeout(timeout);
380 return timeout;
384 #endif // PROTOCOL_UTILITIES_H