1 /*
2 * Copyright 2007-2013, 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 MutexLocking {
25 public:
26 typedef mutex Type;
27 typedef MutexLocker AutoLocker;
28
Init(mutex * lock,const char * name)29 static status_t Init(mutex* lock, const char* name)
30 { mutex_init_etc(lock, name, MUTEX_FLAG_CLONE_NAME); return B_OK; }
Destroy(mutex * lock)31 static void Destroy(mutex* lock) { mutex_destroy(lock); }
Lock(mutex * lock)32 static status_t Lock(mutex* lock) { return mutex_lock(lock); }
Unlock(mutex * lock)33 static status_t Unlock(mutex* lock) { mutex_unlock(lock); return B_OK; }
34 };
35
36
37 extern net_buffer_module_info* gBufferModule;
38 extern net_stack_module_info* gStackModule;
39
40
41 class NetModuleBundleGetter {
42 public:
Stack()43 static net_stack_module_info* Stack() { return gStackModule; }
Buffer()44 static net_buffer_module_info* Buffer() { return gBufferModule; }
45 };
46
47
48 class ProtocolSocket {
49 public:
50 ProtocolSocket(net_socket* socket);
51
52 status_t Open();
53
LocalAddress()54 SocketAddress LocalAddress()
55 { return SocketAddress(
56 fDomain->address_module,
57 &fSocket->address); }
LocalAddress()58 ConstSocketAddress LocalAddress() const
59 { return ConstSocketAddress(
60 fDomain->address_module,
61 &fSocket->address); }
62
PeerAddress()63 SocketAddress PeerAddress()
64 { return SocketAddress(
65 fDomain->address_module,
66 &fSocket->peer); }
PeerAddress()67 ConstSocketAddress PeerAddress() const
68 { return ConstSocketAddress(
69 fDomain->address_module,
70 &fSocket->peer); }
71
Domain()72 net_domain* Domain() const { return fDomain; }
AddressModule()73 net_address_module_info* AddressModule() const
74 { return fDomain->address_module; }
75
Socket()76 net_socket* Socket() const { return fSocket; }
77
78 protected:
79 net_socket* fSocket;
80 net_domain* fDomain;
81 };
82
83
84 inline
ProtocolSocket(net_socket * socket)85 ProtocolSocket::ProtocolSocket(net_socket* socket)
86 :
87 fSocket(socket),
88 fDomain(NULL)
89 {
90 }
91
92
93 inline status_t
Open()94 ProtocolSocket::Open()
95 {
96 fDomain = fSocket->first_protocol->module->get_domain(
97 fSocket->first_protocol);
98
99 if (fDomain == NULL || fDomain->address_module == NULL)
100 return EAFNOSUPPORT;
101
102 return B_OK;
103 }
104
105
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();
113
114 status_t InitCheck() const;
115
116 status_t Enqueue(net_buffer* buffer);
117 status_t EnqueueClone(net_buffer* buffer);
118
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);
123
124 void Clear();
125
IsEmpty()126 bool IsEmpty() const { return fBuffers.IsEmpty(); }
127 ssize_t AvailableData() const;
128
129 void WakeAll();
130 void NotifyOne();
131
132 protected:
133 virtual status_t SocketStatus(bool peek) const;
134
135 private:
136 status_t _Enqueue(net_buffer* buffer);
137 net_buffer* _Dequeue(bool peek);
138 void _Clear();
139
140 status_t _Wait(bigtime_t timeout);
141 void _NotifyOneReader(bool notifySocket);
142
143 bigtime_t _SocketTimeout(uint32 flags) const;
144
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;
150
151 sem_id fNotify;
152 BufferList fBuffers;
153 size_t fCurrentBytes;
154 mutable LockType fLock;
155 };
156
157
158 #define DECL_DATAGRAM_SOCKET(args) \
159 template<typename LockingBase, typename ModuleBundle> args \
160 DatagramSocket<LockingBase, ModuleBundle>
161
162
DECL_DATAGRAM_SOCKET(inline)163 DECL_DATAGRAM_SOCKET(inline)::DatagramSocket(const char* name,
164 net_socket* socket)
165 :
166 ProtocolSocket(socket), fCurrentBytes(0)
167 {
168 status_t status = LockingBase::Init(&fLock, name);
169 if (status != B_OK)
170 fNotify = status;
171 else
172 fNotify = create_sem(0, name);
173 }
174
175
DECL_DATAGRAM_SOCKET(inline)176 DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket()
177 {
178 _Clear();
179 delete_sem(fNotify);
180 LockingBase::Destroy(&fLock);
181 }
182
183
DECL_DATAGRAM_SOCKET(inline status_t)184 DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const
185 {
186 return fNotify >= 0 ? B_OK : fNotify;
187 }
188
189
DECL_DATAGRAM_SOCKET(inline status_t)190 DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer* buffer)
191 {
192 AutoLocker _(fLock);
193 return _Enqueue(buffer);
194 }
195
196
DECL_DATAGRAM_SOCKET(inline status_t)197 DECL_DATAGRAM_SOCKET(inline status_t)::EnqueueClone(net_buffer* _buffer)
198 {
199 AutoLocker _(fLock);
200
201 net_buffer* buffer = ModuleBundle::Buffer()->clone(_buffer, false);
202 if (buffer == NULL)
203 return B_NO_MEMORY;
204
205 status_t status = _Enqueue(buffer);
206 if (status != B_OK)
207 ModuleBundle::Buffer()->free(buffer);
208
209 return status;
210 }
211
212
DECL_DATAGRAM_SOCKET(inline status_t)213 DECL_DATAGRAM_SOCKET(inline status_t)::Dequeue(uint32 flags,
214 net_buffer** _buffer)
215 {
216 if ((flags & ~(MSG_DONTWAIT | MSG_PEEK)) != 0)
217 return EOPNOTSUPP;
218
219 return BlockingDequeue((flags & MSG_PEEK) != 0, _SocketTimeout(flags),
220 _buffer);
221 }
222
223
DECL_DATAGRAM_SOCKET(inline net_buffer *)224 DECL_DATAGRAM_SOCKET(inline net_buffer*)::Dequeue(bool peek)
225 {
226 AutoLocker _(fLock);
227 return _Dequeue(peek);
228 }
229
230
DECL_DATAGRAM_SOCKET(inline status_t)231 DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool peek,
232 bigtime_t timeout, net_buffer** _buffer)
233 {
234 AutoLocker _(fLock);
235
236 bool waited = false;
237 while (fBuffers.IsEmpty()) {
238 status_t status = SocketStatus(peek);
239 if (status != B_OK) {
240 if (peek)
241 _NotifyOneReader(false);
242 return status;
243 }
244
245 status = _Wait(timeout);
246 if (status != B_OK)
247 return status;
248
249 waited = true;
250 }
251
252 *_buffer = _Dequeue(peek);
253 if (peek && waited) {
254 // There is a new buffer in the list; but since we are only peeking,
255 // notify the next waiting reader.
256 _NotifyOneReader(false);
257 }
258
259 if (*_buffer == NULL)
260 return B_NO_MEMORY;
261
262 return B_OK;
263 }
264
265
DECL_DATAGRAM_SOCKET(inline void)266 DECL_DATAGRAM_SOCKET(inline void)::Clear()
267 {
268 AutoLocker _(fLock);
269 _Clear();
270 }
271
272
DECL_DATAGRAM_SOCKET(inline ssize_t)273 DECL_DATAGRAM_SOCKET(inline ssize_t)::AvailableData() const
274 {
275 AutoLocker _(fLock);
276 status_t status = SocketStatus(true);
277 if (status < B_OK)
278 return status;
279
280 return fCurrentBytes;
281 }
282
283
DECL_DATAGRAM_SOCKET(inline void)284 DECL_DATAGRAM_SOCKET(inline void)::WakeAll()
285 {
286 release_sem_etc(fNotify, 0, B_RELEASE_ALL);
287 }
288
289
DECL_DATAGRAM_SOCKET(inline void)290 DECL_DATAGRAM_SOCKET(inline void)::NotifyOne()
291 {
292 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
293 | B_DO_NOT_RESCHEDULE);
294 }
295
296
DECL_DATAGRAM_SOCKET(inline status_t)297 DECL_DATAGRAM_SOCKET(inline status_t)::SocketStatus(bool peek) const
298 {
299 if (peek)
300 return fSocket->error;
301
302 status_t status = fSocket->error;
303 fSocket->error = B_OK;
304
305 return status;
306 }
307
308
DECL_DATAGRAM_SOCKET(inline status_t)309 DECL_DATAGRAM_SOCKET(inline status_t)::_Enqueue(net_buffer* buffer)
310 {
311 if (fSocket->receive.buffer_size > 0
312 && (fCurrentBytes + buffer->size) > fSocket->receive.buffer_size)
313 return ENOBUFS;
314
315 fBuffers.Add(buffer);
316 fCurrentBytes += buffer->size;
317
318 _NotifyOneReader(true);
319
320 return B_OK;
321 }
322
323
DECL_DATAGRAM_SOCKET(inline net_buffer *)324 DECL_DATAGRAM_SOCKET(inline net_buffer*)::_Dequeue(bool peek)
325 {
326 if (fBuffers.IsEmpty())
327 return NULL;
328
329 if (peek)
330 return ModuleBundle::Buffer()->clone(fBuffers.Head(), false);
331
332 net_buffer* buffer = fBuffers.RemoveHead();
333 fCurrentBytes -= buffer->size;
334
335 return buffer;
336 }
337
338
DECL_DATAGRAM_SOCKET(inline void)339 DECL_DATAGRAM_SOCKET(inline void)::_Clear()
340 {
341 BufferList::Iterator it = fBuffers.GetIterator();
342 while (it.HasNext())
343 ModuleBundle::Buffer()->free(it.Next());
344 fCurrentBytes = 0;
345 }
346
347
DECL_DATAGRAM_SOCKET(inline status_t)348 DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout)
349 {
350 LockingBase::Unlock(&fLock);
351 status_t status = acquire_sem_etc(fNotify, 1, B_CAN_INTERRUPT
352 | (timeout != 0 ? B_ABSOLUTE_TIMEOUT : B_RELATIVE_TIMEOUT), timeout);
353 LockingBase::Lock(&fLock);
354
355 return status;
356 }
357
358
DECL_DATAGRAM_SOCKET(inline void)359 DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket)
360 {
361 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY
362 | B_DO_NOT_RESCHEDULE);
363
364 if (notifySocket) {
365 ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ,
366 fCurrentBytes);
367 }
368 }
369
370
DECL_DATAGRAM_SOCKET(inline bigtime_t)371 DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const
372 {
373 if ((flags & MSG_DONTWAIT) != 0)
374 return 0;
375 if (ModuleBundle::Stack()->is_restarted_syscall())
376 return ModuleBundle::Stack()->restore_syscall_restart_timeout();
377
378 bigtime_t timeout = fSocket->receive.timeout;
379 if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
380 timeout += system_time();
381
382 ModuleBundle::Stack()->store_syscall_restart_timeout(timeout);
383 return timeout;
384 }
385
386
387 #endif // PROTOCOL_UTILITIES_H
388