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 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 224 DECL_DATAGRAM_SOCKET(inline net_buffer*)::Dequeue(bool peek) 225 { 226 AutoLocker _(fLock); 227 return _Dequeue(peek); 228 } 229 230 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 266 DECL_DATAGRAM_SOCKET(inline void)::Clear() 267 { 268 AutoLocker _(fLock); 269 _Clear(); 270 } 271 272 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 284 DECL_DATAGRAM_SOCKET(inline void)::WakeAll() 285 { 286 release_sem_etc(fNotify, 0, B_RELEASE_ALL); 287 } 288 289 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 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 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 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 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 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 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 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