| /* | 
 |   | 
 | 	   Copyright (C) 1993-2007 Hewlett-Packard Company | 
 |                          ALL RIGHTS RESERVED. | 
 |   | 
 |   The enclosed software and documentation includes copyrighted works | 
 |   of Hewlett-Packard Co. For as long as you comply with the following | 
 |   limitations, you are hereby authorized to (i) use, reproduce, and | 
 |   modify the software and documentation, and to (ii) distribute the | 
 |   software and documentation, including modifications, for | 
 |   non-commercial purposes only. | 
 |        | 
 |   1.  The enclosed software and documentation is made available at no | 
 |       charge in order to advance the general development of | 
 |       high-performance networking products. | 
 |   | 
 |   2.  You may not delete any copyright notices contained in the | 
 |       software or documentation. All hard copies, and copies in | 
 |       source code or object code form, of the software or | 
 |       documentation (including modifications) must contain at least | 
 |       one of the copyright notices. | 
 |   | 
 |   3.  The enclosed software and documentation has not been subjected | 
 |       to testing and quality control and is not a Hewlett-Packard Co. | 
 |       product. At a future time, Hewlett-Packard Co. may or may not | 
 |       offer a version of the software and documentation as a product. | 
 |    | 
 |   4.  THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS". | 
 |       HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE, | 
 |       REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR | 
 |       DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL | 
 |       PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR | 
 |       DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES, | 
 |       EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE | 
 |       DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF | 
 |       MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 
 |    | 
 |   5.  HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY | 
 |       DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES | 
 |       (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION, | 
 |       MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION. | 
 |   | 
 | */ | 
 |  | 
 | #include "netperf_version.h" | 
 |  | 
 | char	netserver_id[]="\ | 
 | @(#)netserver.c (c) Copyright 1993-2007 Hewlett-Packard Co. Version 2.4.3"; | 
 |  | 
 |  /***********************************************************************/ | 
 |  /*									*/ | 
 |  /*	netserver.c							*/ | 
 |  /*									*/ | 
 |  /*	This is the server side code for the netperf test package. It	*/ | 
 |  /* will operate either stand-alone, or as a child of inetd. In this	*/ | 
 |  /* way, we insure that it can be installed on systems with or without	*/ | 
 |  /* root permissions (editing inetd.conf). Essentially, this code is	*/ | 
 |  /* the analog to the netsh.c code.					*/ | 
 |  /*									*/ | 
 |  /***********************************************************************/ | 
 |  | 
 |  | 
 | /************************************************************************/ | 
 | /*									*/ | 
 | /*	Global include files						*/ | 
 | /*									*/ | 
 | /************************************************************************/ | 
 | #ifdef HAVE_CONFIG_H | 
 | #include "config.h" | 
 | #endif | 
 |  | 
 | #if HAVE_STRING_H | 
 | # if !STDC_HEADERS && HAVE_MEMORY_H | 
 | #  include <memory.h> | 
 | # endif | 
 | # include <string.h> | 
 | #endif | 
 | #if HAVE_STRINGS_H | 
 | # include <strings.h> | 
 | #endif | 
 | #if HAVE_LIMITS_H | 
 | # include <limits.h> | 
 | #endif | 
 | #include <sys/types.h> | 
 | #include <stdio.h> | 
 | #ifndef WIN32 | 
 | #include <errno.h> | 
 | #include <signal.h> | 
 | #endif | 
 | #if !defined(WIN32) && !defined(__VMS) | 
 | #include <sys/ipc.h> | 
 | #endif /* !defined(WIN32) && !defined(__VMS) */ | 
 | #include <fcntl.h> | 
 | #ifdef WIN32 | 
 | #include <time.h> | 
 | #include <winsock2.h> | 
 | #define netperf_socklen_t socklen_t | 
 | /* we need to find some other way to decide to include ws2 */ | 
 | /* if you are trying to compile on Windows 2000 or NT 4 you will */ | 
 | /* probably have to define DONT_IPV6 */ | 
 | #ifndef DONT_IPV6 | 
 | #include <ws2tcpip.h> | 
 | #endif  /* DONT_IPV6 */ | 
 | #include <windows.h> | 
 | #define sleep(x) Sleep((x)*1000) | 
 | #else | 
 | #ifndef MPE | 
 | #include <sys/time.h> | 
 | #endif /* MPE */ | 
 | #include <sys/ioctl.h> | 
 | #include <sys/socket.h> | 
 | #include <sys/stat.h> | 
 | #include <netinet/in.h> | 
 | #include <netdb.h> | 
 | #include <unistd.h> | 
 | #ifndef DONT_WAIT | 
 | #include <sys/wait.h> | 
 | #endif /* DONT_WAIT */ | 
 | #endif /* WIN32 */ | 
 | #include <stdlib.h> | 
 | #ifdef __VMS | 
 | #include <tcpip$inetdef.h>  | 
 | #include <unixio.h>  | 
 | #endif /* __VMS */ | 
 | #include "netlib.h" | 
 | #include "nettest_bsd.h" | 
 |  | 
 | #ifdef WANT_UNIX | 
 | #include "nettest_unix.h" | 
 | #endif /* WANT_UNIX */ | 
 |  | 
 | #ifdef WANT_DLPI | 
 | #include "nettest_dlpi.h" | 
 | #endif /* WANT_DLPI */ | 
 |  | 
 | #ifdef WANT_SCTP | 
 | #include "nettest_sctp.h" | 
 | #endif | 
 |  | 
 | #include "netsh.h" | 
 |  | 
 | #ifndef DEBUG_LOG_FILE | 
 | #ifndef WIN32 | 
 | #define DEBUG_LOG_FILE "/tmp/netperf.debug" | 
 | #else | 
 | #define DEBUG_LOG_FILE "c:\\temp\\netperf.debug" | 
 | #endif  /* WIN32 */ | 
 | #endif /* DEBUG_LOG_FILE */ | 
 |  | 
 |  /* some global variables */ | 
 |  | 
 | FILE	*afp; | 
 | char    listen_port[10]; | 
 | extern	char	*optarg; | 
 | extern	int	optind, opterr; | 
 |  | 
 | #ifndef WIN32 | 
 | #define SERVER_ARGS "dL:n:p:v:V46" | 
 | #else | 
 | #define SERVER_ARGS "dL:n:p:v:V46I:i:" | 
 | #endif | 
 |  | 
 | /* perhaps one day we will use this as part of only opening a debug | 
 |    log file if debug is set, of course we have to be wary of the base | 
 |    use of "where" and so probably always need "where" pointing | 
 |    "somewhere" or other. */ | 
 | void | 
 | open_debug_file()  | 
 | { | 
 | #ifndef WIN32 | 
 | #ifndef PATH_MAX | 
 | #define PATH_MAX MAX_PATH | 
 | #endif | 
 |   char FileName[PATH_MAX];   /* for opening the debug log file */ | 
 |   strcpy(FileName, DEBUG_LOG_FILE); | 
 |  | 
 |   if (where != NULL) fflush(where); | 
 |  | 
 |   snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); | 
 |   if ((where = fopen(FileName, "w")) == NULL) { | 
 |     perror("netserver: debug file"); | 
 |     exit(1); | 
 |   } | 
 |  | 
 |   chmod(FileName,0644); | 
 | #endif | 
 |  | 
 | } | 
 |  /* This routine implements the "main event loop" of the netperf	*/ | 
 |  /* server code. Code above it will have set-up the control connection	*/ | 
 |  /* so it can just merrily go about its business, which is to		*/ | 
 |  /* "schedule" performance tests on the server.				*/ | 
 |  | 
 | void  | 
 | process_requests() | 
 | { | 
 |    | 
 |   float	temp_rate; | 
 |    | 
 |   if (debug)    open_debug_file(); | 
 |  | 
 |  | 
 |   while (1) { | 
 |     recv_request(); | 
 |  | 
 |     switch (netperf_request.content.request_type) { | 
 |        | 
 |     case DEBUG_ON: | 
 |       netperf_response.content.response_type = DEBUG_OK; | 
 |       /*  dump_request already present in recv_request; redundant? */ | 
 |       if (!debug) { | 
 | 	debug++; | 
 | 	open_debug_file(); | 
 | 	dump_request(); | 
 |       } | 
 |       send_response(); | 
 |       break; | 
 |        | 
 |     case DEBUG_OFF: | 
 |       if (debug) | 
 | 	debug--; | 
 |       netperf_response.content.response_type = DEBUG_OK; | 
 |       send_response(); | 
 |       /* +SAF why??? */ | 
 |       if (!debug)  | 
 |       { | 
 | 	fclose(where); | 
 | #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) | 
 | 	/* For Unix: reopen the debug write file descriptor to "/dev/null" */ | 
 | 	/* and redirect stdout to it.					   */ | 
 | 	fflush (stdout); | 
 | 	where = fopen ("/dev/null", "w"); | 
 | 	if (where == NULL) | 
 | 	{ | 
 | 	  perror ("netserver: reopening debug fp for writing: /dev/null"); | 
 | 	  exit   (1); | 
 | 	} | 
 | 	if (close (STDOUT_FILENO) == -1) | 
 | 	{ | 
 | 	  perror ("netserver: closing stdout file descriptor"); | 
 | 	  exit   (1); | 
 | 	} | 
 | 	if (dup (fileno (where))  == -1) | 
 | 	{ | 
 | 	  perror ("netserver: duplicate /dev/null write file descr. to stdout"); | 
 | 	  exit   (1); | 
 | 	} | 
 | #endif /* !WIN32 !MPE !__VMS */ | 
 |       } | 
 |       break; | 
 |        | 
 |     case CPU_CALIBRATE: | 
 |       netperf_response.content.response_type = CPU_CALIBRATE; | 
 |       temp_rate = calibrate_local_cpu(0.0); | 
 |       bcopy((char *)&temp_rate, | 
 | 	    (char *)netperf_response.content.test_specific_data, | 
 | 	    sizeof(temp_rate)); | 
 |       bcopy((char *)&lib_num_loc_cpus, | 
 | 	    (char *)netperf_response.content.test_specific_data + sizeof(temp_rate), | 
 | 	    sizeof(lib_num_loc_cpus)); | 
 |       if (debug) { | 
 | 	fprintf(where,"netserver: sending CPU information:"); | 
 | 	fprintf(where,"rate is %g num cpu %d\n",temp_rate,lib_num_loc_cpus); | 
 | 	fflush(where); | 
 |       } | 
 |        | 
 |       /* we need the cpu_start, cpu_stop in the looper case to kill the */ | 
 |       /* child proceses raj 7/95 */ | 
 |        | 
 | #ifdef USE_LOOPER | 
 |       cpu_start(1); | 
 |       cpu_stop(1,&temp_rate); | 
 | #endif /* USE_LOOPER */ | 
 |        | 
 |       send_response(); | 
 |       break; | 
 |        | 
 |     case DO_TCP_STREAM: | 
 |       recv_tcp_stream(); | 
 |       break; | 
 |        | 
 |     case DO_TCP_MAERTS: | 
 |       recv_tcp_maerts(); | 
 |       break; | 
 |        | 
 |     case DO_TCP_RR: | 
 |       recv_tcp_rr(); | 
 |       break; | 
 |        | 
 |     case DO_TCP_CRR: | 
 |       recv_tcp_conn_rr(); | 
 |       break; | 
 |        | 
 |     case DO_TCP_CC: | 
 |       recv_tcp_cc(); | 
 |       break; | 
 |        | 
 | #ifdef DO_1644 | 
 |     case DO_TCP_TRR: | 
 |       recv_tcp_tran_rr(); | 
 |       break; | 
 | #endif /* DO_1644 */ | 
 |        | 
 | #ifdef DO_NBRR | 
 |     case DO_TCP_NBRR: | 
 |       recv_tcp_nbrr(); | 
 |       break; | 
 | #endif /* DO_NBRR */ | 
 |        | 
 |     case DO_UDP_STREAM: | 
 |       recv_udp_stream(); | 
 |       break; | 
 |        | 
 |     case DO_UDP_RR: | 
 |       recv_udp_rr(); | 
 |       break; | 
 |        | 
 | #ifdef WANT_DLPI | 
 |  | 
 |     case DO_DLPI_CO_RR: | 
 |       recv_dlpi_co_rr(); | 
 |       break; | 
 |        | 
 |     case DO_DLPI_CL_RR: | 
 |       recv_dlpi_cl_rr(); | 
 |       break; | 
 |  | 
 |     case DO_DLPI_CO_STREAM: | 
 |       recv_dlpi_co_stream(); | 
 |       break; | 
 |  | 
 |     case DO_DLPI_CL_STREAM: | 
 |       recv_dlpi_cl_stream(); | 
 |       break; | 
 |  | 
 | #endif /* WANT_DLPI */ | 
 |  | 
 | #ifdef WANT_UNIX | 
 |  | 
 |     case DO_STREAM_STREAM: | 
 |       recv_stream_stream(); | 
 |       break; | 
 |        | 
 |     case DO_STREAM_RR: | 
 |       recv_stream_rr(); | 
 |       break; | 
 |        | 
 |     case DO_DG_STREAM: | 
 |       recv_dg_stream(); | 
 |       break; | 
 |        | 
 |     case DO_DG_RR: | 
 |       recv_dg_rr(); | 
 |       break; | 
 |        | 
 | #endif /* WANT_UNIX */ | 
 |  | 
 | #ifdef WANT_XTI | 
 |     case DO_XTI_TCP_STREAM: | 
 |       recv_xti_tcp_stream(); | 
 |       break; | 
 |        | 
 |     case DO_XTI_TCP_RR: | 
 |       recv_xti_tcp_rr(); | 
 |       break; | 
 |        | 
 |     case DO_XTI_UDP_STREAM: | 
 |       recv_xti_udp_stream(); | 
 |       break; | 
 |        | 
 |     case DO_XTI_UDP_RR: | 
 |       recv_xti_udp_rr(); | 
 |       break; | 
 |  | 
 | #endif /* WANT_XTI */ | 
 |  | 
 | #ifdef WANT_SCTP | 
 |     case DO_SCTP_STREAM: | 
 |       recv_sctp_stream(); | 
 |       break; | 
 |        | 
 |     case DO_SCTP_STREAM_MANY: | 
 |       recv_sctp_stream_1toMany(); | 
 |       break; | 
 |  | 
 |     case DO_SCTP_RR: | 
 |       recv_sctp_rr(); | 
 |       break; | 
 |  | 
 |     case DO_SCTP_RR_MANY: | 
 |       recv_sctp_rr_1toMany(); | 
 |       break; | 
 | #endif | 
 |  | 
 | #ifdef WANT_SDP | 
 |     case DO_SDP_STREAM: | 
 |       recv_sdp_stream(); | 
 |       break; | 
 |  | 
 |     case DO_SDP_MAERTS: | 
 |       recv_sdp_maerts(); | 
 |       break; | 
 |  | 
 |     case DO_SDP_RR: | 
 |       recv_sdp_rr(); | 
 |       break; | 
 | #endif  | 
 |  | 
 |     default: | 
 |       fprintf(where,"unknown test number %d\n", | 
 | 	      netperf_request.content.request_type); | 
 |       fflush(where); | 
 |       netperf_response.content.serv_errno=998; | 
 |       send_response(); | 
 |       break; | 
 |        | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /*	 | 
 |  set_up_server() | 
 |  | 
 |  set-up the server listen socket. we only call this routine if the  | 
 |  user has specified a port number on the command line or we believe we | 
 |  are not a child of inetd or its platform-specific equivalent */ | 
 |  | 
 | /*KC*/ | 
 |  | 
 | void  | 
 | set_up_server(char hostname[], char port[], int af) | 
 | {  | 
 |  | 
 |   struct addrinfo     hints; | 
 |   struct addrinfo     *local_res; | 
 |   struct addrinfo     *local_res_temp; | 
 |  | 
 |   struct sockaddr_storage     peeraddr; | 
 |   netperf_socklen_t                 peeraddr_len = sizeof(peeraddr); | 
 |    | 
 |   SOCKET server_control; | 
 |   int on=1; | 
 |   int count; | 
 |   int error; | 
 |   int not_listening; | 
 |  | 
 | #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) | 
 |   FILE *rd_null_fp;    /* Used to redirect from "/dev/null". */ | 
 |   FILE *wr_null_fp;    /* Used to redirect to   "/dev/null". */ | 
 | #endif /* !WIN32 !MPE !__VMS */ | 
 |  | 
 |   if (debug) { | 
 |     fprintf(stderr, | 
 |             "set_up_server called with host '%s' port '%s' remfam %d\n", | 
 |             hostname, | 
 | 	    port, | 
 |             af); | 
 |     fflush(stderr); | 
 |   } | 
 |  | 
 |   memset(&hints,0,sizeof(hints)); | 
 |   hints.ai_family = af; | 
 |   hints.ai_socktype = SOCK_STREAM; | 
 |   hints.ai_protocol = IPPROTO_TCP; | 
 |   hints.ai_flags = AI_PASSIVE; | 
 |  | 
 |   count = 0; | 
 |   do { | 
 |     error = getaddrinfo((char *)hostname, | 
 |                         (char *)port, | 
 |                         &hints, | 
 |                         &local_res); | 
 |     count += 1; | 
 |     if (error == EAI_AGAIN) { | 
 |       if (debug) { | 
 |         fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n"); | 
 |         fflush(stderr); | 
 |       } | 
 |       sleep(1); | 
 |     } | 
 |   } while ((error == EAI_AGAIN) && (count <= 5)); | 
 |  | 
 |   if (error) { | 
 |     fprintf(stderr, | 
 | 	    "set_up_server: could not resolve remote '%s' port '%s' af %d", | 
 | 	    hostname, | 
 | 	    port, | 
 | 	    af); | 
 |     fprintf(stderr,"\n\tgetaddrinfo returned %d %s\n", | 
 | 	    error, | 
 | 	    gai_strerror(error)); | 
 |     exit(-1); | 
 |   } | 
 |  | 
 |   if (debug) { | 
 |     dump_addrinfo(stderr, local_res, hostname, port, af); | 
 |   } | 
 |  | 
 |   not_listening = 1; | 
 |   local_res_temp = local_res; | 
 |  | 
 |   while((local_res_temp != NULL) && (not_listening)) { | 
 |  | 
 |     fprintf(stderr, | 
 | 	    "Starting netserver at port %s\n", | 
 | 	    port); | 
 |  | 
 |     server_control = socket(local_res_temp->ai_family,SOCK_STREAM,0); | 
 |  | 
 |     if (server_control == INVALID_SOCKET) { | 
 |       perror("set_up_server could not allocate a socket"); | 
 |       exit(-1); | 
 |     } | 
 |  | 
 |     /* happiness and joy, keep going */ | 
 |     if (setsockopt(server_control,  | 
 | 		   SOL_SOCKET,  | 
 | 		   SO_REUSEADDR,  | 
 | 		   (char *)&on ,  | 
 | 		   sizeof(on)) == SOCKET_ERROR) { | 
 |       if (debug) { | 
 | 	perror("warning: set_up_server could not set SO_REUSEADDR"); | 
 |       } | 
 |     } | 
 |     /* still happy and joyful */ | 
 |  | 
 |     if ((bind (server_control,  | 
 | 	       local_res_temp->ai_addr,  | 
 | 	       local_res_temp->ai_addrlen) != SOCKET_ERROR) && | 
 | 	(listen (server_control,5) != SOCKET_ERROR))  { | 
 |       not_listening = 0; | 
 |       break; | 
 |     } | 
 |     else { | 
 |       /* we consider a bind() or listen() failure a transient and try | 
 | 	 the next address */ | 
 |       if (debug) { | 
 | 	perror("warning: set_up_server failed a bind or listen call\n"); | 
 |       } | 
 |       local_res_temp = local_res_temp->ai_next; | 
 |       continue; | 
 |     } | 
 |   } | 
 |  | 
 |   if (not_listening) { | 
 |     fprintf(stderr, | 
 | 	    "set_up_server could not establish a listen endpoint for %s port %s with family %s\n", | 
 | 	    host_name, | 
 | 	    port, | 
 | 	    inet_ftos(af)); | 
 |     fflush(stderr); | 
 |     exit(-1); | 
 |   } | 
 |   else { | 
 |     printf("Starting netserver at hostname %s port %s and family %s\n", | 
 | 	   hostname, | 
 | 	   port, | 
 | 	   inet_ftos(af)); | 
 |   } | 
 |  | 
 |   /* | 
 |     setpgrp(); | 
 |     */ | 
 |  | 
 | #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) | 
 |   /* Flush the standard I/O file descriptors before forking. */ | 
 |   fflush (stdin); | 
 |   fflush (stdout); | 
 |   fflush (stderr); | 
 |   switch (fork()) | 
 |     { | 
 |     case -1:  	 | 
 |       perror("netperf server error"); | 
 |       exit(1); | 
 |        | 
 |     case 0:	 | 
 |       /* Redirect stdin from "/dev/null". */ | 
 |       rd_null_fp = fopen ("/dev/null", "r"); | 
 |       if (rd_null_fp == NULL) | 
 |       { | 
 | 	perror ("netserver: opening for reading: /dev/null"); | 
 | 	exit   (1); | 
 |       } | 
 |       if (close (STDIN_FILENO) == -1) | 
 |       { | 
 | 	perror ("netserver: closing stdin file descriptor"); | 
 | 	exit   (1); | 
 |       } | 
 |       if (dup (fileno (rd_null_fp)) == -1) | 
 |       { | 
 | 	perror ("netserver: duplicate /dev/null read file descr. to stdin"); | 
 | 	exit   (1); | 
 |       } | 
 |  | 
 |       /* Redirect stdout to the debug write file descriptor. */ | 
 |       if (close (STDOUT_FILENO) == -1) | 
 |       { | 
 | 	perror ("netserver: closing stdout file descriptor"); | 
 | 	exit   (1); | 
 |       } | 
 |       if (dup (fileno (where))  == -1) | 
 |       { | 
 | 	perror ("netserver: duplicate the debug write file descr. to stdout"); | 
 | 	exit   (1); | 
 |       } | 
 |  | 
 |       /* Redirect stderr to "/dev/null". */ | 
 |       wr_null_fp = fopen ("/dev/null", "w"); | 
 |       if (wr_null_fp == NULL) | 
 |       { | 
 | 	perror ("netserver: opening for writing: /dev/null"); | 
 | 	exit   (1); | 
 |       } | 
 |       if (close (STDERR_FILENO) == -1) | 
 |       { | 
 | 	perror ("netserver: closing stderr file descriptor"); | 
 | 	exit   (1); | 
 |       } | 
 |       if (dup (fileno (wr_null_fp))  == -1) | 
 |       { | 
 | 	perror ("netserver: dupicate /dev/null write file descr. to stderr"); | 
 | 	exit   (1); | 
 |       } | 
 |   | 
 | #ifndef NO_SETSID | 
 |       setsid(); | 
 | #else | 
 |       setpgrp(); | 
 | #endif /* NO_SETSID */ | 
 |  | 
 |  /* some OS's have SIGCLD defined as SIGCHLD */ | 
 | #ifndef SIGCLD | 
 | #define SIGCLD SIGCHLD | 
 | #endif /* SIGCLD */ | 
 |  | 
 |       signal(SIGCLD, SIG_IGN); | 
 |        | 
 | #endif /* !WIN32 !MPE !__VMS */ | 
 |  | 
 |       for (;;) | 
 | 	{ | 
 | 	  if ((server_sock=accept(server_control, | 
 | 				  (struct sockaddr *)&peeraddr, | 
 | 				  &peeraddr_len)) == INVALID_SOCKET) | 
 | 	    { | 
 | 	      printf("server_control: accept failed errno %d\n",errno); | 
 | 	      exit(1); | 
 | 	    } | 
 | #if defined(MPE) || defined(__VMS) | 
 | 	  /* | 
 | 	   * Since we cannot fork this process , we cant fire any threads | 
 | 	   * as they all share the same global data . So we better allow | 
 | 	   * one request at at time  | 
 | 	   */ | 
 | 	  process_requests() ; | 
 | #elif WIN32 | 
 | 		{ | 
 | 			BOOL b; | 
 | 			char cmdline[80]; | 
 | 			PROCESS_INFORMATION pi; | 
 | 			STARTUPINFO si; | 
 | 			int i; | 
 |  | 
 | 			memset(&si, 0 , sizeof(STARTUPINFO)); | 
 | 			si.cb = sizeof(STARTUPINFO); | 
 |  | 
 | 			/* Pass the server_sock as stdin for the new process. */ | 
 | 			/* Hopefully this will continue to be created with the OBJ_INHERIT attribute. */ | 
 | 			si.hStdInput = (HANDLE)server_sock; | 
 | 			si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); | 
 | 			si.hStdError = GetStdHandle(STD_ERROR_HANDLE); | 
 | 			si.dwFlags = STARTF_USESTDHANDLES; | 
 |  | 
 | 			/* Build cmdline for child process */ | 
 | 			strcpy(cmdline, program); | 
 | 			if (verbosity > 1) { | 
 | 				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -v %d", verbosity); | 
 | 			} | 
 | 			for (i=0; i < debug; i++) { | 
 | 				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -d"); | 
 | 			} | 
 | 			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -I %x", (int)(UINT_PTR)server_sock); | 
 | 			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)server_control); | 
 | 			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)where); | 
 |  | 
 | 			b = CreateProcess(NULL,	 /* Application Name */ | 
 | 					cmdline, | 
 | 					NULL,    /* Process security attributes */ | 
 | 					NULL,    /* Thread security attributes */ | 
 | 					TRUE,    /* Inherit handles */ | 
 | 					0,	   /* Creation flags  PROCESS_QUERY_INFORMATION,  */ | 
 | 					NULL,    /* Enviornment */ | 
 | 					NULL,    /* Current directory */ | 
 | 					&si,	   /* StartupInfo */ | 
 | 					&pi); | 
 | 			if (!b) | 
 | 			{ | 
 | 				perror("CreateProcessfailure: "); | 
 | 				exit(1); | 
 | 			} | 
 |  | 
 | 			/* We don't need the thread or process handles any more; let them */ | 
 | 			/* go away on their own timeframe. */ | 
 |  | 
 | 			CloseHandle(pi.hThread); | 
 | 			CloseHandle(pi.hProcess); | 
 |  | 
 | 			/* And close the server_sock since the child will own it. */ | 
 |  | 
 | 			close(server_sock); | 
 | 		} | 
 | #else | 
 |       signal(SIGCLD, SIG_IGN); | 
 | 	   | 
 | 	  switch (fork()) | 
 | 	    { | 
 | 	    case -1: | 
 | 	      /* something went wrong */ | 
 | 	      exit(1); | 
 | 	    case 0: | 
 | 	      /* we are the child process */ | 
 | 	      close(server_control); | 
 | 	      process_requests(); | 
 | 	      exit(0); | 
 | 	      break; | 
 | 	    default: | 
 | 	      /* we are the parent process */ | 
 | 	      close(server_sock); | 
 | 	      /* we should try to "reap" some of our children. on some */ | 
 | 	      /* systems they are being left as defunct processes. we */ | 
 | 	      /* will call waitpid, looking for any child process, */ | 
 | 	      /* with the WNOHANG feature. when waitpid return a zero, */ | 
 | 	      /* we have reaped all the children there are to reap at */ | 
 | 	      /* the moment, so it is time to move on. raj 12/94 */ | 
 | #ifndef DONT_WAIT | 
 | #ifdef NO_SETSID | 
 | 	      /* Only call "waitpid()" if "setsid()" is not used. */ | 
 | 	      while(waitpid(-1, NULL, WNOHANG) > 0) { } | 
 | #endif /* NO_SETSID */ | 
 | #endif /* DONT_WAIT */ | 
 | 	      break; | 
 | 	    } | 
 | #endif /* !WIN32 !MPE !__VMS */   | 
 | 	} /*for*/ | 
 | #if !defined(WIN32) && !defined(MPE) && !defined(__VMS) | 
 |       break; /*case 0*/ | 
 |        | 
 |     default:  | 
 |       exit (0); | 
 |        | 
 |     } | 
 | #endif /* !WIN32 !MPE !__VMS */   | 
 | } | 
 |  | 
 | #ifdef WIN32 | 
 |  | 
 |   /* With Win2003, WinNT's POSIX subsystem is gone and hence so is */ | 
 |   /* fork. */ | 
 |  | 
 |   /* But hopefully the kernel support will continue to exist for some */ | 
 |   /* time. */ | 
 |  | 
 |   /* We are not counting on the child address space copy_on_write */ | 
 |   /* support, since it isn't exposed except through the NT native APIs */ | 
 |   /* (which is not public). */ | 
 |  | 
 |   /* We will try to use the InheritHandles flag in CreateProcess.  It */ | 
 |   /* is in the public API, though it is documented as "must be FALSE". */ | 
 |  | 
 |   /* So where we would have forked, we will now create a new process. */ | 
 |   /* I have added a set of command line switches to specify a list of */ | 
 |   /* handles that the child should close since they shouldn't have */ | 
 |   /* been inherited ("-i#"), and a single switch to specify the handle */ | 
 |   /* for the server_sock ("I#"). */ | 
 |  | 
 |   /* A better alternative would be to re-write NetPerf to be */ | 
 |   /* multi-threaded; i.e., move all of the various NetPerf global */ | 
 |   /* variables in to thread specific structures.  But this is a bigger */ | 
 |   /* effort than I want to tackle at this time.  (And I doubt that the */ | 
 |   /* HP-UX author sees value in this effort). */ | 
 |  | 
 | #endif | 
 |  | 
 | int _cdecl | 
 | main(int argc, char *argv[]) | 
 | { | 
 |  | 
 |   int	c; | 
 |   int   not_inetd = 0; | 
 | #ifdef WIN32 | 
 |   BOOL  child = FALSE; | 
 | #endif | 
 |   char arg1[BUFSIZ], arg2[BUFSIZ]; | 
 | #ifndef PATH_MAX | 
 | #define PATH_MAX MAX_PATH | 
 | #endif | 
 |   char FileName[PATH_MAX];   /* for opening the debug log file */ | 
 |  | 
 |   struct sockaddr name; | 
 |   netperf_socklen_t namelen = sizeof(name); | 
 |    | 
 |  | 
 | #ifdef WIN32 | 
 | 	WSADATA	wsa_data ; | 
 |  | 
 | 	/* Initialize the winsock lib ( version 2.2 ) */ | 
 | 	if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){ | 
 | 		printf("WSAStartup() failed : %d\n", GetLastError()) ; | 
 | 		return 1 ; | 
 | 	} | 
 | #endif /* WIN32 */ | 
 |  | 
 | 	/* Save away the program name */ | 
 | 	program = (char *)malloc(strlen(argv[0]) + 1); | 
 | 	if (program == NULL) { | 
 | 		printf("malloc(%zu) failed!\n", strlen(argv[0]) + 1); | 
 | 		return 1 ; | 
 | 	} | 
 | 	strcpy(program, argv[0]); | 
 |  | 
 |   netlib_init(); | 
 |    | 
 |   /* Scan the command line to see if we are supposed to set-up our own */ | 
 |   /* listen socket instead of relying on inetd. */ | 
 |  | 
 |   /* first set a copy of initial values */ | 
 |   strncpy(local_host_name,"0.0.0.0",sizeof(local_host_name)); | 
 |   local_address_family = AF_UNSPEC; | 
 |   strncpy(listen_port,TEST_PORT,sizeof(listen_port)); | 
 |  | 
 |   while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF) { | 
 |     switch (c) { | 
 |     case '?': | 
 |     case 'h': | 
 |       print_netserver_usage(); | 
 |       exit(1); | 
 |     case 'd': | 
 |       /* we want to set the debug file name sometime */ | 
 |       debug++; | 
 |       break; | 
 |     case 'L': | 
 |       not_inetd = 1; | 
 |       break_args_explicit(optarg,arg1,arg2); | 
 |       if (arg1[0]) { | 
 | 	strncpy(local_host_name,arg1,sizeof(local_host_name)); | 
 |       } | 
 |       if (arg2[0]) { | 
 | 	local_address_family = parse_address_family(arg2); | 
 | 	/* if only the address family was set, we may need to set the | 
 | 	   local_host_name accordingly. since our defaults are IPv4 | 
 | 	   this should only be necessary if we have IPv6 support raj | 
 | 	   2005-02-07 */   | 
 | #if defined (AF_INET6) | 
 | 	if (!arg1[0]) { | 
 | 	  strncpy(local_host_name,"::0",sizeof(local_host_name)); | 
 | 	} | 
 | #endif | 
 |       } | 
 |       break; | 
 |     case 'n': | 
 |       shell_num_cpus = atoi(optarg); | 
 |       if (shell_num_cpus > MAXCPUS) { | 
 | 	fprintf(stderr, | 
 | 		"netserver: This version can only support %d CPUs. Please", | 
 | 		MAXCPUS); | 
 | 	fprintf(stderr, | 
 | 		"           increase MAXCPUS in netlib.h and recompile.\n"); | 
 | 	fflush(stderr); | 
 | 	exit(1); | 
 |       } | 
 |       break; | 
 |     case 'p': | 
 |       /* we want to open a listen socket at a */ | 
 |       /* specified port number */ | 
 |       strncpy(listen_port,optarg,sizeof(listen_port)); | 
 |       not_inetd = 1; | 
 |       break; | 
 |     case '4': | 
 |       local_address_family = AF_INET; | 
 |       break; | 
 |     case '6': | 
 | #if defined(AF_INET6) | 
 |       local_address_family = AF_INET6; | 
 |       strncpy(local_host_name,"::0",sizeof(local_host_name)); | 
 | #else | 
 |       local_address_family = AF_UNSPEC; | 
 | #endif | 
 |       break; | 
 |     case 'v': | 
 |       /* say how much to say */ | 
 |       verbosity = atoi(optarg); | 
 |       break; | 
 |     case 'V': | 
 |       printf("Netperf version %s\n",NETPERF_VERSION); | 
 |       exit(0); | 
 |       break; | 
 | #ifdef WIN32 | 
 | /*+*+SAF */ | 
 | 	case 'I': | 
 | 		child = TRUE; | 
 | 		/* This is the handle we expect to inherit. */ | 
 | 		/*+*+SAF server_sock = (HANDLE)atoi(optarg); */ | 
 | 		break; | 
 | 	case 'i': | 
 | 		/* This is a handle we should NOT inherit. */ | 
 | 		/*+*+SAF CloseHandle((HANDLE)atoi(optarg)); */ | 
 | 		break; | 
 | #endif | 
 |  | 
 |     } | 
 |   } | 
 |  | 
 |   /* +*+SAF I need a better way to find inherited handles I should close! */ | 
 |   /* +*+SAF Use DuplicateHandle to force inheritable attribute (or reset it)? */ | 
 |  | 
 | /*  unlink(DEBUG_LOG_FILE); */ | 
 |  | 
 |   strcpy(FileName, DEBUG_LOG_FILE); | 
 |      | 
 | #ifndef WIN32 | 
 |   snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid()); | 
 |   if ((where = fopen(FileName, "w")) == NULL) { | 
 |     perror("netserver: debug file"); | 
 |     exit(1); | 
 |   } | 
 | #else | 
 |   { | 
 |      | 
 |     if (child) { | 
 |       snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%x", getpid()); | 
 |     } | 
 |      | 
 |     /* Hopefully, by closing stdout & stderr, the subsequent | 
 |        fopen calls will get mapped to the correct std handles. */ | 
 |     fclose(stdout); | 
 |      | 
 |     if ((where = fopen(FileName, "w")) == NULL) { | 
 |       perror("netserver: fopen of debug file as new stdout failed!"); | 
 |       exit(1); | 
 |     } | 
 |      | 
 |     fclose(stderr); | 
 |      | 
 |     if ((where = fopen(FileName, "w")) == NULL) { | 
 |       fprintf(stdout, "fopen of debug file as new stderr failed!\n"); | 
 |       exit(1); | 
 |     } | 
 |   } | 
 | #endif | 
 |   | 
 | #ifndef WIN32  | 
 |   chmod(DEBUG_LOG_FILE,0644); | 
 | #endif | 
 |    | 
 | #if WIN32 | 
 |   if (child) { | 
 | 	  server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE); | 
 |   } | 
 | #endif | 
 |  | 
 |   /* if we are not a child of an inetd or the like, then we should | 
 |    open a socket and hang listens off of it. otherwise, we should go | 
 |    straight into processing requests. the do_listen() routine will sit | 
 |    in an infinite loop accepting connections and forking child | 
 |    processes. the child processes will call process_requests */ | 
 |    | 
 |   /* If fd 0 is not a socket then assume we're not being called */ | 
 |   /* from inetd and start server socket on the default port. */ | 
 |   /* this enhancement comes from vwelch@ncsa.uiuc.edu (Von Welch) */ | 
 |   if (not_inetd) { | 
 |     /* the user specified a port number on the command line */ | 
 |     set_up_server(local_host_name,listen_port,local_address_family); | 
 |   } | 
 | #ifdef WIN32 | 
 |   /* OK, with Win2003 WinNT's POSIX subsystem is gone, and hence so is */ | 
 |   /* fork.  But hopefully the kernel support will continue to exist */ | 
 |   /* for some time.  We are not counting on the address space */ | 
 |   /* copy_on_write support, since it isn't exposed except through the */ | 
 |   /* NT native APIs (which are not public).  We will try to use the */ | 
 |   /* InheritHandles flag in CreateProcess though since this is public */ | 
 |   /* and is used for more than just POSIX so hopefully it won't go */ | 
 |   /* away. */ | 
 |   else if (TRUE) { | 
 |     if (child) { | 
 |       process_requests(); | 
 |     } else { | 
 |       strncpy(listen_port,TEST_PORT,sizeof(listen_port)); | 
 |       set_up_server(local_host_name,listen_port,local_address_family); | 
 |     } | 
 |   } | 
 | #endif | 
 | #if !defined(__VMS) | 
 |   else if (getsockname(0, &name, &namelen) == SOCKET_ERROR) { | 
 |     /* we may not be a child of inetd */ | 
 |     if (errno == ENOTSOCK) { | 
 |       strncpy(listen_port,TEST_PORT,sizeof(listen_port)); | 
 |       set_up_server(local_host_name,listen_port,local_address_family); | 
 |     } | 
 |   } | 
 | #endif /* !defined(__VMS) */ | 
 |   else { | 
 |     /* we are probably a child of inetd, or are being invoked via the | 
 |        VMS auxilliarly server mechanism */ | 
 | #if !defined(__VMS) | 
 |     server_sock = 0; | 
 | #else | 
 |     if ( (server_sock = socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET )  | 
 |     {  | 
 |       perror("Failed to grab aux server socket" );  | 
 |       exit(1);  | 
 |     }  | 
 |    | 
 | #endif /* !defined(__VMS) */ | 
 |     process_requests(); | 
 |   } | 
 | #ifdef WIN32 | 
 | 	/* Cleanup the winsock lib */ | 
 | 	WSACleanup(); | 
 | #endif | 
 |  | 
 |   return(0); | 
 | } |