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