Home | History | Annotate | Download | only in netperf
      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