1 /* 2 3 Copyright (C) 1993-2007 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-2007 Hewlett-Packard Co. Version 2.4.3"; 49 50 /***********************************************************************/ 51 /* */ 52 /* netserver.c */ 53 /* */ 54 /* This is the server side code for the netperf test package. It */ 55 /* will operate either stand-alone, or as a child of inetd. In this */ 56 /* way, we insure that it can be installed on systems with or without */ 57 /* root permissions (editing inetd.conf). Essentially, this code is */ 58 /* the analog to the netsh.c code. */ 59 /* */ 60 /***********************************************************************/ 61 62 63 /************************************************************************/ 64 /* */ 65 /* Global include files */ 66 /* */ 67 /************************************************************************/ 68 #ifdef HAVE_CONFIG_H 69 #include "config.h" 70 #endif 71 72 #if HAVE_STRING_H 73 # if !STDC_HEADERS && HAVE_MEMORY_H 74 # include <memory.h> 75 # endif 76 # include <string.h> 77 #endif 78 #if HAVE_STRINGS_H 79 # include <strings.h> 80 #endif 81 #if HAVE_LIMITS_H 82 # include <limits.h> 83 #endif 84 #include <sys/types.h> 85 #include <stdio.h> 86 #ifndef WIN32 87 #include <errno.h> 88 #include <signal.h> 89 #endif 90 #if !defined(WIN32) && !defined(__VMS) 91 #include <sys/ipc.h> 92 #endif /* !defined(WIN32) && !defined(__VMS) */ 93 #include <fcntl.h> 94 #ifdef WIN32 95 #include <time.h> 96 #include <winsock2.h> 97 #define netperf_socklen_t socklen_t 98 /* we need to find some other way to decide to include ws2 */ 99 /* if you are trying to compile on Windows 2000 or NT 4 you will */ 100 /* probably have to define DONT_IPV6 */ 101 #ifndef DONT_IPV6 102 #include <ws2tcpip.h> 103 #endif /* DONT_IPV6 */ 104 #include <windows.h> 105 #define sleep(x) Sleep((x)*1000) 106 #else 107 #ifndef MPE 108 #include <sys/time.h> 109 #endif /* MPE */ 110 #include <sys/ioctl.h> 111 #include <sys/socket.h> 112 #include <sys/stat.h> 113 #include <netinet/in.h> 114 #include <netdb.h> 115 #include <unistd.h> 116 #ifndef DONT_WAIT 117 #include <sys/wait.h> 118 #endif /* DONT_WAIT */ 119 #endif /* WIN32 */ 120 #include <stdlib.h> 121 #ifdef __VMS 122 #include <tcpip$inetdef.h> 123 #include <unixio.h> 124 #endif /* __VMS */ 125 #include "netlib.h" 126 #include "nettest_bsd.h" 127 128 #ifdef WANT_UNIX 129 #include "nettest_unix.h" 130 #endif /* WANT_UNIX */ 131 132 #ifdef WANT_DLPI 133 #include "nettest_dlpi.h" 134 #endif /* WANT_DLPI */ 135 136 #ifdef WANT_SCTP 137 #include "nettest_sctp.h" 138 #endif 139 140 #include "netsh.h" 141 142 #ifndef DEBUG_LOG_FILE 143 #ifndef WIN32 144 #define DEBUG_LOG_FILE "/tmp/netperf.debug" 145 #else 146 #define DEBUG_LOG_FILE "c:\\temp\\netperf.debug" 147 #endif /* WIN32 */ 148 #endif /* DEBUG_LOG_FILE */ 149 150 /* some global variables */ 151 152 FILE *afp; 153 char listen_port[10]; 154 extern char *optarg; 155 extern int optind, opterr; 156 157 #ifndef WIN32 158 #define SERVER_ARGS "dL:n:p:v:V46" 159 #else 160 #define SERVER_ARGS "dL:n:p:v:V46I:i:" 161 #endif 162 163 /* perhaps one day we will use this as part of only opening a debug 164 log file if debug is set, of course we have to be wary of the base 165 use of "where" and so probably always need "where" pointing 166 "somewhere" or other. */ 167 void 168 open_debug_file() 169 { 170 #ifndef WIN32 171 #ifndef PATH_MAX 172 #define PATH_MAX MAX_PATH 173 #endif 174 char FileName[PATH_MAX]; /* for opening the debug log file */ 175 strcpy(FileName, DEBUG_LOG_FILE); 176 177 if (where != NULL) fflush(where); 178 179 snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); 180 if ((where = fopen(FileName, "w")) == NULL) { 181 perror("netserver: debug file"); 182 exit(1); 183 } 184 185 chmod(FileName,0644); 186 #endif 187 188 } 189 /* This routine implements the "main event loop" of the netperf */ 190 /* server code. Code above it will have set-up the control connection */ 191 /* so it can just merrily go about its business, which is to */ 192 /* "schedule" performance tests on the server. */ 193 194 void 195 process_requests() 196 { 197 198 float temp_rate; 199 200 if (debug) open_debug_file(); 201 202 203 while (1) { 204 recv_request(); 205 206 switch (netperf_request.content.request_type) { 207 208 case DEBUG_ON: 209 netperf_response.content.response_type = DEBUG_OK; 210 /* dump_request already present in recv_request; redundant? */ 211 if (!debug) { 212 debug++; 213 open_debug_file(); 214 dump_request(); 215 } 216 send_response(); 217 break; 218 219 case DEBUG_OFF: 220 if (debug) 221 debug--; 222 netperf_response.content.response_type = DEBUG_OK; 223 send_response(); 224 /* +SAF why??? */ 225 if (!debug) 226 { 227 fclose(where); 228 #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) 229 /* For Unix: reopen the debug write file descriptor to "/dev/null" */ 230 /* and redirect stdout to it. */ 231 fflush (stdout); 232 where = fopen ("/dev/null", "w"); 233 if (where == NULL) 234 { 235 perror ("netserver: reopening debug fp for writing: /dev/null"); 236 exit (1); 237 } 238 if (close (STDOUT_FILENO) == -1) 239 { 240 perror ("netserver: closing stdout file descriptor"); 241 exit (1); 242 } 243 if (dup (fileno (where)) == -1) 244 { 245 perror ("netserver: duplicate /dev/null write file descr. to stdout"); 246 exit (1); 247 } 248 #endif /* !WIN32 !MPE !__VMS */ 249 } 250 break; 251 252 case CPU_CALIBRATE: 253 netperf_response.content.response_type = CPU_CALIBRATE; 254 temp_rate = calibrate_local_cpu(0.0); 255 bcopy((char *)&temp_rate, 256 (char *)netperf_response.content.test_specific_data, 257 sizeof(temp_rate)); 258 bcopy((char *)&lib_num_loc_cpus, 259 (char *)netperf_response.content.test_specific_data + sizeof(temp_rate), 260 sizeof(lib_num_loc_cpus)); 261 if (debug) { 262 fprintf(where,"netserver: sending CPU information:"); 263 fprintf(where,"rate is %g num cpu %d\n",temp_rate,lib_num_loc_cpus); 264 fflush(where); 265 } 266 267 /* we need the cpu_start, cpu_stop in the looper case to kill the */ 268 /* child proceses raj 7/95 */ 269 270 #ifdef USE_LOOPER 271 cpu_start(1); 272 cpu_stop(1,&temp_rate); 273 #endif /* USE_LOOPER */ 274 275 send_response(); 276 break; 277 278 case DO_TCP_STREAM: 279 recv_tcp_stream(); 280 break; 281 282 case DO_TCP_MAERTS: 283 recv_tcp_maerts(); 284 break; 285 286 case DO_TCP_RR: 287 recv_tcp_rr(); 288 break; 289 290 case DO_TCP_CRR: 291 recv_tcp_conn_rr(); 292 break; 293 294 case DO_TCP_CC: 295 recv_tcp_cc(); 296 break; 297 298 #ifdef DO_1644 299 case DO_TCP_TRR: 300 recv_tcp_tran_rr(); 301 break; 302 #endif /* DO_1644 */ 303 304 #ifdef DO_NBRR 305 case DO_TCP_NBRR: 306 recv_tcp_nbrr(); 307 break; 308 #endif /* DO_NBRR */ 309 310 case DO_UDP_STREAM: 311 recv_udp_stream(); 312 break; 313 314 case DO_UDP_RR: 315 recv_udp_rr(); 316 break; 317 318 #ifdef WANT_DLPI 319 320 case DO_DLPI_CO_RR: 321 recv_dlpi_co_rr(); 322 break; 323 324 case DO_DLPI_CL_RR: 325 recv_dlpi_cl_rr(); 326 break; 327 328 case DO_DLPI_CO_STREAM: 329 recv_dlpi_co_stream(); 330 break; 331 332 case DO_DLPI_CL_STREAM: 333 recv_dlpi_cl_stream(); 334 break; 335 336 #endif /* WANT_DLPI */ 337 338 #ifdef WANT_UNIX 339 340 case DO_STREAM_STREAM: 341 recv_stream_stream(); 342 break; 343 344 case DO_STREAM_RR: 345 recv_stream_rr(); 346 break; 347 348 case DO_DG_STREAM: 349 recv_dg_stream(); 350 break; 351 352 case DO_DG_RR: 353 recv_dg_rr(); 354 break; 355 356 #endif /* WANT_UNIX */ 357 358 #ifdef WANT_XTI 359 case DO_XTI_TCP_STREAM: 360 recv_xti_tcp_stream(); 361 break; 362 363 case DO_XTI_TCP_RR: 364 recv_xti_tcp_rr(); 365 break; 366 367 case DO_XTI_UDP_STREAM: 368 recv_xti_udp_stream(); 369 break; 370 371 case DO_XTI_UDP_RR: 372 recv_xti_udp_rr(); 373 break; 374 375 #endif /* WANT_XTI */ 376 377 #ifdef WANT_SCTP 378 case DO_SCTP_STREAM: 379 recv_sctp_stream(); 380 break; 381 382 case DO_SCTP_STREAM_MANY: 383 recv_sctp_stream_1toMany(); 384 break; 385 386 case DO_SCTP_RR: 387 recv_sctp_rr(); 388 break; 389 390 case DO_SCTP_RR_MANY: 391 recv_sctp_rr_1toMany(); 392 break; 393 #endif 394 395 #ifdef WANT_SDP 396 case DO_SDP_STREAM: 397 recv_sdp_stream(); 398 break; 399 400 case DO_SDP_MAERTS: 401 recv_sdp_maerts(); 402 break; 403 404 case DO_SDP_RR: 405 recv_sdp_rr(); 406 break; 407 #endif 408 409 default: 410 fprintf(where,"unknown test number %d\n", 411 netperf_request.content.request_type); 412 fflush(where); 413 netperf_response.content.serv_errno=998; 414 send_response(); 415 break; 416 417 } 418 } 419 } 420 421 /* 422 set_up_server() 423 424 set-up the server listen socket. we only call this routine if the 425 user has specified a port number on the command line or we believe we 426 are not a child of inetd or its platform-specific equivalent */ 427 428 /*KC*/ 429 430 void 431 set_up_server(char hostname[], char port[], int af) 432 { 433 434 struct addrinfo hints; 435 struct addrinfo *local_res; 436 struct addrinfo *local_res_temp; 437 438 struct sockaddr_storage peeraddr; 439 netperf_socklen_t peeraddr_len = sizeof(peeraddr); 440 441 SOCKET server_control; 442 int on=1; 443 int count; 444 int error; 445 int not_listening; 446 447 #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) 448 FILE *rd_null_fp; /* Used to redirect from "/dev/null". */ 449 FILE *wr_null_fp; /* Used to redirect to "/dev/null". */ 450 #endif /* !WIN32 !MPE !__VMS */ 451 452 if (debug) { 453 fprintf(stderr, 454 "set_up_server called with host '%s' port '%s' remfam %d\n", 455 hostname, 456 port, 457 af); 458 fflush(stderr); 459 } 460 461 memset(&hints,0,sizeof(hints)); 462 hints.ai_family = af; 463 hints.ai_socktype = SOCK_STREAM; 464 hints.ai_protocol = IPPROTO_TCP; 465 hints.ai_flags = AI_PASSIVE; 466 467 count = 0; 468 do { 469 error = getaddrinfo((char *)hostname, 470 (char *)port, 471 &hints, 472 &local_res); 473 count += 1; 474 if (error == EAI_AGAIN) { 475 if (debug) { 476 fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n"); 477 fflush(stderr); 478 } 479 sleep(1); 480 } 481 } while ((error == EAI_AGAIN) && (count <= 5)); 482 483 if (error) { 484 fprintf(stderr, 485 "set_up_server: could not resolve remote '%s' port '%s' af %d", 486 hostname, 487 port, 488 af); 489 fprintf(stderr,"\n\tgetaddrinfo returned %d %s\n", 490 error, 491 gai_strerror(error)); 492 exit(-1); 493 } 494 495 if (debug) { 496 dump_addrinfo(stderr, local_res, hostname, port, af); 497 } 498 499 not_listening = 1; 500 local_res_temp = local_res; 501 502 while((local_res_temp != NULL) && (not_listening)) { 503 504 fprintf(stderr, 505 "Starting netserver at port %s\n", 506 port); 507 508 server_control = socket(local_res_temp->ai_family,SOCK_STREAM,0); 509 510 if (server_control == INVALID_SOCKET) { 511 perror("set_up_server could not allocate a socket"); 512 exit(-1); 513 } 514 515 /* happiness and joy, keep going */ 516 if (setsockopt(server_control, 517 SOL_SOCKET, 518 SO_REUSEADDR, 519 (char *)&on , 520 sizeof(on)) == SOCKET_ERROR) { 521 if (debug) { 522 perror("warning: set_up_server could not set SO_REUSEADDR"); 523 } 524 } 525 /* still happy and joyful */ 526 527 if ((bind (server_control, 528 local_res_temp->ai_addr, 529 local_res_temp->ai_addrlen) != SOCKET_ERROR) && 530 (listen (server_control,5) != SOCKET_ERROR)) { 531 not_listening = 0; 532 break; 533 } 534 else { 535 /* we consider a bind() or listen() failure a transient and try 536 the next address */ 537 if (debug) { 538 perror("warning: set_up_server failed a bind or listen call\n"); 539 } 540 local_res_temp = local_res_temp->ai_next; 541 continue; 542 } 543 } 544 545 if (not_listening) { 546 fprintf(stderr, 547 "set_up_server could not establish a listen endpoint for %s port %s with family %s\n", 548 host_name, 549 port, 550 inet_ftos(af)); 551 fflush(stderr); 552 exit(-1); 553 } 554 else { 555 printf("Starting netserver at hostname %s port %s and family %s\n", 556 hostname, 557 port, 558 inet_ftos(af)); 559 } 560 561 /* 562 setpgrp(); 563 */ 564 565 #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) 566 /* Flush the standard I/O file descriptors before forking. */ 567 fflush (stdin); 568 fflush (stdout); 569 fflush (stderr); 570 switch (fork()) 571 { 572 case -1: 573 perror("netperf server error"); 574 exit(1); 575 576 case 0: 577 /* Redirect stdin from "/dev/null". */ 578 rd_null_fp = fopen ("/dev/null", "r"); 579 if (rd_null_fp == NULL) 580 { 581 perror ("netserver: opening for reading: /dev/null"); 582 exit (1); 583 } 584 if (close (STDIN_FILENO) == -1) 585 { 586 perror ("netserver: closing stdin file descriptor"); 587 exit (1); 588 } 589 if (dup (fileno (rd_null_fp)) == -1) 590 { 591 perror ("netserver: duplicate /dev/null read file descr. to stdin"); 592 exit (1); 593 } 594 595 /* Redirect stdout to the debug write file descriptor. */ 596 if (close (STDOUT_FILENO) == -1) 597 { 598 perror ("netserver: closing stdout file descriptor"); 599 exit (1); 600 } 601 if (dup (fileno (where)) == -1) 602 { 603 perror ("netserver: duplicate the debug write file descr. to stdout"); 604 exit (1); 605 } 606 607 /* Redirect stderr to "/dev/null". */ 608 wr_null_fp = fopen ("/dev/null", "w"); 609 if (wr_null_fp == NULL) 610 { 611 perror ("netserver: opening for writing: /dev/null"); 612 exit (1); 613 } 614 if (close (STDERR_FILENO) == -1) 615 { 616 perror ("netserver: closing stderr file descriptor"); 617 exit (1); 618 } 619 if (dup (fileno (wr_null_fp)) == -1) 620 { 621 perror ("netserver: dupicate /dev/null write file descr. to stderr"); 622 exit (1); 623 } 624 625 #ifndef NO_SETSID 626 setsid(); 627 #else 628 setpgrp(); 629 #endif /* NO_SETSID */ 630 631 /* some OS's have SIGCLD defined as SIGCHLD */ 632 #ifndef SIGCLD 633 #define SIGCLD SIGCHLD 634 #endif /* SIGCLD */ 635 636 signal(SIGCLD, SIG_IGN); 637 638 #endif /* !WIN32 !MPE !__VMS */ 639 640 for (;;) 641 { 642 if ((server_sock=accept(server_control, 643 (struct sockaddr *)&peeraddr, 644 &peeraddr_len)) == INVALID_SOCKET) 645 { 646 printf("server_control: accept failed errno %d\n",errno); 647 exit(1); 648 } 649 #if defined(MPE) || defined(__VMS) 650 /* 651 * Since we cannot fork this process , we cant fire any threads 652 * as they all share the same global data . So we better allow 653 * one request at at time 654 */ 655 process_requests() ; 656 #elif WIN32 657 { 658 BOOL b; 659 char cmdline[80]; 660 PROCESS_INFORMATION pi; 661 STARTUPINFO si; 662 int i; 663 664 memset(&si, 0 , sizeof(STARTUPINFO)); 665 si.cb = sizeof(STARTUPINFO); 666 667 /* Pass the server_sock as stdin for the new process. */ 668 /* Hopefully this will continue to be created with the OBJ_INHERIT attribute. */ 669 si.hStdInput = (HANDLE)server_sock; 670 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 671 si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 672 si.dwFlags = STARTF_USESTDHANDLES; 673 674 /* Build cmdline for child process */ 675 strcpy(cmdline, program); 676 if (verbosity > 1) { 677 snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -v %d", verbosity); 678 } 679 for (i=0; i < debug; i++) { 680 snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -d"); 681 } 682 snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -I %x", (int)(UINT_PTR)server_sock); 683 snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)server_control); 684 snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)where); 685 686 b = CreateProcess(NULL, /* Application Name */ 687 cmdline, 688 NULL, /* Process security attributes */ 689 NULL, /* Thread security attributes */ 690 TRUE, /* Inherit handles */ 691 0, /* Creation flags PROCESS_QUERY_INFORMATION, */ 692 NULL, /* Enviornment */ 693 NULL, /* Current directory */ 694 &si, /* StartupInfo */ 695 &pi); 696 if (!b) 697 { 698 perror("CreateProcessfailure: "); 699 exit(1); 700 } 701 702 /* We don't need the thread or process handles any more; let them */ 703 /* go away on their own timeframe. */ 704 705 CloseHandle(pi.hThread); 706 CloseHandle(pi.hProcess); 707 708 /* And close the server_sock since the child will own it. */ 709 710 close(server_sock); 711 } 712 #else 713 signal(SIGCLD, SIG_IGN); 714 715 switch (fork()) 716 { 717 case -1: 718 /* something went wrong */ 719 exit(1); 720 case 0: 721 /* we are the child process */ 722 close(server_control); 723 process_requests(); 724 exit(0); 725 break; 726 default: 727 /* we are the parent process */ 728 close(server_sock); 729 /* we should try to "reap" some of our children. on some */ 730 /* systems they are being left as defunct processes. we */ 731 /* will call waitpid, looking for any child process, */ 732 /* with the WNOHANG feature. when waitpid return a zero, */ 733 /* we have reaped all the children there are to reap at */ 734 /* the moment, so it is time to move on. raj 12/94 */ 735 #ifndef DONT_WAIT 736 #ifdef NO_SETSID 737 /* Only call "waitpid()" if "setsid()" is not used. */ 738 while(waitpid(-1, NULL, WNOHANG) > 0) { } 739 #endif /* NO_SETSID */ 740 #endif /* DONT_WAIT */ 741 break; 742 } 743 #endif /* !WIN32 !MPE !__VMS */ 744 } /*for*/ 745 #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) 746 break; /*case 0*/ 747 748 default: 749 exit (0); 750 751 } 752 #endif /* !WIN32 !MPE !__VMS */ 753 } 754 755 #ifdef WIN32 756 757 /* With Win2003, WinNT's POSIX subsystem is gone and hence so is */ 758 /* fork. */ 759 760 /* But hopefully the kernel support will continue to exist for some */ 761 /* time. */ 762 763 /* We are not counting on the child address space copy_on_write */ 764 /* support, since it isn't exposed except through the NT native APIs */ 765 /* (which is not public). */ 766 767 /* We will try to use the InheritHandles flag in CreateProcess. It */ 768 /* is in the public API, though it is documented as "must be FALSE". */ 769 770 /* So where we would have forked, we will now create a new process. */ 771 /* I have added a set of command line switches to specify a list of */ 772 /* handles that the child should close since they shouldn't have */ 773 /* been inherited ("-i#"), and a single switch to specify the handle */ 774 /* for the server_sock ("I#"). */ 775 776 /* A better alternative would be to re-write NetPerf to be */ 777 /* multi-threaded; i.e., move all of the various NetPerf global */ 778 /* variables in to thread specific structures. But this is a bigger */ 779 /* effort than I want to tackle at this time. (And I doubt that the */ 780 /* HP-UX author sees value in this effort). */ 781 782 #endif 783 784 int _cdecl 785 main(int argc, char *argv[]) 786 { 787 788 int c; 789 int not_inetd = 0; 790 #ifdef WIN32 791 BOOL child = FALSE; 792 #endif 793 char arg1[BUFSIZ], arg2[BUFSIZ]; 794 #ifndef PATH_MAX 795 #define PATH_MAX MAX_PATH 796 #endif 797 char FileName[PATH_MAX]; /* for opening the debug log file */ 798 799 struct sockaddr name; 800 netperf_socklen_t namelen = sizeof(name); 801 802 803 #ifdef WIN32 804 WSADATA wsa_data ; 805 806 /* Initialize the winsock lib ( version 2.2 ) */ 807 if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){ 808 printf("WSAStartup() failed : %d\n", GetLastError()) ; 809 return 1 ; 810 } 811 #endif /* WIN32 */ 812 813 /* Save away the program name */ 814 program = (char *)malloc(strlen(argv[0]) + 1); 815 if (program == NULL) { 816 printf("malloc(%d) failed!\n", strlen(argv[0]) + 1); 817 return 1 ; 818 } 819 strcpy(program, argv[0]); 820 821 netlib_init(); 822 823 /* Scan the command line to see if we are supposed to set-up our own */ 824 /* listen socket instead of relying on inetd. */ 825 826 /* first set a copy of initial values */ 827 strncpy(local_host_name,"0.0.0.0",sizeof(local_host_name)); 828 local_address_family = AF_UNSPEC; 829 strncpy(listen_port,TEST_PORT,sizeof(listen_port)); 830 831 while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF) { 832 switch (c) { 833 case '?': 834 case 'h': 835 print_netserver_usage(); 836 exit(1); 837 case 'd': 838 /* we want to set the debug file name sometime */ 839 debug++; 840 break; 841 case 'L': 842 not_inetd = 1; 843 break_args_explicit(optarg,arg1,arg2); 844 if (arg1[0]) { 845 strncpy(local_host_name,arg1,sizeof(local_host_name)); 846 } 847 if (arg2[0]) { 848 local_address_family = parse_address_family(arg2); 849 /* if only the address family was set, we may need to set the 850 local_host_name accordingly. since our defaults are IPv4 851 this should only be necessary if we have IPv6 support raj 852 2005-02-07 */ 853 #if defined (AF_INET6) 854 if (!arg1[0]) { 855 strncpy(local_host_name,"::0",sizeof(local_host_name)); 856 } 857 #endif 858 } 859 break; 860 case 'n': 861 shell_num_cpus = atoi(optarg); 862 if (shell_num_cpus > MAXCPUS) { 863 fprintf(stderr, 864 "netserver: This version can only support %d CPUs. Please", 865 MAXCPUS); 866 fprintf(stderr, 867 " increase MAXCPUS in netlib.h and recompile.\n"); 868 fflush(stderr); 869 exit(1); 870 } 871 break; 872 case 'p': 873 /* we want to open a listen socket at a */ 874 /* specified port number */ 875 strncpy(listen_port,optarg,sizeof(listen_port)); 876 not_inetd = 1; 877 break; 878 case '4': 879 local_address_family = AF_INET; 880 break; 881 case '6': 882 #if defined(AF_INET6) 883 local_address_family = AF_INET6; 884 strncpy(local_host_name,"::0",sizeof(local_host_name)); 885 #else 886 local_address_family = AF_UNSPEC; 887 #endif 888 break; 889 case 'v': 890 /* say how much to say */ 891 verbosity = atoi(optarg); 892 break; 893 case 'V': 894 printf("Netperf version %s\n",NETPERF_VERSION); 895 exit(0); 896 break; 897 #ifdef WIN32 898 /*+*+SAF */ 899 case 'I': 900 child = TRUE; 901 /* This is the handle we expect to inherit. */ 902 /*+*+SAF server_sock = (HANDLE)atoi(optarg); */ 903 break; 904 case 'i': 905 /* This is a handle we should NOT inherit. */ 906 /*+*+SAF CloseHandle((HANDLE)atoi(optarg)); */ 907 break; 908 #endif 909 910 } 911 } 912 913 /* +*+SAF I need a better way to find inherited handles I should close! */ 914 /* +*+SAF Use DuplicateHandle to force inheritable attribute (or reset it)? */ 915 916 /* unlink(DEBUG_LOG_FILE); */ 917 918 strcpy(FileName, DEBUG_LOG_FILE); 919 920 #ifndef WIN32 921 snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); 922 if ((where = fopen(FileName, "w")) == NULL) { 923 perror("netserver: debug file"); 924 exit(1); 925 } 926 #else 927 { 928 929 if (child) { 930 snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%x", getpid()); 931 } 932 933 /* Hopefully, by closing stdout & stderr, the subsequent 934 fopen calls will get mapped to the correct std handles. */ 935 fclose(stdout); 936 937 if ((where = fopen(FileName, "w")) == NULL) { 938 perror("netserver: fopen of debug file as new stdout failed!"); 939 exit(1); 940 } 941 942 fclose(stderr); 943 944 if ((where = fopen(FileName, "w")) == NULL) { 945 fprintf(stdout, "fopen of debug file as new stderr failed!\n"); 946 exit(1); 947 } 948 } 949 #endif 950 951 #ifndef WIN32 952 chmod(DEBUG_LOG_FILE,0644); 953 #endif 954 955 #if WIN32 956 if (child) { 957 server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE); 958 } 959 #endif 960 961 /* if we are not a child of an inetd or the like, then we should 962 open a socket and hang listens off of it. otherwise, we should go 963 straight into processing requests. the do_listen() routine will sit 964 in an infinite loop accepting connections and forking child 965 processes. the child processes will call process_requests */ 966 967 /* If fd 0 is not a socket then assume we're not being called */ 968 /* from inetd and start server socket on the default port. */ 969 /* this enhancement comes from vwelch (at) ncsa.uiuc.edu (Von Welch) */ 970 if (not_inetd) { 971 /* the user specified a port number on the command line */ 972 set_up_server(local_host_name,listen_port,local_address_family); 973 } 974 #ifdef WIN32 975 /* OK, with Win2003 WinNT's POSIX subsystem is gone, and hence so is */ 976 /* fork. But hopefully the kernel support will continue to exist */ 977 /* for some time. We are not counting on the address space */ 978 /* copy_on_write support, since it isn't exposed except through the */ 979 /* NT native APIs (which are not public). We will try to use the */ 980 /* InheritHandles flag in CreateProcess though since this is public */ 981 /* and is used for more than just POSIX so hopefully it won't go */ 982 /* away. */ 983 else if (TRUE) { 984 if (child) { 985 process_requests(); 986 } else { 987 strncpy(listen_port,TEST_PORT,sizeof(listen_port)); 988 set_up_server(local_host_name,listen_port,local_address_family); 989 } 990 } 991 #endif 992 #if !defined(__VMS) 993 else if (getsockname(0, &name, &namelen) == SOCKET_ERROR) { 994 /* we may not be a child of inetd */ 995 if (errno == ENOTSOCK) { 996 strncpy(listen_port,TEST_PORT,sizeof(listen_port)); 997 set_up_server(local_host_name,listen_port,local_address_family); 998 } 999 } 1000 #endif /* !defined(__VMS) */ 1001 else { 1002 /* we are probably a child of inetd, or are being invoked via the 1003 VMS auxilliarly server mechanism */ 1004 #if !defined(__VMS) 1005 server_sock = 0; 1006 #else 1007 if ( (server_sock = socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET ) 1008 { 1009 perror("Failed to grab aux server socket" ); 1010 exit(1); 1011 } 1012 1013 #endif /* !defined(__VMS) */ 1014 process_requests(); 1015 } 1016 #ifdef WIN32 1017 /* Cleanup the winsock lib */ 1018 WSACleanup(); 1019 #endif 1020 1021 return(0); 1022 } 1023