The Android Open Source Project | 02fb0ac | 2009-03-03 19:30:07 -0800 | [diff] [blame] | 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 |
| 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 |
| 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 |
| 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 |
| 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) { |
Mark Salyzyn | 1a75dd0 | 2014-04-25 14:43:58 -0700 | [diff] [blame] | 816 | printf("malloc(%zu) failed!\n", strlen(argv[0]) + 1); |
The Android Open Source Project | 02fb0ac | 2009-03-03 19:30:07 -0800 | [diff] [blame] | 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 | } |