1 /* 2 3 Copyright (C) 1993-2012 Hewlett-Packard Company 4 ALL RIGHTS RESERVED. 5 6 The enclosed software and documentation includes copyrighted works 7 of Hewlett-Packard Co. For as long as you comply with the following 8 limitations, you are hereby authorized to (i) use, reproduce, and 9 modify the software and documentation, and to (ii) distribute the 10 software and documentation, including modifications, for 11 non-commercial purposes only. 12 13 1. The enclosed software and documentation is made available at no 14 charge in order to advance the general development of 15 high-performance networking products. 16 17 2. You may not delete any copyright notices contained in the 18 software or documentation. All hard copies, and copies in 19 source code or object code form, of the software or 20 documentation (including modifications) must contain at least 21 one of the copyright notices. 22 23 3. The enclosed software and documentation has not been subjected 24 to testing and quality control and is not a Hewlett-Packard Co. 25 product. At a future time, Hewlett-Packard Co. may or may not 26 offer a version of the software and documentation as a product. 27 28 4. THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS". 29 HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE, 30 REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR 31 DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL 32 PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR 33 DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES, 34 EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE 35 DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF 36 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 37 38 5. HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY 39 DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 40 (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION, 41 MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION. 42 43 */ 44 45 #include "netperf_version.h" 46 47 char netserver_id[]="\ 48 @(#)netserver.c (c) Copyright 1993-2012 Hewlett-Packard Co. Version 2.6.0"; 49 50 51 #ifdef HAVE_CONFIG_H 52 #include "config.h" 53 #endif 54 55 #if HAVE_STRING_H 56 # if !STDC_HEADERS && HAVE_MEMORY_H 57 # include <memory.h> 58 # endif 59 # include <string.h> 60 #endif 61 62 #if HAVE_STRINGS_H 63 # include <strings.h> 64 #endif 65 66 #if HAVE_LIMITS_H 67 # include <limits.h> 68 #endif 69 70 #if HAVE_SYS_IPC_H 71 #include <sys/ipc.h> 72 #endif 73 74 #if HAVE_SYS_IOCTL_H 75 #include <sys/ioctl.h> 76 #endif 77 78 #if HAVE_SYS_SOCKET_H 79 #include <sys/socket.h> 80 #endif 81 82 #if HAVE_SYS_STAT_H 83 #include <sys/stat.h> 84 #endif 85 86 #if HAVE_NETINET_IN_H 87 #include <netinet/in.h> 88 #endif 89 90 #if HAVE_NETDB_H 91 #include <netdb.h> 92 #endif 93 94 #if HAVE_UNISTD_H 95 #include <unistd.h> 96 #endif 97 98 #if HAVE_STDLIB_H 99 #include <stdlib.h> 100 #endif 101 102 #if HAVE_ERRNO_H 103 #include <errno.h> 104 #endif 105 106 #if HAVE_SIGNAL_H 107 #include <signal.h> 108 /* some OS's have SIGCLD defined as SIGCHLD */ 109 #ifndef SIGCLD 110 #define SIGCLD SIGCHLD 111 #endif /* SIGCLD */ 112 113 #endif 114 115 #if !defined(HAVE_SETSID) 116 #if HAVE_SYS_WAIT_H 117 #include <sys/wait.h> 118 #endif 119 #endif 120 121 #ifdef WIN32 122 #include <time.h> 123 #include <winsock2.h> 124 125 #if HAVE_WS2TCPIP_H 126 #include <ws2tcpip.h> 127 #endif 128 129 #include <windows.h> 130 131 #include "missing\stdint.h" 132 133 #define strdup _strdup 134 #define sleep(x) Sleep((x)*1000) 135 #define netperf_socklen_t socklen_t 136 #endif /* WIN32 */ 137 138 /* unconditional system includes */ 139 140 #include <sys/types.h> 141 #include <stdio.h> 142 #include <fcntl.h> 143 144 /* netperf includes */ 145 #include "netlib.h" 146 #include "nettest_bsd.h" 147 148 #ifdef WANT_UNIX 149 #include "nettest_unix.h" 150 #endif /* WANT_UNIX */ 151 152 #ifdef WANT_DLPI 153 #include "nettest_dlpi.h" 154 #endif /* WANT_DLPI */ 155 156 #ifdef WANT_SCTP 157 #include "nettest_sctp.h" 158 #endif 159 160 #include "netsh.h" 161 162 #ifndef DEBUG_LOG_FILE_DIR 163 #if defined(WIN32) 164 #define DEBUG_LOG_FILE_DIR "" 165 #elif defined(ANDROID) 166 #define DEBUG_LOG_FILE_DIR "/data/local/tmp/" 167 #else 168 #define DEBUG_LOG_FILE_DIR "/tmp/" 169 #endif 170 #endif /* DEBUG_LOG_FILE_DIR */ 171 172 #ifndef DEBUG_LOG_FILE 173 #define DEBUG_LOG_FILE DEBUG_LOG_FILE_DIR"netserver.debug" 174 #endif 175 176 #if !defined(PATH_MAX) 177 #define PATH_MAX MAX_PATH 178 #endif 179 char FileName[PATH_MAX]; 180 181 char listen_port[10]; 182 183 struct listen_elt { 184 SOCKET fd; 185 struct listen_elt *next; 186 }; 187 188 struct listen_elt *listen_list = NULL; 189 190 SOCKET server_control; 191 192 int child; /* are we the child of inetd or a parent netserver? 193 */ 194 int netperf_daemon; 195 int daemon_parent = 0; 196 int not_inetd; 197 int want_daemonize; 198 int spawn_on_accept; 199 int suppress_debug = 0; 200 201 extern char *optarg; 202 extern int optind, opterr; 203 204 /* char *passphrase = NULL; */ 205 206 static void 207 init_netserver_globals() { 208 209 #if defined(__VMS) || defined(VMWARE_UW) 210 spawn_on_accept = 0; 211 want_daemonize = 0; 212 #else 213 spawn_on_accept = 1; 214 #if defined(WIN32) 215 /* we only know how to spawn in WIN32, not daemonize */ 216 want_daemonize = 0; 217 #else 218 want_daemonize = 1; 219 #endif /* WIN32 */ 220 #endif /* __VMS || VMWARE_UW */ 221 222 child = 0; 223 not_inetd = 0; 224 netperf_daemon = 0; 225 } 226 227 void 228 unlink_empty_debug_file() { 229 230 #if !defined(WIN32) 231 struct stat buf; 232 233 if (stat(FileName,&buf)== 0) { 234 235 if (buf.st_size == 0) 236 unlink(FileName); 237 } 238 #endif 239 } 240 241 /* it is important that set_server_sock() be called before this 242 routine as we depend on the control socket being dup()ed out of the 243 way when we go messing about with the streams. */ 244 void 245 open_debug_file() 246 { 247 #if !defined WIN32 248 #define NETPERF_NULL "/dev/null" 249 #else 250 #define NETPERF_NULL "nul" 251 #endif 252 253 FILE *rd_null_fp; 254 255 if (where != NULL) fflush(where); 256 257 snprintf(FileName, 258 sizeof(FileName), 259 #if defined(WIN32) 260 "%s\\%s_%d", 261 getenv("TEMP"), 262 #else 263 "%s_%d", 264 #endif 265 DEBUG_LOG_FILE, 266 getpid()); 267 if ((where = fopen((suppress_debug) ? NETPERF_NULL : FileName, 268 "w")) == NULL) { 269 perror("netserver: debug file"); 270 exit(1); 271 } 272 273 #if !defined(WIN32) 274 275 chmod(FileName,0644); 276 277 /* redirect stdin to "/dev/null" */ 278 rd_null_fp = fopen(NETPERF_NULL,"r"); 279 if (NULL == rd_null_fp) { 280 fprintf(where, 281 "%s: opening of %s failed: %s (errno %d)\n", 282 __FUNCTION__, 283 NETPERF_NULL, 284 strerror(errno), 285 errno); 286 fflush(where); 287 exit(1); 288 } 289 290 if (close(STDIN_FILENO) == -1) { 291 fprintf(where, 292 "%s: close of STDIN_FILENO failed: %s (errno %d)\n", 293 __FUNCTION__, 294 strerror(errno), 295 errno); 296 fflush(where); 297 exit(1); 298 } 299 300 if (dup(fileno(rd_null_fp)) == -1) { 301 fprintf(where, 302 "%s: dup of rd_null_fp to stdin failed: %s (errno %d)\n", 303 __FUNCTION__, 304 strerror(errno), 305 errno); 306 fflush(where); 307 exit(1); 308 } 309 310 /* redirect stdout to "where" */ 311 if (close(STDOUT_FILENO) == -1) { 312 fprintf(where, 313 "%s: close of STDOUT_FILENO failed: %s (errno %d)\n", 314 __FUNCTION__, 315 strerror(errno), 316 errno); 317 fflush(where); 318 exit(1); 319 } 320 321 if (dup(fileno(where)) == -1) { 322 fprintf(where, 323 "%s: dup of where to stdout failed: %s (errno %d)\n", 324 __FUNCTION__, 325 strerror(errno), 326 errno); 327 fflush(where); 328 exit(1); 329 } 330 331 /* redirect stderr to "where" */ 332 if (close(STDERR_FILENO) == -1) { 333 fprintf(where, 334 "%s: close of STDERR_FILENO failed: %s (errno %d)\n", 335 __FUNCTION__, 336 strerror(errno), 337 errno); 338 fflush(where); 339 exit(1); 340 } 341 342 if (dup(fileno(where)) == -1) { 343 fprintf(where, 344 "%s: dup of where to stderr failed: %s (errno %d)\n", 345 __FUNCTION__, 346 strerror(errno), 347 errno); 348 fflush(where); 349 exit(1); 350 } 351 352 #else 353 354 /* Hopefully, by closing stdout & stderr, the subsequent fopen calls 355 will get mapped to the correct std handles. */ 356 fclose(stdout); 357 358 if ((where = fopen(FileName, "w")) == NULL) { 359 perror("netserver: fopen of debug file as new stdout failed!"); 360 exit(1); 361 } 362 363 fclose(stderr); 364 365 if ((where = fopen(FileName, "w")) == NULL) { 366 fprintf(stdout, "fopen of debug file as new stderr failed!\n"); 367 exit(1); 368 } 369 370 #endif 371 372 } 373 374 /* so, either we are a child of inetd in which case server_sock should 375 be stdin, or we are a child of a netserver parent. there will be 376 logic here for all of it, including Windows. it is important that 377 this be called before open_debug_file() */ 378 379 void 380 set_server_sock() { 381 382 if (debug) { 383 fprintf(where, 384 "%s: enter\n", 385 __FUNCTION__); 386 fflush(where); 387 } 388 389 #ifdef WIN32 390 server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE); 391 #elif !defined(__VMS) 392 if (server_sock != INVALID_SOCKET) { 393 fprintf(where,"Yo, Iz ain't invalid!\n"); 394 fflush(where); 395 exit(1); 396 } 397 398 /* we dup this to up the reference count so when we do redirection 399 of the io streams we don't accidentally toast the control 400 connection in the case of our being a child of inetd. */ 401 server_sock = dup(0); 402 403 #else 404 if ((server_sock = 405 socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET) { 406 fprintf(stderr, 407 "%s: failed to grab aux server socket: %s (errno %s)\n", 408 __FUNCTION__, 409 strerror(errno), 410 errno); 411 fflush(stderr); 412 exit(1); 413 } 414 #endif 415 416 } 417 418 419 void 420 create_listens(char hostname[], char port[], int af) { 421 422 struct addrinfo hints; 423 struct addrinfo *local_res; 424 struct addrinfo *local_res_temp; 425 int count, error; 426 int on = 1; 427 SOCKET temp_socket; 428 struct listen_elt *temp_elt; 429 430 if (debug) { 431 fprintf(stderr, 432 "%s: called with host '%s' port '%s' family %s(%d)\n", 433 __FUNCTION__, 434 hostname, 435 port, 436 inet_ftos(af), 437 af); 438 fflush(stderr); 439 } 440 memset(&hints,0,sizeof(hints)); 441 hints.ai_family = af; 442 hints.ai_socktype = SOCK_STREAM; 443 hints.ai_protocol = IPPROTO_TCP; 444 hints.ai_flags = AI_PASSIVE; 445 446 count = 0; 447 do { 448 error = getaddrinfo((char *)hostname, 449 (char *)port, 450 &hints, 451 &local_res); 452 count += 1; 453 if (error == EAI_AGAIN) { 454 if (debug) { 455 fprintf(stderr, 456 "%s: Sleeping on getaddrinfo EAI_AGAIN\n", 457 __FUNCTION__); 458 fflush(stderr); 459 } 460 sleep(1); 461 } 462 } while ((error == EAI_AGAIN) && (count <= 5)); 463 464 if (error) { 465 if (debug) { 466 467 fprintf(stderr, 468 "%s: could not resolve remote '%s' port '%s' af %d\n" 469 "\tgetaddrinfo returned %s (%d)\n", 470 __FUNCTION__, 471 hostname, 472 port, 473 af, 474 gai_strerror(error), 475 error); 476 477 } 478 return; 479 } 480 481 if (debug) { 482 dump_addrinfo(stderr, local_res, hostname, port, af); 483 } 484 485 local_res_temp = local_res; 486 487 while (local_res_temp != NULL) { 488 489 temp_socket = socket(local_res_temp->ai_family,SOCK_STREAM,0); 490 491 if (temp_socket == INVALID_SOCKET) { 492 if (debug) { 493 fprintf(stderr, 494 "%s could not allocate a socket: %s (errno %d)\n", 495 __FUNCTION__, 496 strerror(errno), 497 errno); 498 fflush(stderr); 499 } 500 local_res_temp = local_res_temp->ai_next; 501 continue; 502 } 503 504 /* happiness and joy, keep going */ 505 if (setsockopt(temp_socket, 506 SOL_SOCKET, 507 SO_REUSEADDR, 508 (char *)&on , 509 sizeof(on)) == SOCKET_ERROR) { 510 if (debug) { 511 fprintf(stderr, 512 "%s: warning: could not set SO_REUSEADDR: %s (errno %d)\n", 513 __FUNCTION__, 514 strerror(errno), 515 errno); 516 fflush(stderr); 517 } 518 } 519 /* still happy and joyful */ 520 521 if ((bind(temp_socket, 522 local_res_temp->ai_addr, 523 local_res_temp->ai_addrlen) != SOCKET_ERROR) && 524 (listen(temp_socket,1024) != SOCKET_ERROR)) { 525 526 /* OK, now add to the list */ 527 temp_elt = (struct listen_elt *)malloc(sizeof(struct listen_elt)); 528 if (temp_elt) { 529 temp_elt->fd = temp_socket; 530 if (listen_list) { 531 temp_elt->next = listen_list; 532 } 533 else { 534 temp_elt->next = NULL; 535 } 536 listen_list = temp_elt; 537 } 538 else { 539 fprintf(stderr, 540 "%s: could not malloc a listen_elt\n", 541 __FUNCTION__); 542 fflush(stderr); 543 exit(1); 544 } 545 } 546 else { 547 /* we consider a bind() or listen() failure a transient and try 548 the next address */ 549 if (debug) { 550 fprintf(stderr, 551 "%s: warning: bind or listen call failure: %s (errno %d)\n", 552 __FUNCTION__, 553 strerror(errno), 554 errno); 555 fflush(stderr); 556 } 557 close(temp_socket); 558 } 559 local_res_temp = local_res_temp->ai_next; 560 } 561 562 } 563 564 void 565 setup_listens(char name[], char port[], int af) { 566 567 int do_inet; 568 int no_name = 0; 569 #ifdef AF_INET6 570 int do_inet6; 571 #endif 572 573 if (debug) { 574 fprintf(where, 575 "%s: enter\n", 576 __FUNCTION__); 577 fflush(where); 578 } 579 580 581 if (strcmp(name,"") == 0) { 582 no_name = 1; 583 switch (af) { 584 case AF_UNSPEC: 585 do_inet = 1; 586 #ifdef AF_INET6 587 do_inet6 = 1; 588 #endif 589 break; 590 case AF_INET: 591 do_inet = 1; 592 #ifdef AF_INET6 593 do_inet6 = 0; 594 #endif 595 break; 596 #ifdef AF_INET6 597 case AF_INET6: 598 do_inet = 0; 599 do_inet6 = 1; 600 break; 601 #endif 602 default: 603 do_inet = 1; 604 } 605 /* if we have IPv6, try that one first because it may be a superset */ 606 #ifdef AF_INET6 607 if (do_inet6) 608 create_listens("::0",port,AF_INET6); 609 #endif 610 if (do_inet) 611 create_listens("0.0.0.0",port,AF_INET); 612 } 613 else { 614 create_listens(name,port,af); 615 } 616 617 if (listen_list) { 618 fprintf(stdout, 619 "Starting netserver with host '%s' port '%s' and family %s\n", 620 (no_name) ? "IN(6)ADDR_ANY" : name, 621 port, 622 inet_ftos(af)); 623 fflush(stdout); 624 } 625 else { 626 fprintf(stderr, 627 "Unable to start netserver with '%s' port '%s' and family %s\n", 628 (no_name) ? "IN(6)ADDR_ANY" : name, 629 port, 630 inet_ftos(af)); 631 fflush(stderr); 632 exit(1); 633 } 634 } 635 636 SOCKET 637 set_fdset(struct listen_elt *list, fd_set *fdset) { 638 639 struct listen_elt *temp; 640 SOCKET max = INVALID_SOCKET; 641 642 FD_ZERO(fdset); 643 644 temp = list; 645 646 if (debug) { 647 fprintf(where, 648 "%s: enter list %p fd_set %p\n", 649 __FUNCTION__, 650 list, 651 fdset); 652 fflush(where); 653 } 654 655 while (temp) { 656 if (temp->fd > max) 657 max = temp->fd; 658 659 if (debug) { 660 fprintf(where, 661 "setting %d in fdset\n", 662 temp->fd); 663 fflush(where); 664 } 665 666 FD_SET(temp->fd,fdset); 667 668 temp = temp->next; 669 } 670 671 return max; 672 673 } 674 675 void 676 close_listens(struct listen_elt *list) { 677 struct listen_elt *temp; 678 679 if (debug) { 680 fprintf(where, 681 "%s: enter\n", 682 __FUNCTION__); 683 fflush(where); 684 } 685 686 temp = list; 687 688 while (temp) { 689 close(temp->fd); 690 temp = temp->next; 691 } 692 } 693 694 static int 695 recv_passphrase() { 696 697 /* may need to revisit the timeout. we only respond if there is an 698 error with receiving the passphrase */ 699 if ((recv_request_timed_n(0,20) > 0) && 700 (netperf_request.content.request_type == PASSPHRASE) && 701 (!strcmp(passphrase, 702 (char *)netperf_request.content.test_specific_data))) { 703 /* it was okey dokey */ 704 return 0; 705 } 706 #if defined(SEND_PASSPHRASE_RESPONSE) 707 netperf_response.content.response_type = PASSPHRASE; 708 netperf_response.content.serv_errno = 403; 709 snprintf((char *)netperf_response.content.test_specific_data, 710 sizeof(netperf_response.content.test_specific_data), 711 "Sorry, unable to match with required passphrase\n"); 712 send_response_n(0); 713 #endif 714 fprintf(where, 715 "Unable to match required passphrase. Closing control connection\n"); 716 fflush(where); 717 718 close(server_sock); 719 return -1; 720 } 721 722 /* This routine implements the "main event loop" of the netperf server 723 code. Code above it will have set-up the control connection so it 724 can just merrily go about its business, which is to "schedule" 725 performance tests on the server. */ 726 727 void 728 process_requests() 729 { 730 731 float temp_rate; 732 733 if (debug) { 734 fprintf(where, 735 "%s: enter\n", 736 __FUNCTION__); 737 fflush(where); 738 } 739 740 /* if the netserver was started with a passphrase, look for it in 741 the first request to arrive. if there is no passphrase in the 742 first request we will end-up dumping the control connection. raj 743 2012-01-23 */ 744 745 if ((passphrase != NULL) && (recv_passphrase())) 746 return; 747 748 while (1) { 749 750 if (recv_request() <= 0) { 751 close(server_sock); 752 return; 753 } 754 755 switch (netperf_request.content.request_type) { 756 757 case DEBUG_ON: 758 netperf_response.content.response_type = DEBUG_OK; 759 if (!suppress_debug) { 760 debug++; 761 762 if (debug == 1) { 763 /* we just flipped-on debugging, dump the request because 764 recv_request/recv_request_n will not have dumped it as its 765 dump_request() call is conditional on debug being set. raj 766 2011-07-08 */ 767 dump_request(); 768 } 769 } 770 771 send_response(); 772 break; 773 774 case DEBUG_OFF: 775 if (debug) 776 debug--; 777 netperf_response.content.response_type = DEBUG_OK; 778 send_response(); 779 /* we used to take the trouble to close the debug file, but SAF 780 asked a good question when he asked "Why?" and since I cannot 781 think of a good reason, I have removed the code. raj 782 2011-07-08 */ 783 break; 784 785 case DO_SYSINFO: 786 { 787 netperf_response.content.response_type = SYSINFO_RESPONSE; 788 789 snprintf((char *)netperf_response.content.test_specific_data, 790 sizeof(netperf_response.content.test_specific_data), 791 "%c%s%c%s%c%s%c%s", 792 ',', 793 "Deprecated", 794 ',' 795 , "Deprecated", 796 ',', 797 "Deprecated", 798 ',', 799 "Deprecated"); 800 801 send_response_n(0); 802 break; 803 } 804 805 case CPU_CALIBRATE: 806 netperf_response.content.response_type = CPU_CALIBRATE; 807 temp_rate = calibrate_local_cpu(0.0); 808 bcopy((char *)&temp_rate, 809 (char *)netperf_response.content.test_specific_data, 810 sizeof(temp_rate)); 811 bcopy((char *)&lib_num_loc_cpus, 812 (char *)netperf_response.content.test_specific_data + 813 sizeof(temp_rate), 814 sizeof(lib_num_loc_cpus)); 815 if (debug) { 816 fprintf(where, 817 "netserver: sending CPU information: rate is %g num cpu %d\n", 818 temp_rate, 819 lib_num_loc_cpus); 820 fflush(where); 821 } 822 823 /* we need the cpu_start, cpu_stop in the looper case to kill 824 the child proceses raj 7/95 */ 825 826 #ifdef USE_LOOPER 827 cpu_start(1); 828 cpu_stop(1,&temp_rate); 829 #endif /* USE_LOOPER */ 830 831 send_response(); 832 break; 833 834 case DO_TCP_STREAM: 835 recv_tcp_stream(); 836 break; 837 838 case DO_TCP_MAERTS: 839 recv_tcp_maerts(); 840 break; 841 842 case DO_TCP_RR: 843 recv_tcp_rr(); 844 break; 845 846 case DO_TCP_CRR: 847 recv_tcp_conn_rr(); 848 break; 849 850 case DO_TCP_CC: 851 recv_tcp_cc(); 852 break; 853 854 #ifdef DO_1644 855 case DO_TCP_TRR: 856 recv_tcp_tran_rr(); 857 break; 858 #endif /* DO_1644 */ 859 860 #ifdef DO_NBRR 861 case DO_TCP_NBRR: 862 recv_tcp_nbrr(); 863 break; 864 #endif /* DO_NBRR */ 865 866 case DO_UDP_STREAM: 867 recv_udp_stream(); 868 break; 869 870 case DO_UDP_RR: 871 recv_udp_rr(); 872 break; 873 874 #ifdef WANT_DLPI 875 876 case DO_DLPI_CO_RR: 877 recv_dlpi_co_rr(); 878 break; 879 880 case DO_DLPI_CL_RR: 881 recv_dlpi_cl_rr(); 882 break; 883 884 case DO_DLPI_CO_STREAM: 885 recv_dlpi_co_stream(); 886 break; 887 888 case DO_DLPI_CL_STREAM: 889 recv_dlpi_cl_stream(); 890 break; 891 892 #endif /* WANT_DLPI */ 893 894 #ifdef WANT_UNIX 895 896 case DO_STREAM_STREAM: 897 recv_stream_stream(); 898 break; 899 900 case DO_STREAM_RR: 901 recv_stream_rr(); 902 break; 903 904 case DO_DG_STREAM: 905 recv_dg_stream(); 906 break; 907 908 case DO_DG_RR: 909 recv_dg_rr(); 910 break; 911 912 #endif /* WANT_UNIX */ 913 914 #ifdef WANT_XTI 915 case DO_XTI_TCP_STREAM: 916 recv_xti_tcp_stream(); 917 break; 918 919 case DO_XTI_TCP_RR: 920 recv_xti_tcp_rr(); 921 break; 922 923 case DO_XTI_UDP_STREAM: 924 recv_xti_udp_stream(); 925 break; 926 927 case DO_XTI_UDP_RR: 928 recv_xti_udp_rr(); 929 break; 930 931 #endif /* WANT_XTI */ 932 933 #ifdef WANT_SCTP 934 case DO_SCTP_STREAM: 935 recv_sctp_stream(); 936 break; 937 938 case DO_SCTP_STREAM_MANY: 939 recv_sctp_stream_1toMany(); 940 break; 941 942 case DO_SCTP_RR: 943 recv_sctp_rr(); 944 break; 945 946 case DO_SCTP_RR_MANY: 947 recv_sctp_rr_1toMany(); 948 break; 949 #endif 950 951 #ifdef WANT_SDP 952 case DO_SDP_STREAM: 953 recv_sdp_stream(); 954 break; 955 956 case DO_SDP_MAERTS: 957 recv_sdp_maerts(); 958 break; 959 960 case DO_SDP_RR: 961 recv_sdp_rr(); 962 break; 963 #endif 964 965 #ifdef WANT_OMNI 966 case DO_OMNI: 967 recv_omni(); 968 break; 969 #endif 970 971 case PASSPHRASE: 972 if (debug) { 973 fprintf(where,"Ignoring an unexpected passphrase control message\n"); 974 fflush(where); 975 } 976 break; 977 978 default: 979 fprintf(where,"unknown test number %d\n", 980 netperf_request.content.request_type); 981 fflush(where); 982 netperf_response.content.serv_errno=998; 983 send_response(); 984 break; 985 986 } 987 } 988 } 989 990 /* the routine we call when we are going to spawn/fork/whatnot a child 991 process from the parent netserver daemon. raj 2011-07-08 */ 992 void 993 spawn_child() { 994 995 #if defined(HAVE_FORK) 996 997 if (debug) { 998 fprintf(where, 999 "%s: enter\n", 1000 __FUNCTION__); 1001 fflush(where); 1002 } 1003 1004 1005 /* flush the usual suspects */ 1006 fflush(stdin); 1007 fflush(stdout); 1008 fflush(stderr); 1009 fflush(where); 1010 1011 signal(SIGCLD,SIG_IGN); 1012 1013 switch (fork()) { 1014 case -1: 1015 fprintf(where, 1016 "%s: fork() error %s (errno %d)\n", 1017 __FUNCTION__, 1018 strerror(errno), 1019 errno); 1020 fflush(where); 1021 exit(1); 1022 1023 case 0: 1024 /* we are the child, but not of inetd. we don't know if we are 1025 the child of a daemonized parent or not, so we still need to 1026 worry about the standard file descriptors. raj 2011-07-11 */ 1027 1028 close_listens(listen_list); 1029 open_debug_file(); 1030 1031 child = 1; 1032 netperf_daemon = 0; 1033 process_requests(); 1034 exit(0); 1035 break; 1036 1037 default: 1038 /* we are the parent, not a great deal to do here, but we may 1039 want to reap some children */ 1040 #if !defined(HAVE_SETSID) 1041 /* Only call "waitpid()" if "setsid()" is not used. */ 1042 while(waitpid(-1, NULL, WNOHANG) > 0) { 1043 if (debug) { 1044 fprintf(where, 1045 "%s: reaped a child process\n", 1046 __FUNCTION__); 1047 } 1048 } 1049 #endif 1050 break; 1051 } 1052 1053 #elif defined(WIN32) 1054 1055 BOOL b; 1056 char *cmdline; 1057 int cmdline_length; 1058 int cmd_index; 1059 PROCESS_INFORMATION pi; 1060 STARTUPINFO si; 1061 int i; 1062 1063 if (debug) { 1064 fprintf(where, 1065 "%s: enter\n", 1066 __FUNCTION__); 1067 fflush(where); 1068 } 1069 1070 1071 /* create the cmdline array based on strlen(program) + 80 chars */ 1072 cmdline_length = strlen(program) + 80; 1073 cmdline = malloc(cmdline_length + 1); // +1 for trailing null 1074 1075 memset(&si, 0 , sizeof(STARTUPINFO)); 1076 si.cb = sizeof(STARTUPINFO); 1077 1078 /* Pass the server_sock as stdin for the new process. Hopefully 1079 this will continue to be created with the OBJ_INHERIT 1080 attribute. */ 1081 si.hStdInput = (HANDLE)server_sock; 1082 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 1083 si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 1084 si.dwFlags = STARTF_USESTDHANDLES; 1085 1086 /* Build cmdline for child process */ 1087 strcpy(cmdline, program); 1088 cmd_index = strlen(cmdline); 1089 if (verbosity > 1) { 1090 cmd_index += snprintf(&cmdline[cmd_index], 1091 cmdline_length - cmd_index, 1092 " -v %d", 1093 verbosity); 1094 } 1095 for (i=0; i < debug; i++) { 1096 cmd_index += snprintf(&cmdline[cmd_index], 1097 cmdline_length - cmd_index, 1098 " -d"); 1099 } 1100 cmd_index += snprintf(&cmdline[cmd_index], 1101 cmdline_length - cmd_index, 1102 " -I %x", 1103 (int)(UINT_PTR)server_sock); 1104 1105 /* are these -i settings even necessary? the command line scanning 1106 does not seem to do anything with them */ 1107 cmd_index += snprintf(&cmdline[cmd_index], 1108 cmdline_length - cmd_index, 1109 " -i %x", 1110 (int)(UINT_PTR)server_control); 1111 cmd_index += snprintf(&cmdline[cmd_index], 1112 cmdline_length - cmd_index, 1113 " -i %x", 1114 (int)(UINT_PTR)where); 1115 1116 b = CreateProcess(NULL, /* Application Name */ 1117 cmdline, 1118 NULL, /* Process security attributes */ 1119 NULL, /* Thread security attributes */ 1120 TRUE, /* Inherit handles */ 1121 0, /* Creation flags 1122 PROCESS_QUERY_INFORMATION, */ 1123 NULL, /* Enviornment */ 1124 NULL, /* Current directory */ 1125 &si, /* StartupInfo */ 1126 &pi); 1127 if (!b) 1128 { 1129 perror("CreateProcessfailure: "); 1130 free(cmdline); /* even though we exit :) */ 1131 exit(1); 1132 } 1133 1134 /* We don't need the thread or process handles any more; 1135 let them go away on their own timeframe. */ 1136 1137 CloseHandle(pi.hThread); 1138 CloseHandle(pi.hProcess); 1139 1140 /* the caller/parent will close server_sock */ 1141 1142 free(cmdline); 1143 1144 #else 1145 1146 fprintf(where, 1147 "%s called on platform which cannot spawn children\n", 1148 __FUNCTION__); 1149 fflush(where); 1150 exit(1); 1151 1152 #endif /* HAVE_FORK */ 1153 } 1154 1155 void 1156 accept_connection(SOCKET listen_fd) { 1157 1158 struct sockaddr_storage peeraddr; 1159 netperf_socklen_t peeraddrlen; 1160 #if defined(SO_KEEPALIVE) 1161 int on = 1; 1162 #endif 1163 1164 if (debug) { 1165 fprintf(where, 1166 "%s: enter\n", 1167 __FUNCTION__); 1168 fflush(where); 1169 } 1170 1171 peeraddrlen = sizeof(peeraddr); 1172 1173 /* while server_control is only used by the WIN32 path, but why 1174 bother ifdef'ing it? and besides, do we *really* need knowledge 1175 of server_control in the WIN32 case? do we have to tell the 1176 child about *all* the listen endpoints? raj 2011-07-08 */ 1177 server_control = listen_fd; 1178 1179 if ((server_sock = accept(listen_fd, 1180 (struct sockaddr *)&peeraddr, 1181 &peeraddrlen)) == INVALID_SOCKET) { 1182 fprintf(where, 1183 "%s: accept failure: %s (errno %d)\n", 1184 __FUNCTION__, 1185 strerror(errno), 1186 errno); 1187 fflush(where); 1188 exit(1); 1189 } 1190 1191 #if defined(SO_KEEPALIVE) 1192 /* we are not terribly concerned if this does not work, it is merely 1193 duct tape added to belts and suspenders. raj 2011-07-08 */ 1194 setsockopt(server_sock, 1195 SOL_SOCKET, 1196 SO_KEEPALIVE, 1197 (const char *)&on, 1198 sizeof(on)); 1199 #endif 1200 1201 if (spawn_on_accept) { 1202 spawn_child(); 1203 /* spawn_child() only returns when we are the parent */ 1204 close(server_sock); 1205 } 1206 else { 1207 process_requests(); 1208 } 1209 } 1210 1211 void 1212 accept_connections() { 1213 1214 fd_set read_fds, write_fds, except_fds; 1215 SOCKET high_fd, candidate; 1216 int num_ready; 1217 1218 if (debug) { 1219 fprintf(where, 1220 "%s: enter\n", 1221 __FUNCTION__); 1222 fflush(where); 1223 } 1224 1225 while (1) { 1226 1227 FD_ZERO(&write_fds); 1228 FD_ZERO(&except_fds); 1229 high_fd = set_fdset(listen_list,&read_fds); 1230 1231 #if !defined(WIN32) 1232 num_ready = select(high_fd + 1, 1233 #else 1234 num_ready = select(1, 1235 #endif 1236 &read_fds, 1237 &write_fds, 1238 &except_fds, 1239 NULL); 1240 1241 if (num_ready < 0) { 1242 fprintf(where, 1243 "%s: select failure: %s (errno %d)\n", 1244 __FUNCTION__, 1245 strerror(errno), 1246 errno); 1247 fflush(where); 1248 exit(1); 1249 } 1250 1251 /* try to keep things simple */ 1252 candidate = 0; 1253 while ((num_ready) && (candidate <= high_fd)) { 1254 if (FD_ISSET(candidate,&read_fds)) { 1255 accept_connection(candidate); 1256 FD_CLR(candidate,&read_fds); 1257 num_ready--; 1258 } 1259 else { 1260 candidate++; 1261 } 1262 } 1263 } 1264 } 1265 1266 #ifndef WIN32 1267 #define SERVER_ARGS "DdfhL:n:Np:v:VZ:46" 1268 #else 1269 #define SERVER_ARGS "DdfhL:n:Np:v:VZ:46I:i:" 1270 #endif 1271 void 1272 scan_netserver_args(int argc, char *argv[]) { 1273 1274 int c; 1275 char arg1[BUFSIZ], arg2[BUFSIZ]; 1276 1277 if (debug) { 1278 fprintf(where, 1279 "%s: enter\n", 1280 __FUNCTION__); 1281 fflush(where); 1282 } 1283 1284 while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF){ 1285 switch (c) { 1286 case '?': 1287 case 'h': 1288 print_netserver_usage(); 1289 exit(1); 1290 case 'd': 1291 debug++; 1292 suppress_debug = 0; 1293 break; 1294 case 'D': 1295 /* perhaps one of these days we'll take an argument */ 1296 want_daemonize = 0; 1297 not_inetd = 1; 1298 break; 1299 case 'f': 1300 spawn_on_accept = 0; 1301 not_inetd = 1; 1302 break; 1303 #ifdef WIN32 1304 case 'I': 1305 child = TRUE; 1306 break; 1307 case 'i': 1308 break; 1309 #endif 1310 case 'L': 1311 not_inetd = 1; 1312 break_args_explicit(optarg,arg1,arg2); 1313 if (arg1[0]) { 1314 strncpy(local_host_name,arg1,sizeof(local_host_name)); 1315 } 1316 if (arg2[0]) { 1317 local_address_family = parse_address_family(arg2); 1318 } 1319 break; 1320 case 'n': 1321 shell_num_cpus = atoi(optarg); 1322 if (shell_num_cpus > MAXCPUS) { 1323 fprintf(stderr, 1324 "netserver: This version can only support %d CPUs. Please" 1325 "increase MAXCPUS in netlib.h and recompile.\n", 1326 MAXCPUS); 1327 fflush(stderr); 1328 exit(1); 1329 } 1330 break; 1331 case 'N': 1332 suppress_debug = 1; 1333 debug = 0; 1334 break; 1335 case 'p': 1336 /* we want to open a listen socket at a specified port number */ 1337 strncpy(listen_port,optarg,sizeof(listen_port)); 1338 not_inetd = 1; 1339 break; 1340 case 'Z': 1341 /* only copy as much of the passphrase as could fit in the 1342 test-specific portion of a control message. Windows does not 1343 seem to have a strndup() so just malloc and strncpy it. we 1344 weren't checking the strndup() return so won't bother with 1345 checking malloc(). we will though make certain we only 1346 allocated it once in the event that someone puts -Z on the 1347 command line more than once */ 1348 if (passphrase == NULL) 1349 passphrase = malloc(sizeof(netperf_request.content.test_specific_data)); 1350 strncpy(passphrase, 1351 optarg, 1352 sizeof(netperf_request.content.test_specific_data)); 1353 passphrase[sizeof(netperf_request.content.test_specific_data) - 1] = '\0'; 1354 break; 1355 case '4': 1356 local_address_family = AF_INET; 1357 break; 1358 case '6': 1359 #if defined(AF_INET6) 1360 local_address_family = AF_INET6; 1361 #else 1362 local_address_family = AF_UNSPEC; 1363 #endif 1364 break; 1365 case 'v': 1366 /* say how much to say */ 1367 verbosity = atoi(optarg); 1368 break; 1369 case 'V': 1370 printf("Netperf version %s\n",NETPERF_VERSION); 1371 exit(0); 1372 break; 1373 1374 } 1375 } 1376 } 1377 1378 void 1379 daemonize() { 1380 #if defined(HAVE_FORK) 1381 1382 if (debug) { 1383 fprintf(where, 1384 "%s: enter\n", 1385 __FUNCTION__); 1386 fflush(where); 1387 } 1388 1389 /* flush the usual suspects */ 1390 fflush(stdin); 1391 fflush(stdout); 1392 fflush(stderr); 1393 1394 switch (fork()) { 1395 case -1: 1396 fprintf(stderr, 1397 "%s: fork() error %s (errno %d)\n", 1398 __FUNCTION__, 1399 strerror(errno), 1400 errno); 1401 fflush(stderr); 1402 exit(1); 1403 case 0: 1404 1405 /* perhaps belt and suspenders, but if we dump core, perhaps 1406 better to do so here. we won't worry about the call being 1407 successful though. raj 2011-07-08 */ 1408 chdir(DEBUG_LOG_FILE_DIR); 1409 1410 /* we are the child. we should get a new "where" to match our new 1411 pid */ 1412 1413 open_debug_file(); 1414 1415 #ifdef HAVE_SETSID 1416 setsid(); 1417 #else 1418 setpgrp(); 1419 #endif /* HAVE_SETSID */ 1420 1421 signal(SIGCLD, SIG_IGN); 1422 1423 /* ok, we can start accepting control connections now */ 1424 accept_connections(); 1425 1426 default: 1427 /* we are the parent, nothing to do but exit? */ 1428 exit(0); 1429 } 1430 1431 #else 1432 fprintf(where, 1433 "%s called on platform which cannot daemonize\n", 1434 __FUNCTION__); 1435 fflush(where); 1436 exit(1); 1437 #endif /* HAVE_FORK */ 1438 } 1439 1440 static void 1441 check_if_inetd() { 1442 1443 if (debug) { 1444 fprintf(where, 1445 "%s: enter\n", 1446 __FUNCTION__); 1447 fflush(where); 1448 } 1449 1450 if (not_inetd) { 1451 return; 1452 } 1453 else { 1454 #if !defined(WIN32) && !defined(__VMS) 1455 struct sockaddr_storage name; 1456 netperf_socklen_t namelen; 1457 1458 namelen = sizeof(name); 1459 if (getsockname(0, 1460 (struct sockaddr *)&name, 1461 &namelen) == SOCKET_ERROR) { 1462 not_inetd = 1; 1463 } 1464 else { 1465 not_inetd = 0; 1466 child = 1; 1467 } 1468 #endif 1469 } 1470 } 1471 1472 /* OK, so how does all this work you ask? Well, we are in a maze of 1473 twisty options, all different. Netserver can be invoked as a child 1474 of inetd or the VMS auxiliary server process, or a parent netserver 1475 process. In those cases, we could/should follow the "child" 1476 path. However, there are really two "child" paths through the 1477 netserver code. 1478 1479 When this netserver is a child of a parent netserver in the 1480 case of *nix, the child process will be created by a 1481 spawn_child_process() in accept_connections() and will not hit the 1482 "child" path here in main(). 1483 1484 When this netserver is a child of a parent netserver in the case of 1485 windows, the child process will have been spawned via a 1486 Create_Process() call in spawn_child_process() in 1487 accept_connections, but will flow through here again. We rely on 1488 the scan_netserver_args() call to have noticed the magic option 1489 that tells us we are a child process. 1490 1491 When this netserver is launched from the command line we will first 1492 set-up the listen endpoint(s) for the controll connection. At that 1493 point we decide if we want to and can become our own daemon, or 1494 stay attached to the "terminal." When this happens under *nix, we 1495 will again take a fork() path via daemonize() and will not come 1496 back through main(). If we ever learn how to become our own daemon 1497 under Windows, we will undoubtedly take a Create_Process() path 1498 again and will come through main() once again - that is what the 1499 "daemon" case here is all about. 1500 1501 It is hoped that this is all much clearer than the old spaghetti 1502 code that netserver had become. raj 2011-07-11 */ 1503 1504 1505 int _cdecl 1506 main(int argc, char *argv[]) { 1507 1508 #ifdef WIN32 1509 WSADATA wsa_data ; 1510 1511 /* Initialize the winsock lib do we still want version 2.2? */ 1512 if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){ 1513 printf("WSAStartup() failed : %lu\n", GetLastError()) ; 1514 return -1 ; 1515 } 1516 #endif /* WIN32 */ 1517 1518 /* Save away the program name */ 1519 program = (char *)malloc(strlen(argv[0]) + 1); 1520 if (program == NULL) { 1521 printf("malloc for program name failed!\n"); 1522 return -1 ; 1523 } 1524 strcpy(program, argv[0]); 1525 1526 init_netserver_globals(); 1527 1528 netlib_init(); 1529 1530 strncpy(local_host_name,"",sizeof(local_host_name)); 1531 local_address_family = AF_UNSPEC; 1532 strncpy(listen_port,TEST_PORT,sizeof(listen_port)); 1533 1534 scan_netserver_args(argc, argv); 1535 1536 check_if_inetd(); 1537 1538 if (child) { 1539 /* we are the child of either an inetd or parent netserver via 1540 spawning (Windows) rather than fork()ing. if we were fork()ed 1541 we would not be coming through this way. set_server_sock() must 1542 be called before open_debug_file() or there is a chance that 1543 we'll toast the descriptor when we do not wish it. */ 1544 set_server_sock(); 1545 open_debug_file(); 1546 process_requests(); 1547 } 1548 else if (daemon_parent) { 1549 /* we are the parent daemonized netserver 1550 process. accept_connections() will decide if we want to spawn a 1551 child process */ 1552 accept_connections(); 1553 } 1554 else { 1555 /* we are the top netserver process, so we have to create the 1556 listen endpoint(s) and decide if we want to daemonize */ 1557 setup_listens(local_host_name,listen_port,local_address_family); 1558 if (want_daemonize) { 1559 daemonize(); 1560 } 1561 accept_connections(); 1562 } 1563 1564 unlink_empty_debug_file(); 1565 1566 #ifdef WIN32 1567 WSACleanup(); 1568 #endif 1569 1570 return 0; 1571 1572 } 1573