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