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 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(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 = MutexLocking, 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 net_buffer *buffer = ModuleBundle::Buffer()->clone(_buffer, false); 203 if (buffer == NULL) 204 return B_NO_MEMORY; 205 206 status_t status = _Enqueue(buffer); 207 if (status < B_OK) 208 ModuleBundle::Buffer()->free(buffer); 209 210 return status; 211 } 212 213 214 DECL_DATAGRAM_SOCKET(inline net_buffer *)::Dequeue(bool clone) 215 { 216 AutoLocker _(fLock); 217 return _Dequeue(clone); 218 } 219 220 221 DECL_DATAGRAM_SOCKET(inline net_buffer *)::_Dequeue(bool clone) 222 { 223 if (fBuffers.IsEmpty()) 224 return NULL; 225 226 if (clone) 227 return ModuleBundle::Buffer()->clone(fBuffers.Head(), false); 228 229 net_buffer *buffer = fBuffers.RemoveHead(); 230 fCurrentBytes -= buffer->size; 231 232 return buffer; 233 } 234 235 236 DECL_DATAGRAM_SOCKET(inline status_t)::BlockingDequeue(bool clone, 237 bigtime_t timeout, net_buffer **_buffer) 238 { 239 AutoLocker _(fLock); 240 241 bool waited = false; 242 while (fBuffers.IsEmpty()) { 243 status_t status = _SocketStatus(); 244 if (status < B_OK) 245 return status; 246 247 if ((status = _Wait(timeout)) < B_OK) 248 return status; 249 waited = true; 250 } 251 252 *_buffer = _Dequeue(clone); 253 if (clone && waited) { 254 // we were signalled there was a new buffer in the 255 // list; but since we are cloning, notify the next 256 // waiting reader. 257 _NotifyOneReader(false); 258 } 259 260 if (*_buffer == NULL) 261 return B_NO_MEMORY; 262 263 return B_OK; 264 } 265 266 267 DECL_DATAGRAM_SOCKET(inline status_t)::SocketDequeue(uint32 flags, 268 net_buffer **_buffer) 269 { 270 return BlockingDequeue(flags & MSG_PEEK, _SocketTimeout(flags), _buffer); 271 } 272 273 274 DECL_DATAGRAM_SOCKET(inline void)::Clear() 275 { 276 AutoLocker _(fLock); 277 _Clear(); 278 } 279 280 281 DECL_DATAGRAM_SOCKET(inline void)::_Clear() 282 { 283 BufferList::Iterator it = fBuffers.GetIterator(); 284 while (it.HasNext()) 285 ModuleBundle::Buffer()->free(it.Next()); 286 fCurrentBytes = 0; 287 } 288 289 290 DECL_DATAGRAM_SOCKET(inline ssize_t)::AvailableData() const 291 { 292 AutoLocker _(fLock); 293 status_t status = _SocketStatus(); 294 if (status < B_OK) 295 return status; 296 297 return fCurrentBytes; 298 } 299 300 301 DECL_DATAGRAM_SOCKET(inline status_t)::_SocketStatus() const 302 { 303 return B_OK; 304 } 305 306 307 DECL_DATAGRAM_SOCKET(inline status_t)::_Wait(bigtime_t timeout) 308 { 309 LockingBase::Unlock(&fLock); 310 status_t status = acquire_sem_etc(fNotify, 1, B_CAN_INTERRUPT 311 | B_ABSOLUTE_TIMEOUT, timeout); 312 LockingBase::Lock(&fLock); 313 314 return status; 315 } 316 317 318 DECL_DATAGRAM_SOCKET(inline void)::WakeAll() 319 { 320 release_sem_etc(fNotify, 0, B_RELEASE_ALL); 321 } 322 323 324 DECL_DATAGRAM_SOCKET(inline void)::_NotifyOneReader(bool notifySocket) 325 { 326 release_sem_etc(fNotify, 1, B_RELEASE_IF_WAITING_ONLY 327 | B_DO_NOT_RESCHEDULE); 328 329 if (notifySocket) 330 ModuleBundle::Stack()->notify_socket(fSocket, B_SELECT_READ, 331 fCurrentBytes); 332 } 333 334 335 DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const 336 { 337 bigtime_t timeout = fSocket->receive.timeout; 338 339 if (flags & MSG_DONTWAIT) 340 timeout = 0; 341 else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT) 342 timeout += system_time(); 343 344 if (ModuleBundle::Stack()->is_restarted_syscall()) 345 timeout = ModuleBundle::Stack()->restore_syscall_restart_timeout(); 346 else 347 ModuleBundle::Stack()->store_syscall_restart_timeout(timeout); 348 349 return timeout; 350 } 351 352 #endif 353