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 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 37 extern net_buffer_module_info* gBufferModule; 38 extern net_stack_module_info* gStackModule; 39 40 41 class NetModuleBundleGetter { 42 public: 43 static net_stack_module_info* Stack() { return gStackModule; } 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 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 78 protected: 79 net_socket* fSocket; 80 net_domain* fDomain; 81 }; 82 83 84 inline 85 ProtocolSocket::ProtocolSocket(net_socket* socket) 86 : 87 fSocket(socket), 88 fDomain(NULL) 89 { 90 } 91 92 93 inline status_t 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 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 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 176 DECL_DATAGRAM_SOCKET(inline)::~DatagramSocket() 177 { 178 _Clear(); 179 delete_sem(fNotify); 180 LockingBase::Destroy(&fLock); 181 } 182 183 184 DECL_DATAGRAM_SOCKET(inline status_t)::InitCheck() const 185 { 186 return fNotify >= 0 ? B_OK : fNotify; 187 } 188 189 190 DECL_DATAGRAM_SOCKET(inline status_t)::Enqueue(net_buffer* buffer) 191 { 192 AutoLocker _(fLock); 193 return _Enqueue(buffer); 194 } 195 196 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 213 DECL_DATAGRAM_SOCKET(inline status_t)::Dequeue(uint32 flags, 214 net_buffer** _buffer) 215 { 216 return BlockingDequeue((flags & MSG_PEEK) != 0, _SocketTimeout(flags), 217 _buffer); 218 } 219 220 221 DECL_DATAGRAM_SOCKET(inline net_buffer*)::Dequeue(bool peek) 222 { 223 AutoLocker _(fLock); 224 return _Dequeue(peek); 225 } 226 227 228 DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool peek, 229 bigtime_t timeout, net_buffer** _buffer) 230 { 231 AutoLocker _(fLock); 232 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; 240 } 241 242 status = _Wait(timeout); 243 if (status != B_OK) 244 return status; 245 246 waited = true; 247 } 248 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); 254 } 255 256 if (*_buffer == NULL) 257 return B_NO_MEMORY; 258 259 return B_OK; 260 } 261 262 263 DECL_DATAGRAM_SOCKET(inline void)::Clear() 264 { 265 AutoLocker _(fLock); 266 _Clear(); 267 } 268 269 270 DECL_DATAGRAM_SOCKET(inline ssize_t)::AvailableData() const 271 { 272 AutoLocker _(fLock); 273 status_t status = SocketStatus(true); 274 if (status < B_OK) 275 return status; 276 277 return fCurrentBytes; 278 } 279 280 281 DECL_DATAGRAM_SOCKET(inline void)::WakeAll() 282 { 283 release_sem_etc(fNotify, 0, B_RELEASE_ALL); 284 } 285 286 287 DECL_DATAGRAM_SOCKET(inline void)::NotifyOne() 288 { 289 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY 290 | B_DO_NOT_RESCHEDULE); 291 } 292 293 294 DECL_DATAGRAM_SOCKET(inline status_t)::SocketStatus(bool peek) const 295 { 296 if (peek) 297 return fSocket->error; 298 299 status_t status = fSocket->error; 300 fSocket->error = B_OK; 301 302 return status; 303 } 304 305 306 DECL_DATAGRAM_SOCKET(inline status_t)::_Enqueue(net_buffer* buffer) 307 { 308 if (fSocket->receive.buffer_size > 0 309 && (fCurrentBytes + buffer->size) > fSocket->receive.buffer_size) 310 return ENOBUFS; 311 312 fBuffers.Add(buffer); 313 fCurrentBytes += buffer->size; 314 315 _NotifyOneReader(true); 316 317 return B_OK; 318 } 319 320 321 DECL_DATAGRAM_SOCKET(inline net_buffer*)::_Dequeue(bool peek) 322 { 323 if (fBuffers.IsEmpty()) 324 return NULL; 325 326 if (peek) 327 return ModuleBundle::Buffer()->clone(fBuffers.Head(), false); 328 329 net_buffer* buffer = fBuffers.RemoveHead(); 330 fCurrentBytes -= buffer->size; 331 332 return buffer; 333 } 334 335 336 DECL_DATAGRAM_SOCKET(inline void)::_Clear() 337 { 338 BufferList::Iterator it = fBuffers.GetIterator(); 339 while (it.HasNext()) 340 ModuleBundle::Buffer()->free(it.Next()); 341 fCurrentBytes = 0; 342 } 343 344 345 DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout) 346 { 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); 351 352 return status; 353 } 354 355 356 DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket) 357 { 358 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY 359 | B_DO_NOT_RESCHEDULE); 360 361 if (notifySocket) { 362 ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ, 363 fCurrentBytes); 364 } 365 } 366 367 368 DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const 369 { 370 if (ModuleBundle::Stack()->is_restarted_syscall()) 371 return ModuleBundle::Stack()->restore_syscall_restart_timeout(); 372 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(); 378 379 ModuleBundle::Stack()->store_syscall_restart_timeout(timeout); 380 return timeout; 381 } 382 383 384 #endif // PROTOCOL_UTILITIES_H 385