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 // internal Fifo class which doesn't maintain it's own lock 24 // TODO: do we need this one for anything? 25 class Fifo { 26 public: 27 Fifo(const char* name, size_t maxBytes); 28 ~Fifo(); 29 30 status_t InitCheck() const; 31 32 status_t Enqueue(net_buffer* buffer); 33 status_t EnqueueAndNotify(net_buffer* _buffer, net_socket* socket, 34 uint8 event); 35 status_t Wait(mutex* lock, bigtime_t timeout); 36 net_buffer* Dequeue(bool clone); 37 status_t Clear(); 38 39 void WakeAll(); 40 41 bool IsEmpty() const { return current_bytes == 0; } 42 43 //private: 44 // these field names are kept so we can use templatized 45 // functions together with net_fifo 46 sem_id notify; 47 int32 waiting; 48 size_t max_bytes; 49 size_t current_bytes; 50 struct list buffers; 51 }; 52 53 54 55 static struct list sTimers; 56 static mutex sTimerLock; 57 static sem_id sTimerWaitSem; 58 static ConditionVariable sWaitForTimerCondition; 59 static net_timer* sCurrentTimer; 60 static thread_id sTimerThread; 61 static bigtime_t sTimerTimeout; 62 63 64 static inline void 65 fifo_notify_one_reader(int32& waiting, sem_id sem) 66 { 67 if (waiting > 0) { 68 waiting--; 69 release_sem_etc(sem, 1, B_DO_NOT_RESCHEDULE); 70 } 71 } 72 73 74 template<typename FifoType> static inline status_t 75 base_fifo_init(FifoType* fifo, const char* name, size_t maxBytes) 76 { 77 fifo->notify = create_sem(0, name); 78 fifo->max_bytes = maxBytes; 79 fifo->current_bytes = 0; 80 fifo->waiting = 0; 81 list_init(&fifo->buffers); 82 83 return fifo->notify; 84 } 85 86 87 template<typename FifoType> static inline status_t 88 base_fifo_enqueue_buffer(FifoType* fifo, net_buffer* buffer) 89 { 90 if (fifo->max_bytes > 0 91 && fifo->current_bytes + buffer->size > fifo->max_bytes) 92 return ENOBUFS; 93 94 list_add_item(&fifo->buffers, buffer); 95 fifo->current_bytes += buffer->size; 96 fifo_notify_one_reader(fifo->waiting, fifo->notify); 97 98 return B_OK; 99 } 100 101 102 template<typename FifoType> static inline status_t 103 base_fifo_clear(FifoType* fifo) 104 { 105 while (true) { 106 net_buffer* buffer = (net_buffer*)list_remove_head_item(&fifo->buffers); 107 if (buffer == NULL) 108 break; 109 110 gNetBufferModule.free(buffer); 111 } 112 113 fifo->current_bytes = 0; 114 return B_OK; 115 } 116 117 118 // #pragma mark - 119 120 121 void* 122 UserBuffer::Copy(void* source, size_t length) 123 { 124 if (fStatus != B_OK) 125 return NULL; 126 127 if (fAvailable < length) { 128 fStatus = ENOBUFS; 129 return NULL; 130 } 131 132 #ifdef _KERNEL_MODE 133 fStatus = user_memcpy(fBuffer, source, length); 134 if (fStatus < B_OK) 135 return NULL; 136 #else 137 memcpy(fBuffer, source, length); 138 #endif 139 140 void* current = fBuffer; 141 142 fAvailable -= length; 143 fBuffer += length; 144 145 return current; 146 } 147 148 149 uint16 150 compute_checksum(uint8* _buffer, size_t length) 151 { 152 uint16* buffer = (uint16*)_buffer; 153 uint32 sum = 0; 154 155 // TODO: unfold loop for speed 156 // TODO: write processor dependent version for speed 157 while (length >= 2) { 158 sum += *buffer++; 159 length -= 2; 160 } 161 162 if (length) { 163 // give the last byte it's proper endian-aware treatment 164 #if B_HOST_IS_LENDIAN 165 sum += *(uint8*)buffer; 166 #else 167 uint8 ordered[2]; 168 ordered[0] = *(uint8*)buffer; 169 ordered[1] = 0; 170 sum += *(uint16*)ordered; 171 #endif 172 } 173 174 while (sum >> 16) { 175 sum = (sum & 0xffff) + (sum >> 16); 176 } 177 178 return sum; 179 } 180 181 182 uint16 183 checksum(uint8* buffer, size_t length) 184 { 185 return ~compute_checksum(buffer, length); 186 } 187 188 189 // #pragma mark - Notifications 190 191 192 status_t 193 notify_socket(net_socket* socket, uint8 event, int32 value) 194 { 195 return gNetSocketModule.notify(socket, event, value); 196 } 197 198 199 // #pragma mark - FIFOs 200 201 202 Fifo::Fifo(const char* name, size_t maxBytes) 203 { 204 base_fifo_init(this, name, maxBytes); 205 } 206 207 208 Fifo::~Fifo() 209 { 210 Clear(); 211 delete_sem(notify); 212 } 213 214 215 status_t 216 Fifo::InitCheck() const 217 { 218 return !(notify < B_OK); 219 } 220 221 222 status_t 223 Fifo::Enqueue(net_buffer* buffer) 224 { 225 return base_fifo_enqueue_buffer(this, buffer); 226 } 227 228 229 status_t 230 Fifo::EnqueueAndNotify(net_buffer* _buffer, net_socket* socket, uint8 event) 231 { 232 net_buffer *buffer = gNetBufferModule.clone(_buffer, false); 233 if (buffer == NULL) 234 return B_NO_MEMORY; 235 236 status_t status = Enqueue(buffer); 237 if (status < B_OK) 238 gNetBufferModule.free(buffer); 239 else 240 notify_socket(socket, event, current_bytes); 241 242 return status; 243 } 244 245 246 status_t 247 Fifo::Wait(mutex* lock, bigtime_t timeout) 248 { 249 waiting++; 250 mutex_unlock(lock); 251 status_t status = acquire_sem_etc(notify, 1, 252 B_CAN_INTERRUPT | B_ABSOLUTE_TIMEOUT, timeout); 253 mutex_lock(lock); 254 return status; 255 } 256 257 258 net_buffer* 259 Fifo::Dequeue(bool clone) 260 { 261 net_buffer* buffer = (net_buffer*)list_get_first_item(&buffers); 262 263 // assert(buffer != NULL); 264 265 if (clone) { 266 buffer = gNetBufferModule.clone(buffer, false); 267 fifo_notify_one_reader(waiting, notify); 268 }else { 269 list_remove_item(&buffers, buffer); 270 current_bytes -= buffer->size; 271 } 272 273 return buffer; 274 } 275 276 277 ssize_t 278 Fifo::Clear() 279 { 280 return base_fifo_clear(this); 281 } 282 283 284 void 285 Fifo::WakeAll() 286 { 287 #ifdef __HAIKU__ 288 release_sem_etc(notify, 0, B_RELEASE_ALL); 289 #else 290 release_sem_etc(notify, 0, waiting); 291 #endif 292 } 293 294 295 status_t 296 init_fifo(net_fifo* fifo, const char* name, size_t maxBytes) 297 { 298 mutex_init_etc(&fifo->lock, name, MUTEX_FLAG_CLONE_NAME); 299 300 status_t status = base_fifo_init(fifo, name, maxBytes); 301 if (status < B_OK) 302 mutex_destroy(&fifo->lock); 303 304 return status; 305 } 306 307 308 void 309 uninit_fifo(net_fifo* fifo) 310 { 311 clear_fifo(fifo); 312 313 mutex_destroy(&fifo->lock); 314 delete_sem(fifo->notify); 315 } 316 317 318 status_t 319 fifo_enqueue_buffer(net_fifo* fifo, net_buffer* buffer) 320 { 321 MutexLocker locker(fifo->lock); 322 return base_fifo_enqueue_buffer(fifo, buffer); 323 } 324 325 326 /*! Gets the first buffer from the FIFO. If there is no buffer, it 327 will wait depending on the \a flags and \a timeout. 328 The following flags are supported (the rest is ignored): 329 MSG_DONTWAIT - ignores the timeout and never wait for a buffer; if your 330 socket is O_NONBLOCK, you should specify this flag. A \a timeout of 331 zero is equivalent to this flag, though. 332 MSG_PEEK - returns a clone of the buffer and keep the original 333 in the FIFO. 334 */ 335 ssize_t 336 fifo_dequeue_buffer(net_fifo* fifo, uint32 flags, bigtime_t timeout, 337 net_buffer** _buffer) 338 { 339 MutexLocker locker(fifo->lock); 340 bool dontWait = (flags & MSG_DONTWAIT) != 0 || timeout == 0; 341 status_t status; 342 343 while (true) { 344 net_buffer* buffer = (net_buffer*)list_get_first_item(&fifo->buffers); 345 if (buffer != NULL) { 346 if ((flags & MSG_PEEK) != 0) { 347 // we need to clone the buffer for inspection; we can't give a 348 // handle to a buffer that we're still using 349 buffer = gNetBufferModule.clone(buffer, false); 350 if (buffer == NULL) { 351 status = B_NO_MEMORY; 352 break; 353 } 354 } else { 355 list_remove_item(&fifo->buffers, buffer); 356 fifo->current_bytes -= buffer->size; 357 } 358 359 *_buffer = buffer; 360 status = B_OK; 361 break; 362 } 363 364 if (!dontWait) 365 fifo->waiting++; 366 367 locker.Unlock(); 368 369 if (dontWait) 370 return B_WOULD_BLOCK; 371 372 // we need to wait until a new buffer becomes available 373 status = acquire_sem_etc(fifo->notify, 1, 374 B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, timeout); 375 if (status < B_OK) 376 return status; 377 378 locker.Lock(); 379 } 380 381 // if another thread is waiting for data, since we didn't 382 // eat the buffer, it will get it 383 if (flags & MSG_PEEK) 384 fifo_notify_one_reader(fifo->waiting, fifo->notify); 385 386 return status; 387 } 388 389 390 status_t 391 clear_fifo(net_fifo* fifo) 392 { 393 MutexLocker locker(fifo->lock); 394 return base_fifo_clear(fifo); 395 } 396 397 398 status_t 399 fifo_socket_enqueue_buffer(net_fifo* fifo, net_socket* socket, uint8 event, 400 net_buffer* _buffer) 401 { 402 net_buffer *buffer = gNetBufferModule.clone(_buffer, false); 403 if (buffer == NULL) 404 return B_NO_MEMORY; 405 406 MutexLocker locker(fifo->lock); 407 408 status_t status = base_fifo_enqueue_buffer(fifo, buffer); 409 if (status < B_OK) 410 gNetBufferModule.free(buffer); 411 else 412 notify_socket(socket, event, fifo->current_bytes); 413 414 return status; 415 } 416 417 418 // #pragma mark - Timer 419 420 421 static status_t 422 timer_thread(void* /*data*/) 423 { 424 status_t status = B_OK; 425 426 do { 427 bigtime_t timeout = B_INFINITE_TIMEOUT; 428 429 if (status == B_TIMED_OUT || status == B_OK) { 430 // scan timers for new timeout and/or execute a timer 431 mutex_lock(&sTimerLock); 432 433 struct net_timer* timer = NULL; 434 while (true) { 435 timer = (net_timer*)list_get_next_item(&sTimers, timer); 436 if (timer == NULL) 437 break; 438 439 if (timer->due < system_time()) { 440 // execute timer 441 list_remove_item(&sTimers, timer); 442 timer->due = -1; 443 sCurrentTimer = timer; 444 445 mutex_unlock(&sTimerLock); 446 timer->hook(timer, timer->data); 447 mutex_lock(&sTimerLock); 448 449 sCurrentTimer = NULL; 450 sWaitForTimerCondition.NotifyAll(); 451 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 status_t 541 wait_for_timer(struct net_timer* timer) 542 { 543 if (find_thread(NULL) == sTimerThread) { 544 // let's not wait for ourselves... 545 return B_BAD_VALUE; 546 } 547 548 while (true) { 549 MutexLocker locker(sTimerLock); 550 551 if (timer->due <= 0 && sCurrentTimer != timer) 552 return B_OK; 553 554 // we actually need to wait for this timer 555 ConditionVariableEntry entry; 556 sWaitForTimerCondition.Add(&entry); 557 558 locker.Unlock(); 559 560 entry.Wait(); 561 } 562 563 return B_OK; 564 } 565 566 567 bool 568 is_timer_active(net_timer* timer) 569 { 570 return timer->due > 0; 571 } 572 573 574 bool 575 is_timer_running(net_timer* timer) 576 { 577 return timer == sCurrentTimer; 578 } 579 580 581 static int 582 dump_timer(int argc, char** argv) 583 { 584 kprintf("timer hook data due in\n"); 585 586 struct net_timer* timer = NULL; 587 while (true) { 588 timer = (net_timer*)list_get_next_item(&sTimers, timer); 589 if (timer == NULL) 590 break; 591 592 kprintf("%p %p %p %Ld\n", timer, timer->hook, timer->data, 593 timer->due > 0 ? timer->due - system_time() : -1); 594 } 595 596 return 0; 597 } 598 599 600 status_t 601 init_timers(void) 602 { 603 list_init(&sTimers); 604 sTimerTimeout = B_INFINITE_TIMEOUT; 605 606 status_t status = B_OK; 607 mutex_init(&sTimerLock, "net timer"); 608 609 sTimerWaitSem = create_sem(0, "net timer wait"); 610 if (sTimerWaitSem < B_OK) { 611 status = sTimerWaitSem; 612 goto err1; 613 } 614 615 sTimerThread = spawn_kernel_thread(timer_thread, "net timer", 616 B_NORMAL_PRIORITY, NULL); 617 if (sTimerThread < B_OK) { 618 status = sTimerThread; 619 goto err2; 620 } 621 622 sWaitForTimerCondition.Init(NULL, "wait for net timer"); 623 624 add_debugger_command("net_timer", dump_timer, 625 "Lists all active network timer"); 626 627 return resume_thread(sTimerThread); 628 629 err1: 630 mutex_destroy(&sTimerLock); 631 err2: 632 delete_sem(sTimerWaitSem); 633 return status; 634 } 635 636 637 void 638 uninit_timers(void) 639 { 640 delete_sem(sTimerWaitSem); 641 mutex_lock(&sTimerLock); 642 643 mutex_destroy(&sTimerLock); 644 645 status_t status; 646 wait_for_thread(sTimerThread, &status); 647 } 648 649 650 // #pragma mark - Syscall restart 651 652 653 bool 654 is_syscall(void) 655 { 656 struct thread* thread = thread_get_current_thread(); 657 return (thread->flags & THREAD_FLAGS_SYSCALL) != 0; 658 } 659 660 661 bool 662 is_restarted_syscall(void) 663 { 664 return syscall_restart_is_restarted(); 665 } 666 667 668 void 669 store_syscall_restart_timeout(bigtime_t timeout) 670 { 671 struct thread* thread = thread_get_current_thread(); 672 if ((thread->flags & THREAD_FLAGS_SYSCALL) != 0) 673 *(bigtime_t*)thread->syscall_restart.parameters = timeout; 674 } 675 676 677 bigtime_t 678 restore_syscall_restart_timeout(void) 679 { 680 struct thread* thread = thread_get_current_thread(); 681 return *(bigtime_t*)thread->syscall_restart.parameters; 682 } 683 684