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