• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 
3 	   Copyright (C) 1993-2012 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-2012 Hewlett-Packard Co. Version 2.6.0";
49 
50 
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54 
55 #if HAVE_STRING_H
56 # if !STDC_HEADERS && HAVE_MEMORY_H
57 #  include <memory.h>
58 # endif
59 # include <string.h>
60 #endif
61 
62 #if HAVE_STRINGS_H
63 # include <strings.h>
64 #endif
65 
66 #if HAVE_LIMITS_H
67 # include <limits.h>
68 #endif
69 
70 #if HAVE_SYS_IPC_H
71 #include <sys/ipc.h>
72 #endif
73 
74 #if HAVE_SYS_IOCTL_H
75 #include <sys/ioctl.h>
76 #endif
77 
78 #if HAVE_SYS_SOCKET_H
79 #include <sys/socket.h>
80 #endif
81 
82 #if HAVE_SYS_STAT_H
83 #include <sys/stat.h>
84 #endif
85 
86 #if HAVE_NETINET_IN_H
87 #include <netinet/in.h>
88 #endif
89 
90 #if HAVE_NETDB_H
91 #include <netdb.h>
92 #endif
93 
94 #if HAVE_UNISTD_H
95 #include <unistd.h>
96 #endif
97 
98 #if HAVE_STDLIB_H
99 #include <stdlib.h>
100 #endif
101 
102 #if HAVE_ERRNO_H
103 #include <errno.h>
104 #endif
105 
106 #if HAVE_SIGNAL_H
107 #include <signal.h>
108 /* some OS's have SIGCLD defined as SIGCHLD */
109 #ifndef SIGCLD
110 #define SIGCLD SIGCHLD
111 #endif /* SIGCLD */
112 
113 #endif
114 
115 #if !defined(HAVE_SETSID)
116 #if HAVE_SYS_WAIT_H
117 #include <sys/wait.h>
118 #endif
119 #endif
120 
121 #ifdef WIN32
122 #include <time.h>
123 #include <winsock2.h>
124 
125 #if HAVE_WS2TCPIP_H
126 #include <ws2tcpip.h>
127 #endif
128 
129 #include <windows.h>
130 
131 #include "missing\stdint.h"
132 
133 #define strdup _strdup
134 #define sleep(x) Sleep((x)*1000)
135 #define netperf_socklen_t socklen_t
136 #endif /* WIN32 */
137 
138 /* unconditional system includes */
139 
140 #include <sys/types.h>
141 #include <stdio.h>
142 #include <fcntl.h>
143 
144 /* netperf includes */
145 #include "netlib.h"
146 #include "nettest_bsd.h"
147 
148 #ifdef WANT_UNIX
149 #include "nettest_unix.h"
150 #endif /* WANT_UNIX */
151 
152 #ifdef WANT_DLPI
153 #include "nettest_dlpi.h"
154 #endif /* WANT_DLPI */
155 
156 #ifdef WANT_SCTP
157 #include "nettest_sctp.h"
158 #endif
159 
160 #include "netsh.h"
161 
162 #ifndef DEBUG_LOG_FILE_DIR
163 #if defined(WIN32)
164 #define DEBUG_LOG_FILE_DIR ""
165 #elif defined(ANDROID)
166 #define DEBUG_LOG_FILE_DIR "/data/local/tmp/"
167 #else
168 #define DEBUG_LOG_FILE_DIR "/tmp/"
169 #endif
170 #endif /* DEBUG_LOG_FILE_DIR */
171 
172 #ifndef DEBUG_LOG_FILE
173 #define DEBUG_LOG_FILE DEBUG_LOG_FILE_DIR"netserver.debug"
174 #endif
175 
176 #if !defined(PATH_MAX)
177 #define PATH_MAX MAX_PATH
178 #endif
179 char     FileName[PATH_MAX];
180 
181 char     listen_port[10];
182 
183 struct listen_elt {
184   SOCKET fd;
185   struct listen_elt *next;
186 };
187 
188 struct listen_elt *listen_list = NULL;
189 
190 SOCKET   server_control;
191 
192 int      child;   /* are we the child of inetd or a parent netserver?
193 		     */
194 int      netperf_daemon;
195 int      daemon_parent = 0;
196 int      not_inetd;
197 int      want_daemonize;
198 int      spawn_on_accept;
199 int      suppress_debug = 0;
200 
201 extern	char	*optarg;
202 extern	int	optind, opterr;
203 
204 /* char  *passphrase = NULL; */
205 
206 static void
init_netserver_globals()207 init_netserver_globals() {
208 
209 #if defined(__VMS) || defined(VMWARE_UW)
210   spawn_on_accept = 0;
211   want_daemonize = 0;
212 #else
213   spawn_on_accept = 1;
214 #if defined(WIN32)
215   /* we only know how to spawn in WIN32, not daemonize */
216   want_daemonize = 0;
217 #else
218   want_daemonize = 1;
219 #endif /* WIN32 */
220 #endif /* __VMS || VMWARE_UW */
221 
222   child = 0;
223   not_inetd = 0;
224   netperf_daemon = 0;
225 }
226 
227 void
unlink_empty_debug_file()228 unlink_empty_debug_file() {
229 
230 #if !defined(WIN32)
231   struct stat buf;
232 
233   if (stat(FileName,&buf)== 0) {
234 
235     if (buf.st_size == 0)
236       unlink(FileName);
237   }
238 #endif
239 }
240 
241 /* it is important that set_server_sock() be called before this
242    routine as we depend on the control socket being dup()ed out of the
243    way when we go messing about with the streams. */
244 void
open_debug_file()245 open_debug_file()
246 {
247 #if !defined WIN32
248 #define NETPERF_NULL "/dev/null"
249 #else
250 #define NETPERF_NULL "nul"
251 #endif
252 
253   FILE *rd_null_fp;
254 
255   if (where != NULL) fflush(where);
256 
257   snprintf(FileName,
258 	   sizeof(FileName),
259 #if defined(WIN32)
260 	   "%s\\%s_%d",
261 	   getenv("TEMP"),
262 #else
263 	   "%s_%d",
264 #endif
265 	   DEBUG_LOG_FILE,
266 	   getpid());
267   if ((where = fopen((suppress_debug) ? NETPERF_NULL : FileName,
268 		     "w")) == NULL) {
269     perror("netserver: debug file");
270     exit(1);
271   }
272 
273 #if !defined(WIN32)
274 
275   chmod(FileName,0644);
276 
277   /* redirect stdin to "/dev/null" */
278   rd_null_fp = fopen(NETPERF_NULL,"r");
279   if (NULL == rd_null_fp) {
280     fprintf(where,
281 	    "%s: opening of %s failed: %s (errno %d)\n",
282 	    __FUNCTION__,
283 	    NETPERF_NULL,
284 	    strerror(errno),
285 	    errno);
286     fflush(where);
287     exit(1);
288   }
289 
290   if (close(STDIN_FILENO) == -1) {
291     fprintf(where,
292 	    "%s: close of STDIN_FILENO failed: %s (errno %d)\n",
293 	    __FUNCTION__,
294 	    strerror(errno),
295 	    errno);
296     fflush(where);
297     exit(1);
298   }
299 
300   if (dup(fileno(rd_null_fp)) == -1) {
301     fprintf(where,
302 	    "%s: dup of rd_null_fp to stdin failed: %s (errno %d)\n",
303 	    __FUNCTION__,
304 	    strerror(errno),
305 	    errno);
306     fflush(where);
307     exit(1);
308   }
309 
310   /* redirect stdout to "where" */
311   if (close(STDOUT_FILENO) == -1) {
312     fprintf(where,
313 	    "%s: close of STDOUT_FILENO failed: %s (errno %d)\n",
314 	    __FUNCTION__,
315 	    strerror(errno),
316 	    errno);
317     fflush(where);
318     exit(1);
319   }
320 
321   if (dup(fileno(where)) == -1) {
322     fprintf(where,
323 	    "%s: dup of where to stdout failed: %s (errno %d)\n",
324 	    __FUNCTION__,
325 	    strerror(errno),
326 	    errno);
327     fflush(where);
328     exit(1);
329   }
330 
331   /* redirect stderr to "where" */
332   if (close(STDERR_FILENO) == -1) {
333     fprintf(where,
334 	    "%s: close of STDERR_FILENO failed: %s (errno %d)\n",
335 	    __FUNCTION__,
336 	    strerror(errno),
337 	    errno);
338     fflush(where);
339     exit(1);
340   }
341 
342   if (dup(fileno(where)) == -1) {
343     fprintf(where,
344 	    "%s: dup of where to stderr failed: %s (errno %d)\n",
345 	    __FUNCTION__,
346 	    strerror(errno),
347 	    errno);
348     fflush(where);
349     exit(1);
350   }
351 
352 #else
353 
354   /* Hopefully, by closing stdout & stderr, the subsequent fopen calls
355      will get mapped to the correct std handles. */
356   fclose(stdout);
357 
358   if ((where = fopen(FileName, "w")) == NULL) {
359     perror("netserver: fopen of debug file as new stdout failed!");
360     exit(1);
361   }
362 
363   fclose(stderr);
364 
365   if ((where = fopen(FileName, "w")) == NULL) {
366     fprintf(stdout, "fopen of debug file as new stderr failed!\n");
367     exit(1);
368   }
369 
370 #endif
371 
372 }
373 
374 /* so, either we are a child of inetd in which case server_sock should
375    be stdin, or we are a child of a netserver parent.  there will be
376    logic here for all of it, including Windows. it is important that
377    this be called before open_debug_file() */
378 
379 void
set_server_sock()380 set_server_sock() {
381 
382   if (debug) {
383     fprintf(where,
384 	    "%s: enter\n",
385 	    __FUNCTION__);
386     fflush(where);
387   }
388 
389 #ifdef WIN32
390   server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE);
391 #elif !defined(__VMS)
392   if (server_sock != INVALID_SOCKET) {
393     fprintf(where,"Yo, Iz ain't invalid!\n");
394     fflush(where);
395     exit(1);
396   }
397 
398   /* we dup this to up the reference count so when we do redirection
399      of the io streams we don't accidentally toast the control
400      connection in the case of our being a child of inetd. */
401   server_sock = dup(0);
402 
403 #else
404   if ((server_sock =
405        socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET) {
406     fprintf(stderr,
407 	    "%s: failed to grab aux server socket: %s (errno %s)\n",
408 	    __FUNCTION__,
409 	    strerror(errno),
410 	    errno);
411     fflush(stderr);
412     exit(1);
413   }
414 #endif
415 
416 }
417 
418 
419 void
create_listens(char hostname[],char port[],int af)420 create_listens(char hostname[], char port[], int af) {
421 
422   struct addrinfo hints;
423   struct addrinfo *local_res;
424   struct addrinfo *local_res_temp;
425   int count, error;
426   int on = 1;
427   SOCKET temp_socket;
428   struct listen_elt *temp_elt;
429 
430   if (debug) {
431     fprintf(stderr,
432 	    "%s: called with host '%s' port '%s' family %s(%d)\n",
433 	    __FUNCTION__,
434             hostname,
435 	    port,
436 	    inet_ftos(af),
437             af);
438     fflush(stderr);
439   }
440  memset(&hints,0,sizeof(hints));
441   hints.ai_family = af;
442   hints.ai_socktype = SOCK_STREAM;
443   hints.ai_protocol = IPPROTO_TCP;
444   hints.ai_flags = AI_PASSIVE;
445 
446   count = 0;
447   do {
448     error = getaddrinfo((char *)hostname,
449                         (char *)port,
450                         &hints,
451                         &local_res);
452     count += 1;
453     if (error == EAI_AGAIN) {
454       if (debug) {
455         fprintf(stderr,
456 		"%s: Sleeping on getaddrinfo EAI_AGAIN\n",
457 		__FUNCTION__);
458         fflush(stderr);
459       }
460       sleep(1);
461     }
462   } while ((error == EAI_AGAIN) && (count <= 5));
463 
464   if (error) {
465     if (debug) {
466 
467       fprintf(stderr,
468 	      "%s: could not resolve remote '%s' port '%s' af %d\n"
469 	      "\tgetaddrinfo returned %s (%d)\n",
470 	      __FUNCTION__,
471 	      hostname,
472 	      port,
473 	      af,
474 	      gai_strerror(error),
475 	      error);
476 
477     }
478     return;
479   }
480 
481   if (debug) {
482     dump_addrinfo(stderr, local_res, hostname, port, af);
483   }
484 
485   local_res_temp = local_res;
486 
487   while (local_res_temp != NULL) {
488 
489     temp_socket = socket(local_res_temp->ai_family,SOCK_STREAM,0);
490 
491     if (temp_socket == INVALID_SOCKET) {
492       if (debug) {
493 	fprintf(stderr,
494 		"%s could not allocate a socket: %s (errno %d)\n",
495 		__FUNCTION__,
496 		strerror(errno),
497 		errno);
498 	fflush(stderr);
499       }
500       local_res_temp = local_res_temp->ai_next;
501       continue;
502     }
503 
504     /* happiness and joy, keep going */
505     if (setsockopt(temp_socket,
506 		   SOL_SOCKET,
507 		   SO_REUSEADDR,
508 		   (char *)&on ,
509 		   sizeof(on)) == SOCKET_ERROR) {
510       if (debug) {
511 	fprintf(stderr,
512 		"%s: warning: could not set SO_REUSEADDR: %s (errno %d)\n",
513 		__FUNCTION__,
514 		strerror(errno),
515 		errno);
516 	fflush(stderr);
517       }
518     }
519     /* still happy and joyful */
520 
521     if ((bind(temp_socket,
522 	      local_res_temp->ai_addr,
523 	      local_res_temp->ai_addrlen) != SOCKET_ERROR) &&
524 	(listen(temp_socket,1024) != SOCKET_ERROR))  {
525 
526       /* OK, now add to the list */
527       temp_elt = (struct listen_elt *)malloc(sizeof(struct listen_elt));
528       if (temp_elt) {
529 	temp_elt->fd = temp_socket;
530 	if (listen_list) {
531 	  temp_elt->next = listen_list;
532 	}
533 	else {
534 	  temp_elt->next = NULL;
535 	}
536 	listen_list = temp_elt;
537       }
538       else {
539 	fprintf(stderr,
540 		"%s: could not malloc a listen_elt\n",
541 		__FUNCTION__);
542 	fflush(stderr);
543 	exit(1);
544       }
545     }
546     else {
547       /* we consider a bind() or listen() failure a transient and try
548 	 the next address */
549       if (debug) {
550 	fprintf(stderr,
551 		"%s: warning: bind or listen call failure: %s (errno %d)\n",
552 		__FUNCTION__,
553 		strerror(errno),
554 		errno);
555 	fflush(stderr);
556       }
557       close(temp_socket);
558     }
559     local_res_temp = local_res_temp->ai_next;
560   }
561 
562 }
563 
564 void
setup_listens(char name[],char port[],int af)565 setup_listens(char name[], char port[], int af) {
566 
567   int do_inet;
568   int no_name = 0;
569 #ifdef AF_INET6
570   int do_inet6;
571 #endif
572 
573   if (debug) {
574     fprintf(where,
575 	    "%s: enter\n",
576 	    __FUNCTION__);
577     fflush(where);
578   }
579 
580 
581   if (strcmp(name,"") == 0) {
582     no_name = 1;
583     switch (af) {
584     case AF_UNSPEC:
585       do_inet = 1;
586 #ifdef AF_INET6
587       do_inet6 = 1;
588 #endif
589       break;
590     case AF_INET:
591       do_inet = 1;
592 #ifdef AF_INET6
593       do_inet6 = 0;
594 #endif
595       break;
596 #ifdef AF_INET6
597     case AF_INET6:
598       do_inet = 0;
599       do_inet6 = 1;
600       break;
601 #endif
602     default:
603       do_inet = 1;
604     }
605     /* if we have IPv6, try that one first because it may be a superset */
606 #ifdef AF_INET6
607     if (do_inet6)
608       create_listens("::0",port,AF_INET6);
609 #endif
610     if (do_inet)
611       create_listens("0.0.0.0",port,AF_INET);
612   }
613   else {
614     create_listens(name,port,af);
615   }
616 
617   if (listen_list) {
618     fprintf(stdout,
619 	    "Starting netserver with host '%s' port '%s' and family %s\n",
620 	    (no_name) ? "IN(6)ADDR_ANY" : name,
621 	    port,
622 	    inet_ftos(af));
623     fflush(stdout);
624   }
625   else {
626     fprintf(stderr,
627 	    "Unable to start netserver with  '%s' port '%s' and family %s\n",
628 	    (no_name) ? "IN(6)ADDR_ANY" : name,
629 	    port,
630 	    inet_ftos(af));
631     fflush(stderr);
632     exit(1);
633   }
634 }
635 
636 SOCKET
set_fdset(struct listen_elt * list,fd_set * fdset)637 set_fdset(struct listen_elt *list, fd_set *fdset) {
638 
639   struct listen_elt *temp;
640   SOCKET max = INVALID_SOCKET;
641 
642   FD_ZERO(fdset);
643 
644   temp = list;
645 
646   if (debug) {
647     fprintf(where,
648 	    "%s: enter list %p fd_set %p\n",
649 	    __FUNCTION__,
650 	    list,
651 	    fdset);
652     fflush(where);
653   }
654 
655   while (temp) {
656     if (temp->fd > max)
657       max = temp->fd;
658 
659     if (debug) {
660       fprintf(where,
661 	      "setting %d in fdset\n",
662 	      temp->fd);
663       fflush(where);
664     }
665 
666     FD_SET(temp->fd,fdset);
667 
668     temp = temp->next;
669   }
670 
671   return max;
672 
673 }
674 
675 void
close_listens(struct listen_elt * list)676 close_listens(struct listen_elt *list) {
677   struct listen_elt *temp;
678 
679   if (debug) {
680     fprintf(where,
681 	    "%s: enter\n",
682 	    __FUNCTION__);
683     fflush(where);
684   }
685 
686   temp = list;
687 
688   while (temp) {
689     close(temp->fd);
690     temp = temp->next;
691   }
692 }
693 
694 static int
recv_passphrase()695 recv_passphrase() {
696 
697   /* may need to revisit the timeout. we only respond if there is an
698      error with receiving the passphrase */
699   if ((recv_request_timed_n(0,20) > 0) &&
700       (netperf_request.content.request_type == PASSPHRASE) &&
701       (!strcmp(passphrase,
702 	       (char *)netperf_request.content.test_specific_data))) {
703     /* it was okey dokey */
704     return 0;
705   }
706 #if defined(SEND_PASSPHRASE_RESPONSE)
707   netperf_response.content.response_type = PASSPHRASE;
708   netperf_response.content.serv_errno = 403;
709     snprintf((char *)netperf_response.content.test_specific_data,
710 	     sizeof(netperf_response.content.test_specific_data),
711 	     "Sorry, unable to match with required passphrase\n");
712   send_response_n(0);
713 #endif
714   fprintf(where,
715 	  "Unable to match required passphrase.  Closing control connection\n");
716   fflush(where);
717 
718   close(server_sock);
719   return -1;
720 }
721 
722 /* This routine implements the "main event loop" of the netperf server
723    code. Code above it will have set-up the control connection so it
724    can just merrily go about its business, which is to "schedule"
725    performance tests on the server.  */
726 
727 void
process_requests()728 process_requests()
729 {
730 
731   float	temp_rate;
732 
733   if (debug) {
734     fprintf(where,
735 	    "%s: enter\n",
736 	    __FUNCTION__);
737     fflush(where);
738   }
739 
740   /* if the netserver was started with a passphrase, look for it in
741      the first request to arrive.  if there is no passphrase in the
742      first request we will end-up dumping the control connection. raj
743      2012-01-23 */
744 
745   if ((passphrase != NULL)  && (recv_passphrase()))
746       return;
747 
748   while (1) {
749 
750     if (recv_request() <= 0) {
751       close(server_sock);
752       return;
753     }
754 
755     switch (netperf_request.content.request_type) {
756 
757     case DEBUG_ON:
758       netperf_response.content.response_type = DEBUG_OK;
759       if (!suppress_debug) {
760 	debug++;
761 
762 	if (debug == 1) {
763 	  /* we just flipped-on debugging, dump the request because
764 	     recv_request/recv_request_n will not have dumped it as its
765 	     dump_request() call is conditional on debug being set. raj
766 	     2011-07-08 */
767 	  dump_request();
768 	}
769       }
770 
771       send_response();
772       break;
773 
774     case DEBUG_OFF:
775       if (debug)
776 	debug--;
777       netperf_response.content.response_type = DEBUG_OK;
778       send_response();
779       /* we used to take the trouble to close the debug file, but SAF
780 	 asked a good question when he asked "Why?" and since I cannot
781 	 think of a good reason, I have removed the code. raj
782 	 2011-07-08 */
783       break;
784 
785     case DO_SYSINFO:
786       {
787 	netperf_response.content.response_type = SYSINFO_RESPONSE;
788 
789 	snprintf((char *)netperf_response.content.test_specific_data,
790 		 sizeof(netperf_response.content.test_specific_data),
791 		 "%c%s%c%s%c%s%c%s",
792 		 ',',
793 		 "Deprecated",
794 		 ','
795 ,		 "Deprecated",
796 		 ',',
797 		 "Deprecated",
798 		 ',',
799 		 "Deprecated");
800 
801 	send_response_n(0);
802 	break;
803       }
804 
805     case CPU_CALIBRATE:
806       netperf_response.content.response_type = CPU_CALIBRATE;
807       temp_rate = calibrate_local_cpu(0.0);
808       bcopy((char *)&temp_rate,
809 	    (char *)netperf_response.content.test_specific_data,
810 	    sizeof(temp_rate));
811       bcopy((char *)&lib_num_loc_cpus,
812 	    (char *)netperf_response.content.test_specific_data +
813 	            sizeof(temp_rate),
814 	    sizeof(lib_num_loc_cpus));
815       if (debug) {
816 	fprintf(where,
817 		"netserver: sending CPU information: rate is %g num cpu %d\n",
818 		temp_rate,
819 		lib_num_loc_cpus);
820 	fflush(where);
821       }
822 
823       /* we need the cpu_start, cpu_stop in the looper case to kill
824          the child proceses raj 7/95 */
825 
826 #ifdef USE_LOOPER
827       cpu_start(1);
828       cpu_stop(1,&temp_rate);
829 #endif /* USE_LOOPER */
830 
831       send_response();
832       break;
833 
834     case DO_TCP_STREAM:
835       recv_tcp_stream();
836       break;
837 
838     case DO_TCP_MAERTS:
839       recv_tcp_maerts();
840       break;
841 
842     case DO_TCP_RR:
843       recv_tcp_rr();
844       break;
845 
846     case DO_TCP_CRR:
847       recv_tcp_conn_rr();
848       break;
849 
850     case DO_TCP_CC:
851       recv_tcp_cc();
852       break;
853 
854 #ifdef DO_1644
855     case DO_TCP_TRR:
856       recv_tcp_tran_rr();
857       break;
858 #endif /* DO_1644 */
859 
860 #ifdef DO_NBRR
861     case DO_TCP_NBRR:
862       recv_tcp_nbrr();
863       break;
864 #endif /* DO_NBRR */
865 
866     case DO_UDP_STREAM:
867       recv_udp_stream();
868       break;
869 
870     case DO_UDP_RR:
871       recv_udp_rr();
872       break;
873 
874 #ifdef WANT_DLPI
875 
876     case DO_DLPI_CO_RR:
877       recv_dlpi_co_rr();
878       break;
879 
880     case DO_DLPI_CL_RR:
881       recv_dlpi_cl_rr();
882       break;
883 
884     case DO_DLPI_CO_STREAM:
885       recv_dlpi_co_stream();
886       break;
887 
888     case DO_DLPI_CL_STREAM:
889       recv_dlpi_cl_stream();
890       break;
891 
892 #endif /* WANT_DLPI */
893 
894 #ifdef WANT_UNIX
895 
896     case DO_STREAM_STREAM:
897       recv_stream_stream();
898       break;
899 
900     case DO_STREAM_RR:
901       recv_stream_rr();
902       break;
903 
904     case DO_DG_STREAM:
905       recv_dg_stream();
906       break;
907 
908     case DO_DG_RR:
909       recv_dg_rr();
910       break;
911 
912 #endif /* WANT_UNIX */
913 
914 #ifdef WANT_XTI
915     case DO_XTI_TCP_STREAM:
916       recv_xti_tcp_stream();
917       break;
918 
919     case DO_XTI_TCP_RR:
920       recv_xti_tcp_rr();
921       break;
922 
923     case DO_XTI_UDP_STREAM:
924       recv_xti_udp_stream();
925       break;
926 
927     case DO_XTI_UDP_RR:
928       recv_xti_udp_rr();
929       break;
930 
931 #endif /* WANT_XTI */
932 
933 #ifdef WANT_SCTP
934     case DO_SCTP_STREAM:
935       recv_sctp_stream();
936       break;
937 
938     case DO_SCTP_STREAM_MANY:
939       recv_sctp_stream_1toMany();
940       break;
941 
942     case DO_SCTP_RR:
943       recv_sctp_rr();
944       break;
945 
946     case DO_SCTP_RR_MANY:
947       recv_sctp_rr_1toMany();
948       break;
949 #endif
950 
951 #ifdef WANT_SDP
952     case DO_SDP_STREAM:
953       recv_sdp_stream();
954       break;
955 
956     case DO_SDP_MAERTS:
957       recv_sdp_maerts();
958       break;
959 
960     case DO_SDP_RR:
961       recv_sdp_rr();
962       break;
963 #endif
964 
965 #ifdef WANT_OMNI
966     case DO_OMNI:
967       recv_omni();
968       break;
969 #endif
970 
971     case PASSPHRASE:
972       if (debug) {
973 	fprintf(where,"Ignoring an unexpected passphrase control message\n");
974 	fflush(where);
975       }
976       break;
977 
978     default:
979       fprintf(where,"unknown test number %d\n",
980 	      netperf_request.content.request_type);
981       fflush(where);
982       netperf_response.content.serv_errno=998;
983       send_response();
984       break;
985 
986     }
987   }
988 }
989 
990 /* the routine we call when we are going to spawn/fork/whatnot a child
991    process from the parent netserver daemon. raj 2011-07-08 */
992 void
spawn_child()993 spawn_child() {
994 
995 #if defined(HAVE_FORK)
996 
997   if (debug) {
998     fprintf(where,
999 	    "%s: enter\n",
1000 	    __FUNCTION__);
1001     fflush(where);
1002   }
1003 
1004 
1005   /* flush the usual suspects */
1006   fflush(stdin);
1007   fflush(stdout);
1008   fflush(stderr);
1009   fflush(where);
1010 
1011   signal(SIGCLD,SIG_IGN);
1012 
1013   switch (fork()) {
1014   case -1:
1015     fprintf(where,
1016 	    "%s: fork() error %s (errno %d)\n",
1017 	    __FUNCTION__,
1018 	    strerror(errno),
1019 	    errno);
1020     fflush(where);
1021     exit(1);
1022 
1023   case 0:
1024     /* we are the child, but not of inetd.  we don't know if we are
1025        the child of a daemonized parent or not, so we still need to
1026        worry about the standard file descriptors. raj 2011-07-11 */
1027 
1028     close_listens(listen_list);
1029     open_debug_file();
1030 
1031     child = 1;
1032     netperf_daemon = 0;
1033     process_requests();
1034     exit(0);
1035     break;
1036 
1037   default:
1038     /* we are the parent, not a great deal to do here, but we may
1039        want to reap some children */
1040 #if !defined(HAVE_SETSID)
1041     /* Only call "waitpid()" if "setsid()" is not used. */
1042     while(waitpid(-1, NULL, WNOHANG) > 0) {
1043       if (debug) {
1044 	fprintf(where,
1045 		"%s: reaped a child process\n",
1046 		__FUNCTION__);
1047       }
1048     }
1049 #endif
1050     break;
1051   }
1052 
1053 #elif defined(WIN32)
1054 
1055   BOOL b;
1056   char *cmdline;
1057   int cmdline_length;
1058   int cmd_index;
1059   PROCESS_INFORMATION pi;
1060   STARTUPINFO si;
1061   int i;
1062 
1063   if (debug) {
1064     fprintf(where,
1065 	    "%s: enter\n",
1066 	    __FUNCTION__);
1067     fflush(where);
1068   }
1069 
1070 
1071   /* create the cmdline array based on strlen(program) + 80 chars */
1072   cmdline_length = strlen(program) + 80;
1073   cmdline = malloc(cmdline_length + 1);  // +1 for trailing null
1074 
1075   memset(&si, 0 , sizeof(STARTUPINFO));
1076   si.cb = sizeof(STARTUPINFO);
1077 
1078   /* Pass the server_sock as stdin for the new process.  Hopefully
1079      this will continue to be created with the OBJ_INHERIT
1080      attribute. */
1081   si.hStdInput = (HANDLE)server_sock;
1082   si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1083   si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1084   si.dwFlags = STARTF_USESTDHANDLES;
1085 
1086   /* Build cmdline for child process */
1087   strcpy(cmdline, program);
1088   cmd_index = strlen(cmdline);
1089   if (verbosity > 1) {
1090     cmd_index += snprintf(&cmdline[cmd_index],
1091 			  cmdline_length - cmd_index,
1092 			  " -v %d",
1093 			  verbosity);
1094   }
1095   for (i=0; i < debug; i++) {
1096     cmd_index += snprintf(&cmdline[cmd_index],
1097 			  cmdline_length - cmd_index,
1098 			  " -d");
1099   }
1100   cmd_index += snprintf(&cmdline[cmd_index],
1101 			cmdline_length - cmd_index,
1102 			" -I %x",
1103 			(int)(UINT_PTR)server_sock);
1104 
1105   /* are these -i settings even necessary? the command line scanning
1106      does not seem to do anything with them */
1107   cmd_index += snprintf(&cmdline[cmd_index],
1108 			cmdline_length - cmd_index,
1109 			" -i %x",
1110 			(int)(UINT_PTR)server_control);
1111   cmd_index += snprintf(&cmdline[cmd_index],
1112 			cmdline_length - cmd_index,
1113 			" -i %x",
1114 			(int)(UINT_PTR)where);
1115 
1116   b = CreateProcess(NULL,    /* Application Name */
1117 		    cmdline,
1118 		    NULL,    /* Process security attributes */
1119 		    NULL,    /* Thread security attributes */
1120 		    TRUE,    /* Inherit handles */
1121 		    0,       /* Creation flags
1122 				PROCESS_QUERY_INFORMATION,  */
1123 		    NULL,    /* Enviornment */
1124 		    NULL,    /* Current directory */
1125 		    &si,     /* StartupInfo */
1126 		    &pi);
1127   if (!b)
1128     {
1129       perror("CreateProcessfailure: ");
1130       free(cmdline); /* even though we exit :) */
1131       exit(1);
1132     }
1133 
1134   /* We don't need the thread or process handles any more;
1135      let them go away on their own timeframe. */
1136 
1137   CloseHandle(pi.hThread);
1138   CloseHandle(pi.hProcess);
1139 
1140   /* the caller/parent will close server_sock */
1141 
1142   free(cmdline);
1143 
1144 #else
1145 
1146   fprintf(where,
1147 	  "%s called on platform which cannot spawn children\n",
1148 	  __FUNCTION__);
1149   fflush(where);
1150   exit(1);
1151 
1152 #endif /* HAVE_FORK */
1153 }
1154 
1155 void
accept_connection(SOCKET listen_fd)1156 accept_connection(SOCKET listen_fd) {
1157 
1158   struct sockaddr_storage peeraddr;
1159   netperf_socklen_t peeraddrlen;
1160 #if defined(SO_KEEPALIVE)
1161   int on = 1;
1162 #endif
1163 
1164   if (debug) {
1165     fprintf(where,
1166 	    "%s: enter\n",
1167 	    __FUNCTION__);
1168     fflush(where);
1169   }
1170 
1171   peeraddrlen = sizeof(peeraddr);
1172 
1173   /* while server_control is only used by the WIN32 path, but why
1174      bother ifdef'ing it?  and besides, do we *really* need knowledge
1175      of server_control in the WIN32 case? do we have to tell the
1176      child about *all* the listen endpoints? raj 2011-07-08 */
1177   server_control = listen_fd;
1178 
1179   if ((server_sock = accept(listen_fd,
1180 			   (struct sockaddr *)&peeraddr,
1181 			    &peeraddrlen)) == INVALID_SOCKET) {
1182     fprintf(where,
1183 	    "%s: accept failure: %s (errno %d)\n",
1184 	    __FUNCTION__,
1185 	    strerror(errno),
1186 	    errno);
1187     fflush(where);
1188     exit(1);
1189   }
1190 
1191 #if defined(SO_KEEPALIVE)
1192   /* we are not terribly concerned if this does not work, it is merely
1193      duct tape added to belts and suspenders. raj 2011-07-08 */
1194   setsockopt(server_sock,
1195 	     SOL_SOCKET,
1196 	     SO_KEEPALIVE,
1197 	     (const char *)&on,
1198 	     sizeof(on));
1199 #endif
1200 
1201   if (spawn_on_accept) {
1202     spawn_child();
1203     /* spawn_child() only returns when we are the parent */
1204     close(server_sock);
1205   }
1206   else {
1207     process_requests();
1208   }
1209 }
1210 
1211 void
accept_connections()1212 accept_connections() {
1213 
1214   fd_set read_fds, write_fds, except_fds;
1215   SOCKET high_fd, candidate;
1216   int num_ready;
1217 
1218   if (debug) {
1219     fprintf(where,
1220 	    "%s: enter\n",
1221 	    __FUNCTION__);
1222     fflush(where);
1223   }
1224 
1225   while (1) {
1226 
1227     FD_ZERO(&write_fds);
1228     FD_ZERO(&except_fds);
1229     high_fd = set_fdset(listen_list,&read_fds);
1230 
1231 #if !defined(WIN32)
1232     num_ready = select(high_fd + 1,
1233 #else
1234     num_ready = select(1,
1235 #endif
1236 		       &read_fds,
1237 		       &write_fds,
1238 		       &except_fds,
1239 		       NULL);
1240 
1241     if (num_ready < 0) {
1242       fprintf(where,
1243 	      "%s: select failure: %s (errno %d)\n",
1244 	      __FUNCTION__,
1245 	      strerror(errno),
1246 	      errno);
1247       fflush(where);
1248       exit(1);
1249     }
1250 
1251     /* try to keep things simple */
1252     candidate = 0;
1253     while ((num_ready) && (candidate <= high_fd)) {
1254       if (FD_ISSET(candidate,&read_fds)) {
1255 	accept_connection(candidate);
1256 	FD_CLR(candidate,&read_fds);
1257 	num_ready--;
1258       }
1259       else {
1260 	candidate++;
1261       }
1262     }
1263   }
1264 }
1265 
1266 #ifndef WIN32
1267 #define SERVER_ARGS "DdfhL:n:Np:v:VZ:46"
1268 #else
1269 #define SERVER_ARGS "DdfhL:n:Np:v:VZ:46I:i:"
1270 #endif
1271 void
scan_netserver_args(int argc,char * argv[])1272 scan_netserver_args(int argc, char *argv[]) {
1273 
1274   int c;
1275   char arg1[BUFSIZ], arg2[BUFSIZ];
1276 
1277   if (debug) {
1278     fprintf(where,
1279 	    "%s: enter\n",
1280 	    __FUNCTION__);
1281     fflush(where);
1282   }
1283 
1284   while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF){
1285     switch (c) {
1286     case '?':
1287     case 'h':
1288       print_netserver_usage();
1289       exit(1);
1290     case 'd':
1291       debug++;
1292       suppress_debug = 0;
1293       break;
1294     case 'D':
1295       /* perhaps one of these days we'll take an argument */
1296       want_daemonize = 0;
1297       not_inetd = 1;
1298       break;
1299     case 'f':
1300       spawn_on_accept = 0;
1301       not_inetd = 1;
1302       break;
1303 #ifdef WIN32
1304     case 'I':
1305       child = TRUE;
1306       break;
1307     case 'i':
1308       break;
1309 #endif
1310     case 'L':
1311       not_inetd = 1;
1312       break_args_explicit(optarg,arg1,arg2);
1313       if (arg1[0]) {
1314 	strncpy(local_host_name,arg1,sizeof(local_host_name));
1315       }
1316       if (arg2[0]) {
1317 	local_address_family = parse_address_family(arg2);
1318       }
1319       break;
1320     case 'n':
1321       shell_num_cpus = atoi(optarg);
1322       if (shell_num_cpus > MAXCPUS) {
1323 	fprintf(stderr,
1324 		"netserver: This version can only support %d CPUs. Please"
1325 		"increase MAXCPUS in netlib.h and recompile.\n",
1326 		MAXCPUS);
1327 	fflush(stderr);
1328 	exit(1);
1329       }
1330       break;
1331     case 'N':
1332       suppress_debug = 1;
1333       debug = 0;
1334       break;
1335     case 'p':
1336       /* we want to open a listen socket at a specified port number */
1337       strncpy(listen_port,optarg,sizeof(listen_port));
1338       not_inetd = 1;
1339       break;
1340     case 'Z':
1341       /* only copy as much of the passphrase as could fit in the
1342 	 test-specific portion of a control message. Windows does not
1343 	 seem to have a strndup() so just malloc and strncpy it.  we
1344 	 weren't checking the strndup() return so won't bother with
1345 	 checking malloc(). we will though make certain we only
1346 	 allocated it once in the event that someone puts -Z on the
1347 	 command line more than once */
1348       if (passphrase == NULL)
1349 	passphrase = malloc(sizeof(netperf_request.content.test_specific_data));
1350       strncpy(passphrase,
1351 	      optarg,
1352 	      sizeof(netperf_request.content.test_specific_data));
1353       passphrase[sizeof(netperf_request.content.test_specific_data) - 1] = '\0';
1354       break;
1355     case '4':
1356       local_address_family = AF_INET;
1357       break;
1358     case '6':
1359 #if defined(AF_INET6)
1360       local_address_family = AF_INET6;
1361 #else
1362       local_address_family = AF_UNSPEC;
1363 #endif
1364       break;
1365     case 'v':
1366       /* say how much to say */
1367       verbosity = atoi(optarg);
1368       break;
1369     case 'V':
1370       printf("Netperf version %s\n",NETPERF_VERSION);
1371       exit(0);
1372       break;
1373 
1374     }
1375   }
1376 }
1377 
1378 void
daemonize()1379 daemonize() {
1380 #if defined(HAVE_FORK)
1381 
1382   if (debug) {
1383     fprintf(where,
1384 	    "%s: enter\n",
1385 	    __FUNCTION__);
1386     fflush(where);
1387   }
1388 
1389   /* flush the usual suspects */
1390   fflush(stdin);
1391   fflush(stdout);
1392   fflush(stderr);
1393 
1394   switch (fork()) {
1395   case -1:
1396     fprintf(stderr,
1397 	    "%s: fork() error %s (errno %d)\n",
1398 	    __FUNCTION__,
1399 	    strerror(errno),
1400 	    errno);
1401     fflush(stderr);
1402     exit(1);
1403   case 0:
1404 
1405     /* perhaps belt and suspenders, but if we dump core, perhaps
1406        better to do so here. we won't worry about the call being
1407        successful though. raj 2011-07-08 */
1408     chdir(DEBUG_LOG_FILE_DIR);
1409 
1410     /* we are the child. we should get a new "where" to match our new
1411        pid */
1412 
1413     open_debug_file();
1414 
1415 #ifdef HAVE_SETSID
1416       setsid();
1417 #else
1418       setpgrp();
1419 #endif /* HAVE_SETSID */
1420 
1421       signal(SIGCLD, SIG_IGN);
1422 
1423       /* ok, we can start accepting control connections now */
1424       accept_connections();
1425 
1426   default:
1427     /* we are the parent, nothing to do but exit? */
1428     exit(0);
1429   }
1430 
1431 #else
1432   fprintf(where,
1433 	  "%s called on platform which cannot daemonize\n",
1434 	  __FUNCTION__);
1435   fflush(where);
1436   exit(1);
1437 #endif /* HAVE_FORK */
1438 }
1439 
1440 static void
check_if_inetd()1441 check_if_inetd() {
1442 
1443   if (debug) {
1444     fprintf(where,
1445 	    "%s: enter\n",
1446 	    __FUNCTION__);
1447     fflush(where);
1448   }
1449 
1450   if (not_inetd) {
1451     return;
1452   }
1453   else {
1454 #if !defined(WIN32) && !defined(__VMS)
1455     struct sockaddr_storage name;
1456     netperf_socklen_t namelen;
1457 
1458     namelen = sizeof(name);
1459     if (getsockname(0,
1460 		    (struct sockaddr *)&name,
1461 		    &namelen) == SOCKET_ERROR) {
1462       not_inetd = 1;
1463     }
1464     else {
1465       not_inetd = 0;
1466       child = 1;
1467     }
1468 #endif
1469   }
1470 }
1471 
1472 /* OK, so how does all this work you ask?  Well, we are in a maze of
1473    twisty options, all different.  Netserver can be invoked as a child
1474    of inetd or the VMS auxiliary server process, or a parent netserver
1475    process. In those cases, we could/should follow the "child"
1476    path. However, there are really two "child" paths through the
1477    netserver code.
1478 
1479    When this netserver is a child of a parent netserver in the
1480    case of *nix, the child process will be created by a
1481    spawn_child_process() in accept_connections() and will not hit the
1482    "child" path here in main().
1483 
1484    When this netserver is a child of a parent netserver in the case of
1485    windows, the child process will have been spawned via a
1486    Create_Process() call in spawn_child_process() in
1487    accept_connections, but will flow through here again. We rely on
1488    the scan_netserver_args() call to have noticed the magic option
1489    that tells us we are a child process.
1490 
1491    When this netserver is launched from the command line we will first
1492    set-up the listen endpoint(s) for the controll connection.  At that
1493    point we decide if we want to and can become our own daemon, or
1494    stay attached to the "terminal."  When this happens under *nix, we
1495    will again take a fork() path via daemonize() and will not come
1496    back through main().  If we ever learn how to become our own daemon
1497    under Windows, we will undoubtedly take a Create_Process() path
1498    again and will come through main() once again - that is what the
1499    "daemon" case here is all about.
1500 
1501    It is hoped that this is all much clearer than the old spaghetti
1502    code that netserver had become.  raj 2011-07-11 */
1503 
1504 
1505 int _cdecl
main(int argc,char * argv[])1506 main(int argc, char *argv[]) {
1507 
1508 #ifdef WIN32
1509   WSADATA	wsa_data ;
1510 
1511   /* Initialize the winsock lib do we still want version 2.2? */
1512   if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){
1513     printf("WSAStartup() failed : %lu\n", GetLastError()) ;
1514     return -1 ;
1515   }
1516 #endif /* WIN32 */
1517 
1518   /* Save away the program name */
1519   program = (char *)malloc(strlen(argv[0]) + 1);
1520   if (program == NULL) {
1521     printf("malloc for program name failed!\n");
1522     return -1 ;
1523   }
1524   strcpy(program, argv[0]);
1525 
1526   init_netserver_globals();
1527 
1528   netlib_init();
1529 
1530   strncpy(local_host_name,"",sizeof(local_host_name));
1531   local_address_family = AF_UNSPEC;
1532   strncpy(listen_port,TEST_PORT,sizeof(listen_port));
1533 
1534   scan_netserver_args(argc, argv);
1535 
1536   check_if_inetd();
1537 
1538   if (child) {
1539     /* we are the child of either an inetd or parent netserver via
1540        spawning (Windows) rather than fork()ing. if we were fork()ed
1541        we would not be coming through this way. set_server_sock() must
1542        be called before open_debug_file() or there is a chance that
1543        we'll toast the descriptor when we do not wish it. */
1544     set_server_sock();
1545     open_debug_file();
1546     process_requests();
1547   }
1548   else if (daemon_parent) {
1549     /* we are the parent daemonized netserver
1550        process. accept_connections() will decide if we want to spawn a
1551        child process */
1552     accept_connections();
1553   }
1554   else {
1555     /* we are the top netserver process, so we have to create the
1556        listen endpoint(s) and decide if we want to daemonize */
1557     setup_listens(local_host_name,listen_port,local_address_family);
1558     if (want_daemonize) {
1559       daemonize();
1560     }
1561     accept_connections();
1562   }
1563 
1564   unlink_empty_debug_file();
1565 
1566 #ifdef WIN32
1567   WSACleanup();
1568 #endif
1569 
1570   return 0;
1571 
1572 }
1573