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
47char	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
152FILE	*afp;
153char    listen_port[10];
154extern	char	*optarg;
155extern	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. */
167void
168open_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
194void
195process_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
430void
431set_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
784int _cdecl
785main(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@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