2 * Copyright 2007-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Hugo Santos, hugosantos@gmail.com
8 #ifndef PROTOCOL_UTILITIES_H
9 #define PROTOCOL_UTILITIES_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>
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
{
43 static net_stack_module_info
* Stack() { return gStackModule
; }
44 static net_buffer_module_info
* Buffer() { return gBufferModule
; }
48 class ProtocolSocket
{
50 ProtocolSocket(net_socket
* socket
);
54 SocketAddress
LocalAddress()
55 { return SocketAddress(
56 fDomain
->address_module
,
58 ConstSocketAddress
LocalAddress() const
59 { return ConstSocketAddress(
60 fDomain
->address_module
,
63 SocketAddress
PeerAddress()
64 { return SocketAddress(
65 fDomain
->address_module
,
67 ConstSocketAddress
PeerAddress() const
68 { return ConstSocketAddress(
69 fDomain
->address_module
,
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
; }
85 ProtocolSocket::ProtocolSocket(net_socket
* socket
)
94 ProtocolSocket::Open()
96 fDomain
= fSocket
->first_protocol
->module
->get_domain(
97 fSocket
->first_protocol
);
99 if (fDomain
== NULL
|| fDomain
->address_module
== NULL
)
106 template<typename LockingBase
= MutexLocking
,
107 typename ModuleBundle
= NetModuleBundleGetter
>
108 class DatagramSocket
: public ProtocolSocket
{
110 DatagramSocket(const char* name
,
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
);
126 bool IsEmpty() const { return fBuffers
.IsEmpty(); }
127 ssize_t
AvailableData() const;
133 virtual status_t
SocketStatus(bool peek
) const;
136 status_t
_Enqueue(net_buffer
* buffer
);
137 net_buffer
* _Dequeue(bool peek
);
140 status_t
_Wait(bigtime_t timeout
);
141 void _NotifyOneReader(bool notifySocket
);
143 bigtime_t
_SocketTimeout(uint32 flags
) const;
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
;
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
,
166 ProtocolSocket(socket
), fCurrentBytes(0)
168 status_t status
= LockingBase::Init(&fLock
, name
);
172 fNotify
= create_sem(0, name
);
176 DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket()
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
)
193 return _Enqueue(buffer
);
197 DECL_DATAGRAM_SOCKET(inline status_t
)::EnqueueClone(net_buffer
* _buffer
)
201 net_buffer
* buffer
= ModuleBundle::Buffer()->clone(_buffer
, false);
205 status_t status
= _Enqueue(buffer
);
207 ModuleBundle::Buffer()->free(buffer
);
213 DECL_DATAGRAM_SOCKET(inline status_t
)::Dequeue(uint32 flags
,
214 net_buffer
** _buffer
)
216 return BlockingDequeue((flags
& MSG_PEEK
) != 0, _SocketTimeout(flags
),
221 DECL_DATAGRAM_SOCKET(inline net_buffer
*)::Dequeue(bool peek
)
224 return _Dequeue(peek
);
228 DECL_DATAGRAM_SOCKET(inline status_t
)::BlockingDequeue(bool peek
,
229 bigtime_t timeout
, net_buffer
** _buffer
)
234 while (fBuffers
.IsEmpty()) {
235 status_t status
= SocketStatus(peek
);
236 if (status
!= B_OK
) {
238 _NotifyOneReader(false);
242 status
= _Wait(timeout
);
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
)
263 DECL_DATAGRAM_SOCKET(inline void)::Clear()
270 DECL_DATAGRAM_SOCKET(inline ssize_t
)::AvailableData() const
273 status_t status
= SocketStatus(true);
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
297 return fSocket
->error
;
299 status_t status
= fSocket
->error
;
300 fSocket
->error
= B_OK
;
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
)
312 fBuffers
.Add(buffer
);
313 fCurrentBytes
+= buffer
->size
;
315 _NotifyOneReader(true);
321 DECL_DATAGRAM_SOCKET(inline net_buffer
*)::_Dequeue(bool peek
)
323 if (fBuffers
.IsEmpty())
327 return ModuleBundle::Buffer()->clone(fBuffers
.Head(), false);
329 net_buffer
* buffer
= fBuffers
.RemoveHead();
330 fCurrentBytes
-= buffer
->size
;
336 DECL_DATAGRAM_SOCKET(inline void)::_Clear()
338 BufferList::Iterator it
= fBuffers
.GetIterator();
340 ModuleBundle::Buffer()->free(it
.Next());
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
);
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
);
362 ModuleBundle::Stack()->notify_socket(fSocket
, B_SELECT_READ
,
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)
376 else if (timeout
!= 0 && timeout
!= B_INFINITE_TIMEOUT
)
377 timeout
+= system_time();
379 ModuleBundle::Stack()->store_syscall_restart_timeout(timeout
);
384 #endif // PROTOCOL_UTILITIES_H