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 24class MutexLocking { 25public: 26 typedef mutex Type; 27 typedef MutexLocker AutoLocker; 28 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; } 34}; 35 36 37extern net_buffer_module_info* gBufferModule; 38extern net_stack_module_info* gStackModule; 39 40 41class NetModuleBundleGetter { 42public: 43 static net_stack_module_info* Stack() { return gStackModule; } 44 static net_buffer_module_info* Buffer() { return gBufferModule; } 45}; 46 47 48class ProtocolSocket { 49public: 50 ProtocolSocket(net_socket* socket); 51 52 status_t Open(); 53 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); } 62 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); } 71 72 net_domain* Domain() const { return fDomain; } 73 net_address_module_info* AddressModule() const 74 { return fDomain->address_module; } 75 76 net_socket* Socket() const { return fSocket; } 77 78protected: 79 net_socket* fSocket; 80 net_domain* fDomain; 81}; 82 83 84inline 85ProtocolSocket::ProtocolSocket(net_socket* socket) 86 : 87 fSocket(socket), 88 fDomain(NULL) 89{ 90} 91 92 93inline status_t 94ProtocolSocket::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 106template<typename LockingBase = MutexLocking, 107 typename ModuleBundle = NetModuleBundleGetter> 108class DatagramSocket : public ProtocolSocket { 109public: 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 126 bool IsEmpty() const { return fBuffers.IsEmpty(); } 127 ssize_t AvailableData() const; 128 129 void WakeAll(); 130 void NotifyOne(); 131 132protected: 133 virtual status_t SocketStatus(bool peek) const; 134 135private: 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 145protected: 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 163DECL_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 176DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket() 177{ 178 _Clear(); 179 delete_sem(fNotify); 180 LockingBase::Destroy(&fLock); 181} 182 183 184DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const 185{ 186 return fNotify >= 0 ? B_OK : fNotify; 187} 188 189 190DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer* buffer) 191{ 192 AutoLocker _(fLock); 193 return _Enqueue(buffer); 194} 195 196 197DECL_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 213DECL_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 224DECL_DATAGRAM_SOCKET(inline net_buffer*)::Dequeue(bool peek) 225{ 226 AutoLocker _(fLock); 227 return _Dequeue(peek); 228} 229 230 231DECL_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 266DECL_DATAGRAM_SOCKET(inline void)::Clear() 267{ 268 AutoLocker _(fLock); 269 _Clear(); 270} 271 272 273DECL_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 284DECL_DATAGRAM_SOCKET(inline void)::WakeAll() 285{ 286 release_sem_etc(fNotify, 0, B_RELEASE_ALL); 287} 288 289 290DECL_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 297DECL_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 309DECL_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 324DECL_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 339DECL_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 348DECL_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 359DECL_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 371DECL_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