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 "argv.h" 11 #include "tcp.h" 12 #include "utility.h" 13 14 #include <NetBufferUtilities.h> 15 #include <net_buffer.h> 16 #include <net_datalink.h> 17 #include <net_protocol.h> 18 #include <net_socket.h> 19 #include <net_stack.h> 20 #include <slab/Slab.h> 21 #include <util/AutoLock.h> 22 #include <util/DoublyLinkedList.h> 23 24 #include <KernelExport.h> 25 #include <Select.h> 26 #include <module.h> 27 #include <Locker.h> 28 29 #include <ctype.h> 30 #include <netinet/in.h> 31 #include <new> 32 #include <set> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 38 struct context { 39 BLocker lock; 40 sem_id wait_sem; 41 struct list list; 42 net_route route; 43 bool server; 44 thread_id thread; 45 }; 46 47 struct cmd_entry { 48 const char* name; 49 void (*func)(int argc, char **argv); 50 const char* help; 51 }; 52 53 54 struct net_socket_private; 55 typedef DoublyLinkedList<net_socket_private> SocketList; 56 57 struct net_socket_private : net_socket, 58 DoublyLinkedListLinkImpl<net_socket_private> { 59 struct net_socket *parent; 60 61 team_id owner; 62 uint32 max_backlog; 63 uint32 child_count; 64 SocketList pending_children; 65 SocketList connected_children; 66 67 struct select_sync_pool *select_pool; 68 mutex lock; 69 }; 70 71 72 extern "C" status_t _add_builtin_module(module_info *info); 73 extern "C" status_t _get_builtin_dependencies(void); 74 extern bool gDebugOutputEnabled; 75 // from libkernelland_emu.so 76 77 extern struct net_buffer_module_info gNetBufferModule; 78 // from net_buffer.cpp 79 extern net_address_module_info gIPv4AddressModule; 80 // from ipv4_address.cpp 81 extern module_info *modules[]; 82 // from tcp.cpp 83 84 85 extern struct net_protocol_module_info gDomainModule; 86 struct net_interface_address gInterfaceAddress = {}; 87 extern struct net_socket_module_info gNetSocketModule; 88 struct net_protocol_module_info *gTCPModule; 89 struct net_socket *gServerSocket, *gClientSocket; 90 static struct context sClientContext, sServerContext; 91 92 static int32 sPacketNumber = 1; 93 static double sRandomDrop = 0.0; 94 static std::set<uint32> sDropList; 95 static bigtime_t sRoundTripTime = 0; 96 static bool sIncreasingRoundTrip = false; 97 static bool sRandomRoundTrip = false; 98 static bool sTCPDump = true; 99 static bigtime_t sStartTime; 100 static double sRandomReorder = 0.0; 101 static std::set<uint32> sReorderList; 102 static bool sSimultaneousConnect = false; 103 static bool sSimultaneousClose = false; 104 static bool sServerActiveClose = false; 105 106 static struct net_domain sDomain = { 107 "ipv4", 108 AF_INET, 109 110 &gDomainModule, 111 &gIPv4AddressModule 112 }; 113 114 115 static bool 116 is_server(const sockaddr* addr) 117 { 118 return ((sockaddr_in*)addr)->sin_port == htons(1024); 119 } 120 121 122 static uint8 123 tcp_segment_flags(net_buffer* buffer) 124 { 125 NetBufferHeaderReader<tcp_header> bufferHeader(buffer); 126 if (bufferHeader.Status() < B_OK) 127 return bufferHeader.Status(); 128 129 tcp_header &header = bufferHeader.Data(); 130 return header.flags; 131 } 132 133 134 static bool 135 is_syn(net_buffer* buffer) 136 { 137 return (tcp_segment_flags(buffer) & TCP_FLAG_SYNCHRONIZE) != 0; 138 } 139 140 141 static bool 142 is_fin(net_buffer* buffer) 143 { 144 return (tcp_segment_flags(buffer) & TCP_FLAG_FINISH) != 0; 145 } 146 147 148 // #pragma mark - stack 149 150 151 status_t 152 std_ops(int32, ...) 153 { 154 return B_OK; 155 } 156 157 158 net_domain * 159 get_domain(int family) 160 { 161 return &sDomain; 162 } 163 164 165 status_t 166 register_domain_protocols(int family, int type, int protocol, ...) 167 { 168 return B_OK; 169 } 170 171 172 status_t 173 register_domain_datalink_protocols(int family, int type, ...) 174 { 175 return B_OK; 176 } 177 178 179 static status_t 180 register_domain_receiving_protocol(int family, int type, const char *moduleName) 181 { 182 return B_OK; 183 } 184 185 186 static bool 187 dummy_is_syscall(void) 188 { 189 return false; 190 } 191 192 193 static bool 194 dummy_is_restarted_syscall(void) 195 { 196 return false; 197 } 198 199 200 static void 201 dummy_store_syscall_restart_timeout(bigtime_t timeout) 202 { 203 } 204 205 206 static net_stack_module_info gNetStackModule = { 207 { 208 NET_STACK_MODULE_NAME, 209 0, 210 std_ops 211 }, 212 NULL, // register_domain, 213 NULL, // unregister_domain, 214 get_domain, 215 216 register_domain_protocols, 217 register_domain_datalink_protocols, 218 register_domain_receiving_protocol, 219 220 NULL, // get_domain_receiving_protocol, 221 NULL, // put_domain_receiving_protocol, 222 223 NULL, // register_device_deframer, 224 NULL, // unregister_device_deframer, 225 NULL, // register_domain_device_handler, 226 NULL, // register_device_handler, 227 NULL, // unregister_device_handler, 228 NULL, // register_device_monitor, 229 NULL, // unregister_device_monitor, 230 NULL, // device_link_changed, 231 NULL, // device_removed, 232 NULL, // device_enqueue_buffer, 233 234 notify_socket, 235 236 checksum, 237 238 init_fifo, 239 uninit_fifo, 240 fifo_enqueue_buffer, 241 fifo_dequeue_buffer, 242 clear_fifo, 243 fifo_socket_enqueue_buffer, 244 245 init_timer, 246 set_timer, 247 cancel_timer, 248 wait_for_timer, 249 is_timer_active, 250 is_timer_running, 251 252 dummy_is_syscall, 253 dummy_is_restarted_syscall, 254 dummy_store_syscall_restart_timeout, 255 NULL, // restore_syscall_restart_timeout 256 257 // ancillary data is not used by TCP 258 }; 259 260 261 // #pragma mark - socket 262 263 264 status_t 265 socket_create(int family, int type, int protocol, net_socket **_socket) 266 { 267 net_protocol* domainProtocol; 268 269 struct net_socket_private *socket = new (std::nothrow) net_socket_private; 270 if (socket == NULL) 271 return B_NO_MEMORY; 272 273 memset(socket, 0, sizeof(net_socket)); 274 socket->family = family; 275 socket->type = type; 276 socket->protocol = protocol; 277 278 mutex_init(&socket->lock, "socket"); 279 280 // set defaults (may be overridden by the protocols) 281 socket->send.buffer_size = 65535; 282 socket->send.low_water_mark = 1; 283 socket->send.timeout = B_INFINITE_TIMEOUT; 284 socket->receive.buffer_size = 65535; 285 socket->receive.low_water_mark = 1; 286 socket->receive.timeout = B_INFINITE_TIMEOUT; 287 288 socket->first_protocol = gTCPModule->init_protocol(socket); 289 if (socket->first_protocol == NULL) { 290 fprintf(stderr, "tcp_tester: cannot create protocol\n"); 291 mutex_destroy(&socket->lock); 292 delete socket; 293 return B_ERROR; 294 } 295 296 socket->first_info = gTCPModule; 297 298 domainProtocol = new net_protocol; 299 domainProtocol->module = &gDomainModule; 300 domainProtocol->socket = socket; 301 302 socket->first_protocol->next = domainProtocol; 303 socket->first_protocol->module = gTCPModule; 304 socket->first_protocol->socket = socket; 305 306 *_socket = socket; 307 return B_OK; 308 } 309 310 311 void 312 socket_delete(net_socket *_socket) 313 { 314 net_socket_private *socket = (net_socket_private *)_socket; 315 316 if (socket->parent != NULL) 317 panic("socket still has a parent!"); 318 319 socket->first_info->uninit_protocol(socket->first_protocol); 320 mutex_destroy(&socket->lock); 321 delete socket; 322 } 323 324 325 int 326 socket_accept(net_socket *socket, struct sockaddr *address, 327 socklen_t *_addressLength, net_socket **_acceptedSocket) 328 { 329 net_socket *accepted; 330 status_t status = socket->first_info->accept(socket->first_protocol, 331 &accepted); 332 if (status < B_OK) 333 return status; 334 335 if (address && *_addressLength > 0) { 336 memcpy(address, &accepted->peer, min_c(*_addressLength, 337 accepted->peer.ss_len)); 338 *_addressLength = accepted->peer.ss_len; 339 } 340 341 *_acceptedSocket = accepted; 342 return B_OK; 343 } 344 345 346 int 347 socket_bind(net_socket *socket, const struct sockaddr *address, socklen_t addressLength) 348 { 349 sockaddr empty; 350 if (address == NULL) { 351 // special - try to bind to an empty address, like INADDR_ANY 352 memset(&empty, 0, sizeof(sockaddr)); 353 empty.sa_len = sizeof(sockaddr); 354 empty.sa_family = socket->family; 355 356 address = ∅ 357 addressLength = sizeof(sockaddr); 358 } 359 360 if (socket->address.ss_len != 0) { 361 status_t status = socket->first_info->unbind(socket->first_protocol, 362 (sockaddr *)&socket->address); 363 if (status < B_OK) 364 return status; 365 } 366 367 memcpy(&socket->address, address, sizeof(sockaddr)); 368 369 status_t status = socket->first_info->bind(socket->first_protocol, 370 (sockaddr *)address); 371 if (status < B_OK) { 372 // clear address again, as binding failed 373 socket->address.ss_len = 0; 374 } 375 376 return status; 377 } 378 379 380 int 381 socket_connect(net_socket *socket, const struct sockaddr *address, socklen_t addressLength) 382 { 383 if (address == NULL || addressLength == 0) 384 return ENETUNREACH; 385 386 if (socket->address.ss_len == 0) { 387 // try to bind first 388 status_t status = socket_bind(socket, NULL, 0); 389 if (status < B_OK) 390 return status; 391 } 392 393 return socket->first_info->connect(socket->first_protocol, address); 394 } 395 396 397 int 398 socket_listen(net_socket *socket, int backlog) 399 { 400 status_t status = socket->first_info->listen(socket->first_protocol, backlog); 401 if (status == B_OK) 402 socket->options |= SO_ACCEPTCONN; 403 404 return status; 405 } 406 407 408 ssize_t 409 socket_send(net_socket *socket, const void *data, size_t length, int flags) 410 { 411 if (socket->peer.ss_len == 0) 412 return EDESTADDRREQ; 413 414 if (socket->address.ss_len == 0) { 415 // try to bind first 416 status_t status = socket_bind(socket, NULL, 0); 417 if (status < B_OK) 418 return status; 419 } 420 421 // TODO: useful, maybe even computed header space! 422 net_buffer *buffer = gNetBufferModule.create(256); 423 if (buffer == NULL) 424 return ENOBUFS; 425 426 // copy data into buffer 427 if (gNetBufferModule.append(buffer, data, length) < B_OK) { 428 gNetBufferModule.free(buffer); 429 return ENOBUFS; 430 } 431 432 buffer->flags = flags; 433 memcpy(buffer->source, &socket->address, socket->address.ss_len); 434 memcpy(buffer->destination, &socket->peer, socket->peer.ss_len); 435 436 status_t status = socket->first_info->send_data(socket->first_protocol, buffer); 437 if (status < B_OK) { 438 gNetBufferModule.free(buffer); 439 return status; 440 } 441 442 return length; 443 } 444 445 446 ssize_t 447 socket_recv(net_socket *socket, void *data, size_t length, int flags) 448 { 449 net_buffer *buffer; 450 ssize_t status = socket->first_info->read_data( 451 socket->first_protocol, length, flags, &buffer); 452 if (status < B_OK) 453 return status; 454 455 // if 0 bytes we're received, no buffer will be created 456 if (buffer == NULL) 457 return 0; 458 459 ssize_t bytesReceived = buffer->size; 460 gNetBufferModule.read(buffer, 0, data, bytesReceived); 461 gNetBufferModule.free(buffer); 462 463 return bytesReceived; 464 } 465 466 467 bool 468 socket_acquire(net_socket* _socket) 469 { 470 return true; 471 } 472 473 474 bool 475 socket_release(net_socket* _socket) 476 { 477 return true; 478 } 479 480 481 status_t 482 socket_spawn_pending(net_socket *_parent, net_socket **_socket) 483 { 484 net_socket_private *parent = (net_socket_private *)_parent; 485 486 MutexLocker locker(parent->lock); 487 488 // We actually accept more pending connections to compensate for those 489 // that never complete, and also make sure at least a single connection 490 // can always be accepted 491 if (parent->child_count > 3 * parent->max_backlog / 2) 492 return ENOBUFS; 493 494 net_socket_private *socket; 495 status_t status = socket_create(parent->family, parent->type, parent->protocol, 496 (net_socket **)&socket); 497 if (status < B_OK) 498 return status; 499 500 // inherit parent's properties 501 socket->send = parent->send; 502 socket->receive = parent->receive; 503 socket->options = parent->options & ~SO_ACCEPTCONN; 504 socket->linger = parent->linger; 505 memcpy(&socket->address, &parent->address, parent->address.ss_len); 506 memcpy(&socket->peer, &parent->peer, parent->peer.ss_len); 507 508 // add to the parent's list of pending connections 509 parent->pending_children.Add(socket); 510 socket->parent = parent; 511 parent->child_count++; 512 513 *_socket = socket; 514 return B_OK; 515 } 516 517 518 status_t 519 socket_dequeue_connected(net_socket *_parent, net_socket **_socket) 520 { 521 net_socket_private *parent = (net_socket_private *)_parent; 522 523 mutex_lock(&parent->lock); 524 525 net_socket_private *socket = parent->connected_children.RemoveHead(); 526 if (socket != NULL) { 527 socket->parent = NULL; 528 parent->child_count--; 529 *_socket = socket; 530 } 531 532 mutex_unlock(&parent->lock); 533 return socket != NULL ? B_OK : B_ENTRY_NOT_FOUND; 534 } 535 536 537 ssize_t 538 socket_count_connected(net_socket *_parent) 539 { 540 net_socket_private *parent = (net_socket_private *)_parent; 541 542 MutexLocker _(parent->lock); 543 544 return parent->connected_children.Count(); 545 } 546 547 548 status_t 549 socket_set_max_backlog(net_socket *_socket, uint32 backlog) 550 { 551 net_socket_private *socket = (net_socket_private *)_socket; 552 553 // we enforce an upper limit of connections waiting to be accepted 554 if (backlog > 256) 555 backlog = 256; 556 557 mutex_lock(&socket->lock); 558 559 // first remove the pending connections, then the already connected ones as needed 560 net_socket_private *child; 561 while (socket->child_count > backlog 562 && (child = socket->pending_children.RemoveTail()) != NULL) { 563 child->parent = NULL; 564 socket->child_count--; 565 } 566 while (socket->child_count > backlog 567 && (child = socket->connected_children.RemoveTail()) != NULL) { 568 child->parent = NULL; 569 socket_delete(child); 570 socket->child_count--; 571 } 572 573 socket->max_backlog = backlog; 574 mutex_unlock(&socket->lock); 575 return B_OK; 576 } 577 578 579 bool 580 socket_has_parent(net_socket* _socket) 581 { 582 net_socket_private* socket = (net_socket_private*)_socket; 583 return socket->parent != NULL; 584 } 585 586 587 status_t 588 socket_connected(net_socket *socket) 589 { 590 net_socket_private *socket_private = (net_socket_private *)socket; 591 net_socket_private *parent = (net_socket_private *)socket_private->parent; 592 if (parent == NULL) 593 return B_BAD_VALUE; 594 595 mutex_lock(&parent->lock); 596 597 parent->pending_children.Remove(socket_private); 598 parent->connected_children.Add(socket_private); 599 600 mutex_unlock(&parent->lock); 601 return B_OK; 602 } 603 604 605 status_t 606 socket_notify(net_socket *_socket, uint8 event, int32 value) 607 { 608 net_socket_private *socket = (net_socket_private *)_socket; 609 610 mutex_lock(&socket->lock); 611 612 bool notify = true; 613 614 switch (event) { 615 case B_SELECT_READ: 616 { 617 if ((ssize_t)socket->receive.low_water_mark > value && value >= B_OK) 618 notify = false; 619 break; 620 } 621 case B_SELECT_WRITE: 622 { 623 if ((ssize_t)socket->send.low_water_mark > value && value >= B_OK) 624 notify = false; 625 break; 626 } 627 case B_SELECT_ERROR: 628 socket->error = value; 629 break; 630 } 631 632 if (notify) 633 ; 634 635 mutex_unlock(&socket->lock); 636 return B_OK; 637 } 638 639 640 net_socket_module_info gNetSocketModule = { 641 { 642 NET_SOCKET_MODULE_NAME, 643 0, 644 std_ops 645 }, 646 NULL, // open, 647 NULL, // close, 648 NULL, // free, 649 650 NULL, // control, 651 652 NULL, // read_avail, 653 NULL, // send_avail, 654 655 NULL, // send_data, 656 NULL, // receive_data, 657 658 NULL, // get_option, 659 NULL, // set_option, 660 NULL, // get_next_stat, 661 662 socket_acquire, 663 socket_release, 664 665 // connections 666 socket_spawn_pending, 667 socket_dequeue_connected, 668 socket_count_connected, 669 socket_set_max_backlog, 670 socket_has_parent, 671 socket_connected, 672 NULL, // set_aborted 673 674 // notifications 675 NULL, // request_notification, 676 NULL, // cancel_notification, 677 socket_notify, 678 679 // standard socket API 680 NULL, // accept, 681 NULL, // bind, 682 NULL, // connect, 683 NULL, // getpeername, 684 NULL, // getsockname, 685 NULL, // getsockopt, 686 NULL, // listen, 687 NULL, // receive, 688 NULL, // send, 689 NULL, // setsockopt, 690 NULL, // shutdown, 691 NULL, // socketpair 692 }; 693 694 695 // #pragma mark - protocol 696 697 698 net_protocol* 699 init_protocol(net_socket** _socket) 700 { 701 net_socket *socket; 702 status_t status = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &socket); 703 if (status < B_OK) 704 return NULL; 705 706 status = socket->first_info->open(socket->first_protocol); 707 if (status < B_OK) { 708 fprintf(stderr, "tcp_tester: cannot open client: %s\n", strerror(status)); 709 socket_delete(socket); 710 return NULL; 711 } 712 713 *_socket = socket; 714 return socket->first_protocol; 715 } 716 717 718 void 719 close_protocol(net_protocol* protocol) 720 { 721 gTCPModule->close(protocol); 722 if (gTCPModule->free(protocol) == B_OK) 723 gTCPModule->uninit_protocol(protocol); 724 //socket_delete(protocol->socket); 725 } 726 727 728 // #pragma mark - datalink 729 730 731 status_t 732 datalink_send_data(struct net_route *route, net_buffer *buffer) 733 { 734 struct context* context = (struct context*)route->gateway; 735 736 buffer->interface_address = &gInterfaceAddress; 737 738 context->lock.Lock(); 739 list_add_item(&context->list, buffer); 740 context->lock.Unlock(); 741 742 release_sem(context->wait_sem); 743 return B_OK; 744 } 745 746 747 status_t 748 datalink_send_datagram(net_protocol *protocol, net_domain *domain, 749 net_buffer *buffer) 750 { 751 panic("called"); 752 return B_ERROR; 753 } 754 755 756 struct net_route * 757 get_route(struct net_domain *_domain, const struct sockaddr *address) 758 { 759 if (is_server(address)) { 760 // to the server 761 return &sServerContext.route; 762 } 763 764 return &sClientContext.route; 765 } 766 767 768 net_datalink_module_info gNetDatalinkModule = { 769 { 770 NET_DATALINK_MODULE_NAME, 771 0, 772 std_ops 773 }, 774 775 NULL, // control 776 datalink_send_data, 777 datalink_send_datagram, 778 779 NULL, // is_local_address 780 NULL, // is_local_link_address 781 782 NULL, // get_interface 783 NULL, // get_interface_with_address 784 NULL, // put_interface 785 786 NULL, // get_interface_address 787 NULL, // get_next_interface_address, 788 NULL, // put_interface_address 789 790 NULL, // join_multicast 791 NULL, // leave_multicast 792 793 NULL, //add_route, 794 NULL, //remove_route, 795 get_route, 796 NULL, //put_route, 797 NULL, //register_route_info, 798 NULL, //unregister_route_info, 799 NULL, //update_route_info 800 }; 801 802 803 // #pragma mark - domain 804 805 806 status_t 807 domain_open(net_protocol *protocol) 808 { 809 return B_OK; 810 } 811 812 813 status_t 814 domain_close(net_protocol *protocol) 815 { 816 return B_OK; 817 } 818 819 820 status_t 821 domain_free(net_protocol *protocol) 822 { 823 return B_OK; 824 } 825 826 827 status_t 828 domain_connect(net_protocol *protocol, const struct sockaddr *address) 829 { 830 return B_ERROR; 831 } 832 833 834 status_t 835 domain_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 836 { 837 return EOPNOTSUPP; 838 } 839 840 841 status_t 842 domain_control(net_protocol *protocol, int level, int option, void *value, 843 size_t *_length) 844 { 845 return B_ERROR; 846 } 847 848 849 status_t 850 domain_bind(net_protocol *protocol, const struct sockaddr *address) 851 { 852 memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in)); 853 protocol->socket->address.ss_len = sizeof(struct sockaddr_in); 854 // explicitly set length, as our callers can't be trusted to 855 // always provide the correct length! 856 return B_OK; 857 } 858 859 860 status_t 861 domain_unbind(net_protocol *protocol, struct sockaddr *address) 862 { 863 return B_OK; 864 } 865 866 867 status_t 868 domain_listen(net_protocol *protocol, int count) 869 { 870 return EOPNOTSUPP; 871 } 872 873 874 status_t 875 domain_shutdown(net_protocol *protocol, int direction) 876 { 877 return EOPNOTSUPP; 878 } 879 880 881 status_t 882 domain_send_data(net_protocol *protocol, net_buffer *buffer) 883 { 884 // find route 885 struct net_route *route = get_route(&sDomain, (sockaddr *)&buffer->destination); 886 if (route == NULL) 887 return ENETUNREACH; 888 889 return datalink_send_data(route, buffer); 890 } 891 892 893 status_t 894 domain_send_routed_data(net_protocol *protocol, struct net_route *route, 895 net_buffer *buffer) 896 { 897 return datalink_send_data(route, buffer); 898 } 899 900 901 ssize_t 902 domain_send_avail(net_protocol *protocol) 903 { 904 return B_ERROR; 905 } 906 907 908 status_t 909 domain_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 910 net_buffer **_buffer) 911 { 912 return B_ERROR; 913 } 914 915 916 ssize_t 917 domain_read_avail(net_protocol *protocol) 918 { 919 return B_ERROR; 920 } 921 922 923 struct net_domain * 924 domain_get_domain(net_protocol *protocol) 925 { 926 return &sDomain; 927 } 928 929 930 size_t 931 domain_get_mtu(net_protocol *protocol, const struct sockaddr *address) 932 { 933 return 1480; 934 // 1500 ethernet - IPv4 header 935 } 936 937 938 status_t 939 domain_receive_data(net_buffer *buffer) 940 { 941 static bigtime_t lastTime = 0; 942 943 uint32 packetNumber = atomic_add(&sPacketNumber, 1); 944 945 bool drop = false; 946 if (sDropList.find(packetNumber) != sDropList.end() 947 || (sRandomDrop > 0.0 && (1.0 * rand() / RAND_MAX) > sRandomDrop)) 948 drop = true; 949 950 if (!drop && (sRoundTripTime > 0 || sRandomRoundTrip || sIncreasingRoundTrip)) { 951 bigtime_t add = 0; 952 if (sRandomRoundTrip) 953 add = (bigtime_t)(1.0 * rand() / RAND_MAX * 500000) - 250000; 954 if (sIncreasingRoundTrip) 955 sRoundTripTime += (bigtime_t)(1.0 * rand() / RAND_MAX * 150000); 956 957 snooze(sRoundTripTime / 2 + add); 958 } 959 960 if (sTCPDump) { 961 NetBufferHeaderReader<tcp_header> bufferHeader(buffer); 962 if (bufferHeader.Status() < B_OK) 963 return bufferHeader.Status(); 964 965 tcp_header &header = bufferHeader.Data(); 966 967 bigtime_t now = system_time(); 968 if (lastTime == 0) 969 lastTime = now; 970 971 printf("\33[0m% 3ld %8.6f (%8.6f) ", packetNumber, (now - sStartTime) / 1000000.0, 972 (now - lastTime) / 1000000.0); 973 lastTime = now; 974 975 if (is_server((sockaddr *)buffer->source)) 976 printf("\33[31mserver > client: "); 977 else 978 printf("client > server: "); 979 980 int32 length = buffer->size - header.HeaderLength(); 981 982 if ((header.flags & TCP_FLAG_PUSH) != 0) 983 putchar('P'); 984 if ((header.flags & TCP_FLAG_SYNCHRONIZE) != 0) 985 putchar('S'); 986 if ((header.flags & TCP_FLAG_FINISH) != 0) 987 putchar('F'); 988 if ((header.flags & TCP_FLAG_RESET) != 0) 989 putchar('R'); 990 if ((header.flags 991 & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_PUSH | TCP_FLAG_RESET)) == 0) 992 putchar('.'); 993 994 printf(" %lu:%lu (%lu)", header.Sequence(), header.Sequence() + length, length); 995 if ((header.flags & TCP_FLAG_ACKNOWLEDGE) != 0) 996 printf(" ack %lu", header.Acknowledge()); 997 998 printf(" win %u", header.AdvertisedWindow()); 999 1000 if (header.HeaderLength() > sizeof(tcp_header)) { 1001 int32 size = header.HeaderLength() - sizeof(tcp_header); 1002 1003 tcp_option *option; 1004 uint8 optionsBuffer[1024]; 1005 if (gBufferModule->direct_access(buffer, sizeof(tcp_header), 1006 size, (void **)&option) != B_OK) { 1007 if (size > 1024) { 1008 printf("options too large to take into account (%ld bytes)\n", size); 1009 size = 1024; 1010 } 1011 1012 gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size); 1013 option = (tcp_option *)optionsBuffer; 1014 } 1015 1016 while (size > 0) { 1017 uint32 length = 1; 1018 switch (option->kind) { 1019 case TCP_OPTION_END: 1020 case TCP_OPTION_NOP: 1021 break; 1022 case TCP_OPTION_MAX_SEGMENT_SIZE: 1023 printf(" <mss %u>", ntohs(option->max_segment_size)); 1024 length = 4; 1025 break; 1026 case TCP_OPTION_WINDOW_SHIFT: 1027 printf(" <ws %u>", option->window_shift); 1028 length = 3; 1029 break; 1030 case TCP_OPTION_TIMESTAMP: 1031 printf(" <ts %lu:%lu>", option->timestamp.value, option->timestamp.reply); 1032 length = 10; 1033 break; 1034 1035 default: 1036 length = option->length; 1037 // make sure we don't end up in an endless loop 1038 if (length == 0) 1039 size = 0; 1040 break; 1041 } 1042 1043 size -= length; 1044 option = (tcp_option *)((uint8 *)option + length); 1045 } 1046 } 1047 1048 if (drop) 1049 printf(" <DROPPED>"); 1050 printf("\33[0m\n"); 1051 } else if (drop) 1052 printf("<**** DROPPED %ld ****>\n", packetNumber); 1053 1054 if (drop) { 1055 gNetBufferModule.free(buffer); 1056 return B_OK; 1057 } 1058 1059 return gTCPModule->receive_data(buffer); 1060 } 1061 1062 1063 status_t 1064 domain_error(net_error error, net_buffer* data) 1065 { 1066 return B_ERROR; 1067 } 1068 1069 1070 status_t 1071 domain_error_reply(net_protocol* self, net_buffer* cause, 1072 net_error error, net_error_data* errorData) 1073 { 1074 return B_ERROR; 1075 } 1076 1077 1078 net_protocol_module_info gDomainModule = { 1079 { 1080 NULL, 1081 0, 1082 std_ops 1083 }, 1084 NET_PROTOCOL_ATOMIC_MESSAGES, 1085 1086 NULL, // init 1087 NULL, // uninit 1088 domain_open, 1089 domain_close, 1090 domain_free, 1091 domain_connect, 1092 domain_accept, 1093 domain_control, 1094 NULL, // getsockopt 1095 NULL, // setsockopt 1096 domain_bind, 1097 domain_unbind, 1098 domain_listen, 1099 domain_shutdown, 1100 domain_send_data, 1101 domain_send_routed_data, 1102 domain_send_avail, 1103 domain_read_data, 1104 domain_read_avail, 1105 domain_get_domain, 1106 domain_get_mtu, 1107 domain_receive_data, 1108 NULL, // deliver_data 1109 domain_error, 1110 domain_error_reply, 1111 NULL, // attach_ancillary_data 1112 NULL, // process_ancillary_data 1113 }; 1114 1115 1116 // #pragma mark - test 1117 1118 1119 int32 1120 receiving_thread(void* _data) 1121 { 1122 struct context* context = (struct context*)_data; 1123 struct net_buffer* reorderBuffer = NULL; 1124 1125 while (true) { 1126 status_t status; 1127 do { 1128 status = acquire_sem(context->wait_sem); 1129 } while (status == B_INTERRUPTED); 1130 1131 if (status < B_OK) 1132 break; 1133 1134 while (true) { 1135 context->lock.Lock(); 1136 net_buffer* buffer = (net_buffer*)list_remove_head_item( 1137 &context->list); 1138 context->lock.Unlock(); 1139 1140 if (buffer == NULL) 1141 break; 1142 1143 if (sSimultaneousConnect && context->server && is_syn(buffer)) { 1144 // delay getting the SYN request, and connect as well 1145 sockaddr_in address; 1146 memset(&address, 0, sizeof(address)); 1147 address.sin_family = AF_INET; 1148 address.sin_port = htons(1023); 1149 address.sin_addr.s_addr = htonl(0xc0a80001); 1150 1151 status_t status = socket_connect(gServerSocket, 1152 (struct sockaddr *)&address, sizeof(struct sockaddr)); 1153 if (status < B_OK) 1154 fprintf(stderr, "tcp_tester: simultaneous connect failed: %s\n", strerror(status)); 1155 1156 sSimultaneousConnect = false; 1157 } 1158 if (sSimultaneousClose && !context->server && is_fin(buffer)) { 1159 close_protocol(gClientSocket->first_protocol); 1160 sSimultaneousClose = false; 1161 } 1162 if ((sRandomReorder > 0.0 1163 || sReorderList.find(sPacketNumber) != sReorderList.end()) 1164 && reorderBuffer == NULL 1165 && (1.0 * rand() / RAND_MAX) > sRandomReorder) { 1166 reorderBuffer = buffer; 1167 } else { 1168 if (sDomain.module->receive_data(buffer) < B_OK) 1169 gNetBufferModule.free(buffer); 1170 1171 if (reorderBuffer != NULL) { 1172 if (sDomain.module->receive_data(reorderBuffer) < B_OK) 1173 gNetBufferModule.free(reorderBuffer); 1174 reorderBuffer = NULL; 1175 } 1176 } 1177 } 1178 } 1179 1180 return 0; 1181 } 1182 1183 1184 int32 1185 server_thread(void*) 1186 { 1187 while (true) { 1188 // main accept() loop 1189 net_socket* connectionSocket; 1190 sockaddr_in address; 1191 socklen_t size = sizeof(struct sockaddr_in); 1192 status_t status = socket_accept(gServerSocket, 1193 (struct sockaddr *)&address, &size, &connectionSocket); 1194 if (status < B_OK) { 1195 fprintf(stderr, "SERVER: accepting failed: %s\n", strerror(status)); 1196 break; 1197 } 1198 1199 printf("server: got connection from %08x\n", address.sin_addr.s_addr); 1200 1201 char buffer[1024]; 1202 ssize_t bytesRead; 1203 while ((bytesRead = socket_recv(connectionSocket, buffer, 1204 sizeof(buffer), 0)) > 0) { 1205 printf("server: received %ld bytes\n", bytesRead); 1206 1207 if (sServerActiveClose) { 1208 printf("server: active close\n"); 1209 close_protocol(connectionSocket->first_protocol); 1210 return 0; 1211 } 1212 } 1213 if (bytesRead < 0) 1214 printf("server: receiving failed: %s\n", strerror(bytesRead)); 1215 else 1216 printf("server: peer closed connection.\n"); 1217 1218 snooze(1000000); 1219 close_protocol(connectionSocket->first_protocol); 1220 } 1221 1222 return 0; 1223 } 1224 1225 1226 void 1227 setup_server() 1228 { 1229 sockaddr_in address; 1230 memset(&address, 0, sizeof(address)); 1231 address.sin_len = sizeof(sockaddr_in); 1232 address.sin_family = AF_INET; 1233 address.sin_port = htons(1024); 1234 address.sin_addr.s_addr = INADDR_ANY; 1235 1236 status_t status = socket_bind(gServerSocket, (struct sockaddr*)&address, 1237 sizeof(struct sockaddr)); 1238 if (status < B_OK) { 1239 fprintf(stderr, "tcp_tester: cannot bind server: %s\n", strerror(status)); 1240 exit(1); 1241 } 1242 status = socket_listen(gServerSocket, 40); 1243 if (status < B_OK) { 1244 fprintf(stderr, "tcp_tester: server cannot listen: %s\n", 1245 strerror(status)); 1246 exit(1); 1247 } 1248 1249 thread_id serverThread = spawn_thread(server_thread, "server", 1250 B_NORMAL_PRIORITY, NULL); 1251 if (serverThread < B_OK) { 1252 fprintf(stderr, "tcp_tester: cannot start server: %s\n", 1253 strerror(serverThread)); 1254 exit(1); 1255 } 1256 1257 resume_thread(serverThread); 1258 } 1259 1260 1261 void 1262 setup_context(struct context& context, bool server) 1263 { 1264 list_init(&context.list); 1265 context.route.interface_address = &gInterfaceAddress; 1266 context.route.gateway = (sockaddr *)&context; 1267 // backpointer to the context 1268 context.route.mtu = 1500; 1269 context.server = server; 1270 context.wait_sem = create_sem(0, "receive wait"); 1271 1272 context.thread = spawn_thread(receiving_thread, 1273 server ? "server receiver" : "client receiver", B_NORMAL_PRIORITY, 1274 &context); 1275 resume_thread(context.thread); 1276 } 1277 1278 1279 void 1280 cleanup_context(struct context& context) 1281 { 1282 delete_sem(context.wait_sem); 1283 1284 status_t status; 1285 wait_for_thread(context.thread, &status); 1286 } 1287 1288 1289 // #pragma mark - 1290 1291 1292 static void do_help(int argc, char** argv); 1293 1294 1295 static void 1296 do_connect(int argc, char** argv) 1297 { 1298 sSimultaneousConnect = false; 1299 1300 int port = 1024; 1301 if (argc > 1) { 1302 if (!strcmp(argv[1], "-s")) 1303 sSimultaneousConnect = true; 1304 else if (isdigit(argv[1][0])) 1305 port = atoi(argv[1]); 1306 else { 1307 fprintf(stderr, "usage: connect [-s|<port-number>]\n"); 1308 return; 1309 } 1310 } 1311 1312 if (sSimultaneousConnect) { 1313 // bind to a port first, so the other end can find us 1314 sockaddr_in address; 1315 memset(&address, 0, sizeof(address)); 1316 address.sin_family = AF_INET; 1317 address.sin_port = htons(1023); 1318 address.sin_addr.s_addr = htonl(0xc0a80001); 1319 1320 status_t status = socket_bind(gClientSocket, (struct sockaddr *)&address, 1321 sizeof(struct sockaddr)); 1322 if (status < B_OK) { 1323 fprintf(stderr, "Could not bind to port 1023: %s\n", strerror(status)); 1324 sSimultaneousConnect = false; 1325 return; 1326 } 1327 } 1328 1329 sStartTime = system_time(); 1330 1331 sockaddr_in address; 1332 memset(&address, 0, sizeof(address)); 1333 address.sin_family = AF_INET; 1334 address.sin_port = htons(port); 1335 address.sin_addr.s_addr = htonl(0xc0a80001); 1336 1337 status_t status = socket_connect(gClientSocket, (struct sockaddr *)&address, 1338 sizeof(struct sockaddr)); 1339 if (status < B_OK) 1340 fprintf(stderr, "tcp_tester: could not connect: %s\n", strerror(status)); 1341 } 1342 1343 1344 static void 1345 do_send(int argc, char** argv) 1346 { 1347 size_t size = 1024; 1348 if (argc > 1 && isdigit(argv[1][0])) { 1349 char *unit; 1350 size = strtoul(argv[1], &unit, 0); 1351 if (unit != NULL && unit[0]) { 1352 if (unit[0] == 'k' || unit[0] == 'K') 1353 size *= 1024; 1354 else if (unit[0] == 'm' || unit[0] == 'M') 1355 size *= 1024 * 1024; 1356 else { 1357 fprintf(stderr, "unknown unit specified!\n"); 1358 return; 1359 } 1360 } 1361 } else if (argc > 1) { 1362 fprintf(stderr, "invalid args!\n"); 1363 return; 1364 } 1365 1366 if (size > 4 * 1024 * 1024) { 1367 printf("amount to send will be limited to 4 MB\n"); 1368 size = 4 * 1024 * 1024; 1369 } 1370 1371 char *buffer = (char *)malloc(size); 1372 if (buffer == NULL) { 1373 fprintf(stderr, "not enough memory!\n"); 1374 return; 1375 } 1376 1377 // initialize buffer with some not so random data 1378 for (uint32 i = 0; i < size; i++) { 1379 buffer[i] = (char)(i & 0xff); 1380 } 1381 1382 ssize_t bytesWritten = socket_send(gClientSocket, buffer, size, 0); 1383 if (bytesWritten < B_OK) { 1384 fprintf(stderr, "failed sending buffer: %s\n", strerror(bytesWritten)); 1385 return; 1386 } 1387 } 1388 1389 1390 static void 1391 do_close(int argc, char** argv) 1392 { 1393 sSimultaneousClose = false; 1394 sServerActiveClose = true; 1395 1396 if (argc > 1) { 1397 if (!strcmp(argv[1], "-s")) 1398 sSimultaneousClose = true; 1399 else { 1400 fprintf(stderr, "usage: close [-s]\n"); 1401 return; 1402 } 1403 } 1404 1405 gClientSocket->send.timeout = 0; 1406 1407 char buffer[32767] = {'q'}; 1408 ssize_t bytesWritten = socket_send(gClientSocket, buffer, sizeof(buffer), 0); 1409 if (bytesWritten < B_OK) { 1410 fprintf(stderr, "failed sending buffer: %s\n", strerror(bytesWritten)); 1411 return; 1412 } 1413 } 1414 1415 1416 static void 1417 do_drop(int argc, char** argv) 1418 { 1419 if (argc == 1) { 1420 // show list of dropped packets 1421 if (sRandomDrop > 0.0) 1422 printf("Drop probability is %f\n", sRandomDrop); 1423 1424 printf("Drop pakets:\n"); 1425 1426 std::set<uint32>::iterator iterator = sDropList.begin(); 1427 uint32 count = 0; 1428 for (; iterator != sDropList.end(); iterator++) { 1429 printf("%4lu\n", *iterator); 1430 count++; 1431 } 1432 1433 if (count == 0) 1434 printf("<empty>\n"); 1435 } else if (!strcmp(argv[1], "-f")) { 1436 // flush drop list 1437 sDropList.clear(); 1438 puts("drop list cleared."); 1439 } else if (!strcmp(argv[1], "-r")) { 1440 if (argc < 3) { 1441 fprintf(stderr, "No drop probability specified.\n"); 1442 return; 1443 } 1444 1445 sRandomDrop = atof(argv[2]); 1446 if (sRandomDrop < 0.0) 1447 sRandomDrop = 0; 1448 else if (sRandomDrop > 1.0) 1449 sRandomDrop = 1.0; 1450 } else if (isdigit(argv[1][0])) { 1451 // add to drop list 1452 for (int i = 1; i < argc; i++) { 1453 uint32 packet = strtoul(argv[i], NULL, 0); 1454 if (packet == 0) { 1455 fprintf(stderr, "invalid packet number: %s\n", argv[i]); 1456 break; 1457 } 1458 1459 sDropList.insert(packet); 1460 } 1461 } else { 1462 // print usage 1463 puts("usage: drop <packet-number> [...]\n" 1464 " or: drop -r <probability>\n\n" 1465 " or: drop [-f]\n\n" 1466 "Specifiying -f flushes the drop list, -r sets the probability a packet\n" 1467 "is dropped; if you called drop without any arguments, the current\n" 1468 "drop list is dumped."); 1469 } 1470 } 1471 1472 1473 static void 1474 do_reorder(int argc, char** argv) 1475 { 1476 if (argc == 1) { 1477 // show list of dropped packets 1478 if (sRandomReorder > 0.0) 1479 printf("Reorder probability is %f\n", sRandomReorder); 1480 1481 printf("Reorder packets:\n"); 1482 1483 std::set<uint32>::iterator iterator = sReorderList.begin(); 1484 uint32 count = 0; 1485 for (; iterator != sReorderList.end(); iterator++) { 1486 printf("%4lu\n", *iterator); 1487 count++; 1488 } 1489 1490 if (count == 0) 1491 printf("<empty>\n"); 1492 } else if (!strcmp(argv[1], "-f")) { 1493 // flush reorder list 1494 sReorderList.clear(); 1495 puts("reorder list cleared."); 1496 } else if (!strcmp(argv[1], "-r")) { 1497 if (argc < 3) { 1498 fprintf(stderr, "No reorder probability specified.\n"); 1499 return; 1500 } 1501 1502 sRandomReorder = atof(argv[2]); 1503 if (sRandomReorder < 0.0) 1504 sRandomReorder = 0; 1505 else if (sRandomReorder > 1.0) 1506 sRandomReorder = 1.0; 1507 } else if (isdigit(argv[1][0])) { 1508 // add to reorder list 1509 for (int i = 1; i < argc; i++) { 1510 uint32 packet = strtoul(argv[i], NULL, 0); 1511 if (packet == 0) { 1512 fprintf(stderr, "invalid packet number: %s\n", argv[i]); 1513 break; 1514 } 1515 1516 sReorderList.insert(packet); 1517 } 1518 } else { 1519 // print usage 1520 puts("usage: reorder <packet-number> [...]\n" 1521 " or: reorder -r <probability>\n\n" 1522 " or: reorder [-f]\n\n" 1523 "Specifiying -f flushes the reorder list, -r sets the probability a packet\n" 1524 "is reordered; if you called reorder without any arguments, the current\n" 1525 "reorder list is dumped."); 1526 } 1527 } 1528 1529 1530 static void 1531 do_round_trip_time(int argc, char** argv) 1532 { 1533 if (argc == 1) { 1534 // show current time 1535 printf("Current round trip time: %g ms\n", sRoundTripTime / 1000.0); 1536 } else if (!strcmp(argv[1], "-r")) { 1537 // toggle random time 1538 sRandomRoundTrip = !sRandomRoundTrip; 1539 printf("Round trip time is now %s.\n", sRandomRoundTrip ? "random" : "fixed"); 1540 } else if (!strcmp(argv[1], "-i")) { 1541 // toggle increasing time 1542 sIncreasingRoundTrip = !sIncreasingRoundTrip; 1543 printf("Round trip time is now %s.\n", sIncreasingRoundTrip ? "increasing" : "fixed"); 1544 } else if (isdigit(argv[1][0])) { 1545 // set time 1546 sRoundTripTime = 1000LL * strtoul(argv[1], NULL, 0); 1547 } else { 1548 // print usage 1549 puts("usage: rtt <time in ms>\n" 1550 " or: rtt [-r|-i]\n\n" 1551 "Specifiying -r sets random time, -i causes the times to increase over time;\n" 1552 "witout any arguments, the current time is printed."); 1553 } 1554 } 1555 1556 1557 static void 1558 do_dprintf(int argc, char** argv) 1559 { 1560 if (argc > 1) 1561 gDebugOutputEnabled = !strcmp(argv[1], "on"); 1562 else 1563 gDebugOutputEnabled = !gDebugOutputEnabled; 1564 1565 printf("debug output turned %s.\n", gDebugOutputEnabled ? "on" : "off"); 1566 } 1567 1568 1569 static cmd_entry sBuiltinCommands[] = { 1570 {"connect", do_connect, "Connects the client"}, 1571 {"send", do_send, "Sends data from the client to the server"}, 1572 {"close", do_close, "Performs an active or simultaneous close"}, 1573 {"dprintf", do_dprintf, "Toggles debug output"}, 1574 {"drop", do_drop, "Lets you drop packets during transfer"}, 1575 {"reorder", do_reorder, "Lets you reorder packets during transfer"}, 1576 {"help", do_help, "prints this help text"}, 1577 {"rtt", do_round_trip_time, "Specifies the round trip time"}, 1578 {"quit", NULL, "exits the application"}, 1579 {NULL, NULL, NULL}, 1580 }; 1581 1582 1583 static void 1584 do_help(int argc, char** argv) 1585 { 1586 printf("Available commands:\n"); 1587 1588 for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) { 1589 printf("%8s - %s\n", command->name, command->help); 1590 } 1591 } 1592 1593 1594 // #pragma mark - 1595 1596 1597 int 1598 main(int argc, char** argv) 1599 { 1600 status_t status = init_timers(); 1601 if (status < B_OK) { 1602 fprintf(stderr, "tcp_tester: Could not initialize timers: %s\n", 1603 strerror(status)); 1604 return 1; 1605 } 1606 1607 _add_builtin_module((module_info*)&gNetStackModule); 1608 _add_builtin_module((module_info*)&gNetBufferModule); 1609 _add_builtin_module((module_info*)&gNetSocketModule); 1610 _add_builtin_module((module_info*)&gNetDatalinkModule); 1611 _add_builtin_module(modules[0]); 1612 if (_get_builtin_dependencies() < B_OK) { 1613 fprintf(stderr, "tcp_tester: Could not initialize modules: %s\n", 1614 strerror(status)); 1615 return 1; 1616 } 1617 1618 sockaddr_in interfaceAddress; 1619 interfaceAddress.sin_len = sizeof(sockaddr_in); 1620 interfaceAddress.sin_family = AF_INET; 1621 interfaceAddress.sin_addr.s_addr = htonl(0xc0a80001); 1622 gInterfaceAddress.local = (sockaddr*)&interfaceAddress; 1623 gInterfaceAddress.domain = &sDomain; 1624 1625 status = get_module("network/protocols/tcp/v1", (module_info **)&gTCPModule); 1626 if (status < B_OK) { 1627 fprintf(stderr, "tcp_tester: Could not open TCP module: %s\n", 1628 strerror(status)); 1629 return 1; 1630 } 1631 1632 net_protocol* client = init_protocol(&gClientSocket); 1633 if (client == NULL) 1634 return 1; 1635 net_protocol* server = init_protocol(&gServerSocket); 1636 if (server == NULL) 1637 return 1; 1638 1639 setup_context(sClientContext, false); 1640 setup_context(sServerContext, true); 1641 1642 printf("*** Server: %p (%ld), Client: %p (%ld)\n", server, 1643 sServerContext.thread, client, sClientContext.thread); 1644 1645 setup_server(); 1646 1647 while (true) { 1648 printf("> "); 1649 fflush(stdout); 1650 1651 char line[1024]; 1652 if (fgets(line, sizeof(line), stdin) == NULL) 1653 break; 1654 1655 argc = 0; 1656 argv = build_argv(line, &argc); 1657 if (argv == NULL || argc == 0) 1658 continue; 1659 1660 int length = strlen(argv[0]); 1661 1662 #if 0 1663 char *newLine = strchr(line, '\n'); 1664 if (newLine != NULL) 1665 newLine[0] = '\0'; 1666 #endif 1667 1668 if (!strcmp(argv[0], "quit") 1669 || !strcmp(argv[0], "exit") 1670 || !strcmp(argv[0], "q")) 1671 break; 1672 1673 bool found = false; 1674 1675 for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) { 1676 if (!strncmp(command->name, argv[0], length)) { 1677 command->func(argc, argv); 1678 found = true; 1679 break; 1680 } 1681 } 1682 1683 if (!found) 1684 fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a list of commands.\n", argv[0]); 1685 1686 free(argv); 1687 } 1688 1689 close_protocol(client); 1690 close_protocol(server); 1691 1692 snooze(2000000); 1693 1694 cleanup_context(sClientContext); 1695 cleanup_context(sServerContext); 1696 1697 put_module("network/protocols/tcp/v1"); 1698 uninit_timers(); 1699 return 0; 1700 } 1701