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