1 /* 2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "utility.h" 11 12 #include <ByteOrder.h> 13 #include <KernelExport.h> 14 15 #include <condition_variable.h> 16 #include <net_buffer.h> 17 #include <syscall_restart.h> 18 #include <util/AutoLock.h> 19 20 #include "stack_private.h" 21 22 23 #define TIMER_IS_RUNNING 0x80000000 24 25 // internal Fifo class which doesn't maintain it's own lock 26 // TODO: do we need this one for anything? 27 class Fifo { 28 public: 29 Fifo(const char* name, size_t maxBytes); 30 ~Fifo(); 31 32 status_t InitCheck() const; 33 34 status_t Enqueue(net_buffer* buffer); 35 status_t EnqueueAndNotify(net_buffer* _buffer, net_socket* socket, 36 uint8 event); 37 status_t Wait(mutex* lock, bigtime_t timeout); 38 net_buffer* Dequeue(bool clone); 39 status_t Clear(); 40 41 void WakeAll(); 42 43 bool IsEmpty() const { return current_bytes == 0; } 44 45 //private: 46 // these field names are kept so we can use templatized 47 // functions together with net_fifo 48 sem_id notify; 49 int32 waiting; 50 size_t max_bytes; 51 size_t current_bytes; 52 struct list buffers; 53 }; 54 55 56 57 static struct list sTimers; 58 static mutex sTimerLock; 59 static sem_id sTimerWaitSem; 60 static ConditionVariable sWaitForTimerCondition; 61 static thread_id sTimerThread; 62 static bigtime_t sTimerTimeout; 63 64 65 static inline void 66 fifo_notify_one_reader(int32& waiting, sem_id sem) 67 { 68 if (waiting > 0) { 69 waiting--; 70 release_sem_etc(sem, 1, B_DO_NOT_RESCHEDULE); 71 } 72 } 73 74 75 template<typename FifoType> static inline status_t 76 base_fifo_init(FifoType* fifo, const char* name, size_t maxBytes) 77 { 78 fifo->notify = create_sem(0, name); 79 fifo->max_bytes = maxBytes; 80 fifo->current_bytes = 0; 81 fifo->waiting = 0; 82 list_init(&fifo->buffers); 83 84 return fifo->notify; 85 } 86 87 88 template<typename FifoType> static inline status_t 89 base_fifo_enqueue_buffer(FifoType* fifo, net_buffer* buffer) 90 { 91 if (fifo->max_bytes > 0 92 && fifo->current_bytes + buffer->size > fifo->max_bytes) 93 return ENOBUFS; 94 95 list_add_item(&fifo->buffers, buffer); 96 fifo->current_bytes += buffer->size; 97 fifo_notify_one_reader(fifo->waiting, fifo->notify); 98 99 return B_OK; 100 } 101 102 103 template<typename FifoType> static inline status_t 104 base_fifo_clear(FifoType* fifo) 105 { 106 while (true) { 107 net_buffer* buffer = (net_buffer*)list_remove_head_item(&fifo->buffers); 108 if (buffer == NULL) 109 break; 110 111 gNetBufferModule.free(buffer); 112 } 113 114 fifo->current_bytes = 0; 115 return B_OK; 116 } 117 118 119 // #pragma mark - 120 121 122 void* 123 UserBuffer::Copy(void* source, size_t length) 124 { 125 if (fStatus != B_OK) 126 return NULL; 127 128 if (fAvailable < length) { 129 fStatus = ENOBUFS; 130 return NULL; 131 } 132 133 #ifdef _KERNEL_MODE 134 fStatus = user_memcpy(fBuffer, source, length); 135 if (fStatus < B_OK) 136 return NULL; 137 #else 138 memcpy(fBuffer, source, length); 139 #endif 140 141 void* current = fBuffer; 142 143 fAvailable -= length; 144 fBuffer += length; 145 146 return current; 147 } 148 149 150 uint16 151 compute_checksum(uint8* _buffer, size_t length) 152 { 153 uint16* buffer = (uint16*)_buffer; 154 uint32 sum = 0; 155 156 // TODO: unfold loop for speed 157 // TODO: write processor dependent version for speed 158 while (length >= 2) { 159 sum += *buffer++; 160 length -= 2; 161 } 162 163 if (length) { 164 // give the last byte it's proper endian-aware treatment 165 #if B_HOST_IS_LENDIAN 166 sum += *(uint8*)buffer; 167 #else 168 uint8 ordered[2]; 169 ordered[0] = *(uint8*)buffer; 170 ordered[1] = 0; 171 sum += *(uint16*)ordered; 172 #endif 173 } 174 175 while (sum >> 16) { 176 sum = (sum & 0xffff) + (sum >> 16); 177 } 178 179 return sum; 180 } 181 182 183 uint16 184 checksum(uint8* buffer, size_t length) 185 { 186 return ~compute_checksum(buffer, length); 187 } 188 189 190 // #pragma mark - Notifications 191 192 193 status_t 194 notify_socket(net_socket* socket, uint8 event, int32 value) 195 { 196 return gNetSocketModule.notify(socket, event, value); 197 } 198 199 200 // #pragma mark - FIFOs 201 202 203 Fifo::Fifo(const char* name, size_t maxBytes) 204 { 205 base_fifo_init(this, name, maxBytes); 206 } 207 208 209 Fifo::~Fifo() 210 { 211 Clear(); 212 delete_sem(notify); 213 } 214 215 216 status_t 217 Fifo::InitCheck() const 218 { 219 return !(notify < B_OK); 220 } 221 222 223 status_t 224 Fifo::Enqueue(net_buffer* buffer) 225 { 226 return base_fifo_enqueue_buffer(this, buffer); 227 } 228 229 230 status_t 231 Fifo::EnqueueAndNotify(net_buffer* _buffer, net_socket* socket, uint8 event) 232 { 233 net_buffer *buffer = gNetBufferModule.clone(_buffer, false); 234 if (buffer == NULL) 235 return B_NO_MEMORY; 236 237 status_t status = Enqueue(buffer); 238 if (status < B_OK) 239 gNetBufferModule.free(buffer); 240 else 241 notify_socket(socket, event, current_bytes); 242 243 return status; 244 } 245 246 247 status_t 248 Fifo::Wait(mutex* lock, bigtime_t timeout) 249 { 250 waiting++; 251 mutex_unlock(lock); 252 status_t status = acquire_sem_etc(notify, 1, 253 B_CAN_INTERRUPT | B_ABSOLUTE_TIMEOUT, timeout); 254 mutex_lock(lock); 255 return status; 256 } 257 258 259 net_buffer* 260 Fifo::Dequeue(bool clone) 261 { 262 net_buffer* buffer = (net_buffer*)list_get_first_item(&buffers); 263 264 // assert(buffer != NULL); 265 266 if (clone) { 267 buffer = gNetBufferModule.clone(buffer, false); 268 fifo_notify_one_reader(waiting, notify); 269 }else { 270 list_remove_item(&buffers, buffer); 271 current_bytes -= buffer->size; 272 } 273 274 return buffer; 275 } 276 277 278 ssize_t 279 Fifo::Clear() 280 { 281 return base_fifo_clear(this); 282 } 283 284 285 void 286 Fifo::WakeAll() 287 { 288 #ifdef __HAIKU__ 289 release_sem_etc(notify, 0, B_RELEASE_ALL); 290 #else 291 release_sem_etc(notify, 0, waiting); 292 #endif 293 } 294 295 296 status_t 297 init_fifo(net_fifo* fifo, const char* name, size_t maxBytes) 298 { 299 mutex_init_etc(&fifo->lock, name, MUTEX_FLAG_CLONE_NAME); 300 301 status_t status = base_fifo_init(fifo, name, maxBytes); 302 if (status < B_OK) 303 mutex_destroy(&fifo->lock); 304 305 return status; 306 } 307 308 309 void 310 uninit_fifo(net_fifo* fifo) 311 { 312 clear_fifo(fifo); 313 314 mutex_destroy(&fifo->lock); 315 delete_sem(fifo->notify); 316 } 317 318 319 status_t 320 fifo_enqueue_buffer(net_fifo* fifo, net_buffer* buffer) 321 { 322 MutexLocker locker(fifo->lock); 323 return base_fifo_enqueue_buffer(fifo, buffer); 324 } 325 326 327 /*! Gets the first buffer from the FIFO. If there is no buffer, it 328 will wait depending on the \a flags and \a timeout. 329 The following flags are supported (the rest is ignored): 330 MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your 331 socket is O_NONBLOCK, you should specify this flag. A \a timeout of 332 zero is equivalent to this flag, though. 333 MSG_PEEK - returns a clone of the buffer and keep the original 334 in the FIFO. 335 */ 336 ssize_t 337 fifo_dequeue_buffer(net_fifo* fifo, uint32 flags, bigtime_t timeout, 338 net_buffer** _buffer) 339 { 340 MutexLocker locker(fifo->lock); 341 bool dontWait = (flags & MSG_DONTWAIT) != 0 || timeout == 0; 342 status_t status; 343 344 while (true) { 345 net_buffer* buffer = (net_buffer*)list_get_first_item(&fifo->buffers); 346 if (buffer != NULL) { 347 if ((flags & MSG_PEEK) != 0) { 348 // we need to clone the buffer for inspection; we can't give a 349 // handle to a buffer that we're still using 350 buffer = gNetBufferModule.clone(buffer, false); 351 if (buffer == NULL) { 352 status = B_NO_MEMORY; 353 break; 354 } 355 } else { 356 list_remove_item(&fifo->buffers, buffer); 357 fifo->current_bytes -= buffer->size; 358 } 359 360 *_buffer = buffer; 361 status = B_OK; 362 break; 363 } 364 365 if (!dontWait) 366 fifo->waiting++; 367 368 locker.Unlock(); 369 370 if (dontWait) 371 return B_WOULD_BLOCK; 372 373 // we need to wait until a new buffer becomes available 374 status = acquire_sem_etc(fifo->notify, 1, 375 B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, timeout); 376 if (status < B_OK) 377 return status; 378 379 locker.Lock(); 380 } 381 382 // if another thread is waiting for data, since we didn't 383 // eat the buffer, it will get it 384 if (flags & MSG_PEEK) 385 fifo_notify_one_reader(fifo->waiting, fifo->notify); 386 387 return status; 388 } 389 390 391 status_t 392 clear_fifo(net_fifo* fifo) 393 { 394 MutexLocker locker(fifo->lock); 395 return base_fifo_clear(fifo); 396 } 397 398 399 status_t 400 fifo_socket_enqueue_buffer(net_fifo* fifo, net_socket* socket, uint8 event, 401 net_buffer* _buffer) 402 { 403 net_buffer *buffer = gNetBufferModule.clone(_buffer, false); 404 if (buffer == NULL) 405 return B_NO_MEMORY; 406 407 MutexLocker locker(fifo->lock); 408 409 status_t status = base_fifo_enqueue_buffer(fifo, buffer); 410 if (status < B_OK) 411 gNetBufferModule.free(buffer); 412 else 413 notify_socket(socket, event, fifo->current_bytes); 414 415 return status; 416 } 417 418 419 // #pragma mark - Timer 420 421 422 static status_t 423 timer_thread(void* /*data*/) 424 { 425 status_t status = B_OK; 426 427 do { 428 bigtime_t timeout = B_INFINITE_TIMEOUT; 429 430 if (status == B_TIMED_OUT || status == B_OK) { 431 // scan timers for new timeout and/or execute a timer 432 mutex_lock(&sTimerLock); 433 434 struct net_timer* timer = NULL; 435 while (true) { 436 timer = (net_timer*)list_get_next_item(&sTimers, timer); 437 if (timer == NULL) 438 break; 439 440 if (timer->due < system_time()) { 441 // execute timer 442 list_remove_item(&sTimers, timer); 443 timer->due = -1; 444 timer->flags |= TIMER_IS_RUNNING; 445 446 mutex_unlock(&sTimerLock); 447 timer->hook(timer, timer->data); 448 mutex_lock(&sTimerLock); 449 450 timer->flags &= ~TIMER_IS_RUNNING; 451 sWaitForTimerCondition.NotifyAll(); 452 timer = NULL; 453 // restart scanning as we unlocked the list 454 } else { 455 // calculate new timeout 456 if (timer->due < timeout) 457 timeout = timer->due; 458 } 459 } 460 461 sTimerTimeout = timeout; 462 mutex_unlock(&sTimerLock); 463 } 464 465 status = acquire_sem_etc(sTimerWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout); 466 // the wait sem normally can't be acquired, so we 467 // have to look at the status value the call returns: 468 // 469 // B_OK - a new timer has been added or canceled 470 // B_TIMED_OUT - look for timers to be executed 471 // B_BAD_SEM_ID - we are asked to quit 472 } while (status != B_BAD_SEM_ID); 473 474 return B_OK; 475 } 476 477 478 /*! 479 Initializes a timer before use. You can also use this function to change 480 a timer later on, but make sure you have canceled it before using set_timer(). 481 */ 482 void 483 init_timer(net_timer* timer, net_timer_func hook, void* data) 484 { 485 timer->hook = hook; 486 timer->data = data; 487 timer->due = 0; 488 timer->flags = 0; 489 } 490 491 492 /*! 493 Sets or cancels a timer. When the \a delay is below zero, an eventually running 494 timer is canceled, if not, it is scheduled to be executed after the specified 495 \a delay. 496 You need to have initialized the timer before calling this function. 497 In case you need to change a running timer, you have to cancel it first, before 498 making any changes. 499 */ 500 void 501 set_timer(net_timer* timer, bigtime_t delay) 502 { 503 MutexLocker locker(sTimerLock); 504 505 if (timer->due > 0 && delay < 0) { 506 // this timer is scheduled, cancel it 507 list_remove_item(&sTimers, timer); 508 timer->due = 0; 509 } 510 511 if (delay >= 0) { 512 // reschedule or add this timer 513 if (timer->due <= 0) 514 list_add_item(&sTimers, timer); 515 516 timer->due = system_time() + delay; 517 518 // notify timer about the change if necessary 519 if (sTimerTimeout > timer->due) 520 release_sem(sTimerWaitSem); 521 } 522 } 523 524 525 bool 526 cancel_timer(struct net_timer* timer) 527 { 528 MutexLocker locker(sTimerLock); 529 530 if (timer->due <= 0) 531 return false; 532 533 // this timer is scheduled, cancel it 534 list_remove_item(&sTimers, timer); 535 timer->due = 0; 536 return true; 537 } 538 539 540 void 541 wait_for_timer(struct net_timer* timer) 542 { 543 while (true) { 544 MutexLocker locker(sTimerLock); 545 546 if (timer->due <= 0 && (timer->flags & TIMER_IS_RUNNING) == 0) 547 return; 548 549 // we actually need to wait for this timer 550 ConditionVariableEntry entry; 551 sWaitForTimerCondition.Add(&entry); 552 553 locker.Unlock(); 554 555 entry.Wait(); 556 } 557 } 558 559 560 bool 561 is_timer_active(net_timer* timer) 562 { 563 return timer->due > 0; 564 } 565 566 567 static int 568 dump_timer(int argc, char** argv) 569 { 570 kprintf("timer hook data due in\n"); 571 572 struct net_timer* timer = NULL; 573 while (true) { 574 timer = (net_timer*)list_get_next_item(&sTimers, timer); 575 if (timer == NULL) 576 break; 577 578 kprintf("%p %p %p %Ld\n", timer, timer->hook, timer->data, 579 timer->due > 0 ? timer->due - system_time() : -1); 580 } 581 582 return 0; 583 } 584 585 586 status_t 587 init_timers(void) 588 { 589 list_init(&sTimers); 590 sTimerTimeout = B_INFINITE_TIMEOUT; 591 592 status_t status = B_OK; 593 mutex_init(&sTimerLock, "net timer"); 594 595 sTimerWaitSem = create_sem(0, "net timer wait"); 596 if (sTimerWaitSem < B_OK) { 597 status = sTimerWaitSem; 598 goto err1; 599 } 600 601 sTimerThread = spawn_kernel_thread(timer_thread, "net timer", 602 B_NORMAL_PRIORITY, NULL); 603 if (sTimerThread < B_OK) { 604 status = sTimerThread; 605 goto err2; 606 } 607 608 sWaitForTimerCondition.Init(NULL, "wait for net timer"); 609 610 add_debugger_command("net_timer", dump_timer, 611 "Lists all active network timer"); 612 613 return resume_thread(sTimerThread); 614 615 err1: 616 mutex_destroy(&sTimerLock); 617 err2: 618 delete_sem(sTimerWaitSem); 619 return status; 620 } 621 622 623 void 624 uninit_timers(void) 625 { 626 delete_sem(sTimerWaitSem); 627 mutex_lock(&sTimerLock); 628 629 mutex_destroy(&sTimerLock); 630 631 status_t status; 632 wait_for_thread(sTimerThread, &status); 633 } 634 635 636 // #pragma mark - Syscall restart 637 638 639 bool 640 is_syscall(void) 641 { 642 struct thread* thread = thread_get_current_thread(); 643 return (thread->flags & THREAD_FLAGS_SYSCALL) != 0; 644 } 645 646 647 bool 648 is_restarted_syscall(void) 649 { 650 return syscall_restart_is_restarted(); 651 } 652 653 654 void 655 store_syscall_restart_timeout(bigtime_t timeout) 656 { 657 struct thread* thread = thread_get_current_thread(); 658 if ((thread->flags & THREAD_FLAGS_SYSCALL) != 0) 659 *(bigtime_t*)thread->syscall_restart.parameters = timeout; 660 } 661 662 663 bigtime_t 664 restore_syscall_restart_timeout(void) 665 { 666 struct thread* thread = thread_get_current_thread(); 667 return *(bigtime_t*)thread->syscall_restart.parameters; 668 } 669 670