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
open_debug_file()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
process_requests()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
set_up_server(char hostname[],char port[],int af)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
main(int argc,char * argv[])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@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