home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / netper21.zip / nettest_bsd.c < prev    next >
C/C++ Source or Header  |  1996-02-21  |  252KB  |  8,073 lines

  1. #ifndef lint
  2. char    nettest_id[]="\
  3. @(#)nettest_bsd.c (c) Copyright 1993, 1994 Hewlett-Packard Co. Version 2.1";
  4. #else
  5. #define DIRTY
  6. #define HISTOGRAM
  7. #define INTERVALS
  8. #endif /* lint */
  9.  
  10. /****************************************************************/
  11. /*                                */
  12. /*    nettest_bsd.c                        */
  13. /*                                */
  14. /*      the BSD sockets parsing routine...                      */
  15. /*       ...with the addition of Windows NT, this is now also   */
  16. /*          a Winsock test... sigh :)                           */
  17. /*                                                              */
  18. /*      scan_sockets_args()                                     */
  19. /*                                                              */
  20. /*    the actual test routines...                */
  21. /*                                */
  22. /*    send_tcp_stream()    perform a tcp stream test    */
  23. /*    recv_tcp_stream()                    */
  24. /*    send_tcp_rr()        perform a tcp request/response    */
  25. /*    recv_tcp_rr()                        */
  26. /*      send_tcp_conn_rr()      an RR test including connect    */
  27. /*      recv_tcp_conn_rr()                                      */
  28. /*    send_udp_stream()    perform a udp stream test    */
  29. /*    recv_udp_stream()                    */
  30. /*    send_udp_rr()        perform a udp request/response    */
  31. /*    recv_udp_rr()                        */
  32. /*    loc_cpu_rate()        determine the local cpu maxrate */
  33. /*    rem_cpu_rate()        find the remote cpu maxrate    */
  34. /*                                */
  35. /****************************************************************/
  36.      
  37. #include <sys/types.h>
  38. #include <fcntl.h>
  39. #include <errno.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include <time.h>
  44. #ifdef NOSTDLIBH
  45. #include <malloc.h>
  46. #else /* NOSTDLIBH */
  47. #include <stdlib.h>
  48. #endif /* NOSTDLIBH */
  49.  
  50. #ifndef WIN32
  51. #include <sys/ipc.h>
  52. #include <unistd.h>
  53. #include <sys/socket.h>
  54. #include <netinet/in.h>
  55. #include <netinet/tcp.h>
  56. #include <netdb.h>
  57. #else /* WIN32 */
  58. #include <process.h>
  59. #include <windows.h>
  60. #include <winsock.h>
  61. #define close(x)    closesocket(x)
  62. #endif /* WIN32 */
  63.  
  64. #include "netlib.h"
  65. #include "netsh.h"
  66. #include "nettest_bsd.h"
  67.  
  68. #ifdef HISTOGRAM
  69. #include "hist.h"
  70. #endif /* HISTOGRAM */
  71.  
  72.  
  73.  
  74.  /* these variables are specific to the BSD sockets tests. declare */
  75.  /* them static to make them global only to this file. */
  76.  
  77. static int    
  78.   rss_size,        /* remote socket send buffer size    */
  79.   rsr_size,        /* remote socket recv buffer size    */
  80.   lss_size,        /* local  socket send buffer size     */
  81.   lsr_size,        /* local  socket recv buffer size     */
  82.   req_size = 1,        /* request size                       */
  83.   rsp_size = 1,        /* response size            */
  84.   send_size,        /* how big are individual sends        */
  85.   recv_size;        /* how big are individual receives    */
  86.  
  87. static  int confidence_iteration;
  88. static  char  local_cpu_method;
  89. static  char  remote_cpu_method;
  90.  
  91.  /* these will control the width of port numbers we try to use in the */
  92.  /* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
  93. static int client_port_min = 5000;
  94. static int client_port_max = 65535;
  95.  
  96.  /* different options for the sockets                */
  97.  
  98. int
  99.   loc_nodelay,        /* don't/do use NODELAY    locally        */
  100.   rem_nodelay,        /* don't/do use NODELAY remotely    */
  101.   loc_sndavoid,        /* avoid send copies locally        */
  102.   loc_rcvavoid,        /* avoid recv copies locally        */
  103.   rem_sndavoid,        /* avoid send copies remotely        */
  104.   rem_rcvavoid;        /* avoid recv_copies remotely        */
  105.  
  106. #ifdef HISTOGRAM
  107. static struct timeval time_one;
  108. static struct timeval time_two;
  109. static HIST time_hist;
  110. #endif /* HISTOGRAM */
  111.  
  112.  
  113. char sockets_usage[] = "\n\
  114. Usage: netperf [global options] -- [test options] \n\
  115. \n\
  116. TCP/UDP BSD Sockets Test Options:\n\
  117.     -D [L][,R]        Set TCP_NODELAY locally and/or remotely (TCP_*)\n\
  118.     -h                Display this text\n\
  119.     -m bytes          Set the send size (TCP_STREAM, UDP_STREAM)\n\
  120.     -M bytes          Set the recv size (TCP_STREAM, UDP_STREAM)\n\
  121.     -p min[,max]      Set the min/max port numbers for TCP_CRR, TCP_TRR\n\
  122.     -r bytes          Set request size (TCP_RR, UDP_RR)\n\
  123.     -R bytes          Set response size (TCP_RR, UDP_RR)\n\
  124.     -s send[,recv]    Set local socket send/recv buffer sizes\n\
  125.     -S send[,recv]    Set remote socket send/recv buffer sizes\n\
  126. \n\
  127. For those options taking two parms, at least one must be specified;\n\
  128. specifying one value without a comma will set both parms to that\n\
  129. value, specifying a value with a leading comma will set just the second\n\
  130. parm, a value with a trailing comma will set just the first. To set\n\
  131. each parm to unique values, specify both and separate them with a\n\
  132. comma.\n"; 
  133.      
  134.  
  135.  /* This routine is intended to retrieve interesting aspects of tcp */
  136.  /* for the data connection. at first, it attempts to retrieve the */
  137.  /* maximum segment size. later, it might be modified to retrieve */
  138.  /* other information, but it must be information that can be */
  139.  /* retrieved quickly as it is called during the timing of the test. */
  140.  /* for that reason, a second routine may be created that can be */
  141.  /* called outside of the timing loop */
  142. static
  143. void
  144. get_tcp_info(socket, mss)
  145.      int socket;
  146.      int *mss;
  147. {
  148.  
  149. #ifdef TCP_MAXSEG
  150.   int sock_opt_len;
  151.  
  152.   sock_opt_len = sizeof(int);
  153.   if (getsockopt(socket,
  154.          getprotobyname("tcp")->p_proto,    
  155.          TCP_MAXSEG,
  156.          (char *)mss,
  157.          &sock_opt_len) < 0) {
  158.     fprintf(where,
  159.         "netperf: get_tcp_info: getsockopt TCP_MAXSEG: errno %d\n",
  160.         errno);
  161.     fflush(where);
  162.     lss_size = -1;
  163.   }
  164. #else
  165.   *mss = -1;
  166. #endif /* TCP_MAXSEG */
  167. }
  168.  
  169.  
  170.  /* This routine will create a data (listen) socket with the apropriate */
  171.  /* options set and return it to the caller. this replaces all the */
  172.  /* duplicate code in each of the test routines and should help make */
  173.  /* things a little easier to understand. since this routine can be */
  174.  /* called by either the netperf or netserver programs, all output */
  175.  /* should be directed towards "where." family is generally AF_INET, */
  176.  /* and type will be either SOCK_STREAM or SOCK_DGRAM */
  177. static
  178. int
  179. create_data_socket(family, type)
  180.      int family;
  181.      int type;
  182. {
  183.  
  184.   int temp_socket;
  185.   int one;
  186.   int sock_opt_len;
  187.  
  188.   /*set up the data socket                        */
  189.   temp_socket = socket(family, 
  190.                type,
  191.                0);
  192.   
  193. #ifdef WIN32
  194.   if (temp_socket == INVALID_SOCKET){
  195. #else
  196.   if (temp_socket < 0){
  197. #endif /* WIN32 */
  198.     fprintf(where,
  199.         "netperf: create_data_socket: socket: %d\n",
  200.         errno);
  201.     fflush(where);
  202.     exit(1);
  203.   }
  204.   
  205.   if (debug) {
  206.     fprintf(where,"create_data_socket: socket %d obtained...\n",temp_socket);
  207.     fflush(where);
  208.   }
  209.   
  210.   /* Modify the local socket size. The reason we alter the send buffer */
  211.   /* size here rather than when the connection is made is to take care */
  212.   /* of decreases in buffer size. Decreasing the window size after */
  213.   /* connection establishment is a TCP no-no. Also, by setting the */
  214.   /* buffer (window) size before the connection is established, we can */
  215.   /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
  216.   /* the minimum receive buffer size at each half of the connection. */
  217.   /* This is why we are altering the receive buffer size on the sending */
  218.   /* size of a unidirectional transfer. If the user has not requested */
  219.   /* that the socket buffers be altered, we will try to find-out what */
  220.   /* their values are. If we cannot touch the socket buffer in any way, */
  221.   /* we will set the values to -1 to indicate that.  */
  222.   
  223. #ifdef SO_SNDBUF
  224.   if (lss_size > 0) {
  225.     if(setsockopt(temp_socket, SOL_SOCKET, SO_SNDBUF,
  226.           (char *)&lss_size, sizeof(int)) < 0) {
  227.       fprintf(where,
  228.           "netperf: create_data_socket: SO_SNDBUF option: errno %d\n",
  229.           errno);
  230.       fflush(where);
  231.       exit(1);
  232.     }
  233.     if (debug > 1) {
  234.       fprintf(where,
  235.           "netperf: create_data_socket: SO_SNDBUF of %d requested.\n",
  236.           lss_size);
  237.       fflush(where);
  238.     }
  239.   }
  240.   if (lsr_size > 0) {
  241.     if(setsockopt(temp_socket, SOL_SOCKET, SO_RCVBUF,
  242.           (char *)&lsr_size, sizeof(int)) < 0) {
  243.       fprintf(where,
  244.           "netperf: create_data_socket: SO_RCVBUF option: errno %d\n",
  245.           errno);
  246.       fflush(where);
  247.       exit(1);
  248.     }
  249.     if (debug > 1) {
  250.       fprintf(where,
  251.           "netperf: create_data_socket: SO_SNDBUF of %d requested.\n",
  252.           lss_size);
  253.       fflush(where);
  254.     }
  255.   }
  256.   
  257.   
  258.   /* Now, we will find-out what the size actually became, and report */
  259.   /* that back to the user. If the call fails, we will just report a -1 */
  260.   /* back to the initiator for the recv buffer size. */
  261.   
  262.   sock_opt_len = sizeof(int);
  263.   if (getsockopt(temp_socket,
  264.          SOL_SOCKET,    
  265.          SO_SNDBUF,
  266.          (char *)&lss_size,
  267.          &sock_opt_len) < 0) {
  268.     fprintf(where,
  269.         "netperf: create_data_socket: getsockopt SO_SNDBUF: errno %d\n",
  270.         errno);
  271.     fflush(where);
  272.     lss_size = -1;
  273.   }
  274.   if (getsockopt(temp_socket,
  275.          SOL_SOCKET,    
  276.          SO_RCVBUF,
  277.          (char *)&lsr_size,
  278.          &sock_opt_len) < 0) {
  279.     fprintf(where,
  280.         "netperf: create_data_socket: getsockopt SO_SNDBUF: errno %d\n",
  281.         errno);
  282.     fflush(where);
  283.     lsr_size = -1;
  284.   }
  285.   
  286.   if (debug) {
  287.     fprintf(where,
  288.         "netperf: create_data_socket: socket sizes determined...\n");
  289.     fprintf(where,
  290.         "                       send: %d recv: %d\n",
  291.         lss_size,lsr_size);
  292.     fflush(where);
  293.   }
  294.   
  295. #else /* SO_SNDBUF */
  296.   
  297.   lss_size = -1;
  298.   lsr_size = -1;
  299.   
  300. #endif /* SO_SNDBUF */
  301.  
  302.   /* now, we may wish to enable the copy avoidance features on the */
  303.   /* local system. of course, this may not be possible... */
  304.   
  305. #ifdef SO_RCV_COPYAVOID
  306.   if (loc_rcvavoid) {
  307.     if (setsockopt(temp_socket,
  308.            SOL_SOCKET,
  309.            SO_RCV_COPYAVOID,
  310.            &loc_rcvavoid,
  311.            sizeof(int)) < 0) {
  312.       fprintf(where,
  313.           "netperf: create_data_socket: Could not enable receive copy avoidance");
  314.       fflush(where);
  315.       loc_rcvavoid = 0;
  316.     }
  317.   }
  318. #else
  319.   /* it wasn't compiled in... */
  320.   loc_rcvavoid = 0;
  321. #endif /* SO_RCV_COPYAVOID */
  322.  
  323. #ifdef SO_SND_COPYAVOID
  324.   if (loc_sndavoid) {
  325.     if (setsockopt(temp_socket,
  326.            SOL_SOCKET,
  327.            SO_SND_COPYAVOID,
  328.            &loc_sndavoid,
  329.            sizeof(int)) < 0) {
  330.       fprintf(where,
  331.           "netperf: create_data_socket: Could not enable send copy avoidance");
  332.       fflush(where);
  333.       loc_sndavoid = 0;
  334.     }
  335.   }
  336. #else
  337.   /* it was not compiled in... */
  338.   loc_sndavoid = 0;
  339. #endif
  340.   
  341.   /* Now, we will see about setting the TCP_NO_DELAY flag on the local */
  342.   /* socket. We will only do this for those systems that actually */
  343.   /* support the option. If it fails, note the fact, but keep going. */
  344.   /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
  345.   /* will cause an error to be displayed */
  346.   
  347. #ifdef TCP_NODELAY
  348.   if (loc_nodelay) {
  349.     one = 1;
  350.     if(setsockopt(temp_socket,
  351.           getprotobyname("tcp")->p_proto,
  352.           TCP_NODELAY,
  353.           (char *)&one,
  354.           sizeof(one)) < 0) {
  355.       fprintf(where,
  356.           "netperf: create_data_socket: nodelay: errno %d\n",
  357.           errno);
  358.       fflush(where);
  359.     }
  360.     
  361.     if (debug > 1) {
  362.       fprintf(where,
  363.           "netperf: create_data_socket: TCP_NODELAY requested...\n");
  364.       fflush(where);
  365.     }
  366.   }
  367. #else /* TCP_NODELAY */
  368.   
  369.   loc_nodelay = 0;
  370.   
  371. #endif /* TCP_NODELAY */
  372.  
  373.   return(temp_socket);
  374.  
  375. }
  376.  
  377. #ifdef KLUDGE_SOCKET_OPTIONS
  378.  
  379.  
  380.  /* This routine is for those BROKEN systems which do not correctly */
  381.  /* pass socket attributes through calls such as accept(). It should */
  382.  /* only be called for those broken systems. I *really* don't want to */
  383.  /* have this, but even broken systems must be measured. raj 11/95 */
  384. void
  385. kludge_socket_options(temp_socket)
  386. int temp_socket;
  387. {
  388. #ifdef SO_SNDBUF
  389.   if (lss_size > 0) {
  390.     if(setsockopt(temp_socket, SOL_SOCKET, SO_SNDBUF,
  391.           (char *)&lss_size, sizeof(int)) < 0) {
  392.       fprintf(where,
  393.           "netperf: kludge_socket_options: SO_SNDBUF option: errno %d\n",
  394.           errno);
  395.       fflush(where);
  396.       exit(1);
  397.     }
  398.     if (debug > 1) {
  399.       fprintf(where,
  400.           "netperf: kludge_socket_options: SO_SNDBUF of %d requested.\n",
  401.           lss_size);
  402.       fflush(where);
  403.     }
  404.   }
  405.   if (lsr_size > 0) {
  406.     if(setsockopt(temp_socket, SOL_SOCKET, SO_RCVBUF,
  407.           (char *)&lsr_size, sizeof(int)) < 0) {
  408.       fprintf(where,
  409.           "netperf: kludge_socket_options: SO_RCVBUF option: errno %d\n",
  410.           errno);
  411.       fflush(where);
  412.       exit(1);
  413.     }
  414.     if (debug > 1) {
  415.       fprintf(where,
  416.           "netperf: kludge_socket_options: SO_SNDBUF of %d requested.\n",
  417.           lss_size);
  418.       fflush(where);
  419.     }
  420.   }
  421.   
  422.   
  423.   /* Now, we will find-out what the size actually became, and report */
  424.   /* that back to the user. If the call fails, we will just report a -1 */
  425.   /* back to the initiator for the recv buffer size. */
  426.   
  427.   sock_opt_len = sizeof(int);
  428.   if (getsockopt(temp_socket,
  429.          SOL_SOCKET,    
  430.          SO_SNDBUF,
  431.          (char *)&lss_size,
  432.          &sock_opt_len) < 0) {
  433.     fprintf(where,
  434.         "netperf: kludge_socket_options: getsockopt SO_SNDBUF: errno %d\n",
  435.         errno);
  436.     fflush(where);
  437.     lss_size = -1;
  438.   }
  439.   if (getsockopt(temp_socket,
  440.          SOL_SOCKET,    
  441.          SO_RCVBUF,
  442.          (char *)&lsr_size,
  443.          &sock_opt_len) < 0) {
  444.     fprintf(where,
  445.         "netperf: kludge_socket_options: getsockopt SO_SNDBUF: errno %d\n",
  446.         errno);
  447.     fflush(where);
  448.     lsr_size = -1;
  449.   }
  450.   
  451.   if (debug) {
  452.     fprintf(where,
  453.         "netperf: kludge_socket_options: socket sizes determined...\n");
  454.     fprintf(where,
  455.         "                       send: %d recv: %d\n",
  456.         lss_size,lsr_size);
  457.     fflush(where);
  458.   }
  459.   
  460. #else /* SO_SNDBUF */
  461.   
  462.   lss_size = -1;
  463.   lsr_size = -1;
  464.   
  465. #endif /* SO_SNDBUF */
  466.  
  467.   /* now, we may wish to enable the copy avoidance features on the */
  468.   /* local system. of course, this may not be possible... */
  469.   /* those calls were only valid for HP-UX, and I know that HP-UX is */
  470.   /* written correctly, and so we do not need to include those calls */
  471.   /* in this kludgy routine. raj 11/95 */
  472.  
  473.   
  474.   /* Now, we will see about setting the TCP_NODELAY flag on the local */
  475.   /* socket. We will only do this for those systems that actually */
  476.   /* support the option. If it fails, note the fact, but keep going. */
  477.   /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
  478.   /* will cause an error to be displayed */
  479.   
  480. #ifdef TCP_NODELAY
  481.   if (loc_nodelay) {
  482.     one = 1;
  483.     if(setsockopt(temp_socket,
  484.           getprotobyname("tcp")->p_proto,
  485.           TCP_NODELAY,
  486.           (char *)&one,
  487.           sizeof(one)) < 0) {
  488.       fprintf(where,"netperf: kludge_socket_options: nodelay: errno %d\n",
  489.           errno);
  490.       fflush(where);
  491.     }
  492.     
  493.     if (debug > 1) {
  494.       fprintf(where,
  495.           "netperf: kludge_socket_options: TCP_NODELAY requested...\n");
  496.       fflush(where);
  497.     }
  498.   }
  499. #else /* TCP_NODELAY */
  500.   
  501.   loc_nodelay = 0;
  502.   
  503. #endif /* TCP_NODELAY */
  504.  
  505.   }
  506.  
  507. #endif /* KLUDGE_SOCKET_OPTIONS */
  508.  
  509.  
  510.  
  511.  
  512.  
  513. /* This routine implements the TCP unidirectional data transfer test */
  514. /* (a.k.a. stream) for the sockets interface. It receives its */
  515. /* parameters via global variables from the shell and writes its */
  516. /* output to the standard output. */
  517.  
  518.  
  519. void 
  520. send_tcp_stream(remote_host)
  521. char    remote_host[];
  522. {
  523.   
  524.   char *tput_title = "\
  525. Recv   Send    Send                          \n\
  526. Socket Socket  Message  Elapsed              \n\
  527. Size   Size    Size     Time     Throughput  \n\
  528. bytes  bytes   bytes    secs.    %s/sec  \n\n";
  529.   
  530.   char *tput_fmt_0 =
  531.     "%7.2f\n";
  532.   
  533.   char *tput_fmt_1 =
  534.     "%6d %6d %6d    %-6.2f   %7.2f   \n";
  535.   
  536.   char *cpu_title = "\
  537. Recv   Send    Send                          Utilization       Service Demand\n\
  538. Socket Socket  Message  Elapsed              Send     Recv     Send    Recv\n\
  539. Size   Size    Size     Time     Throughput  local    remote   local   remote\n\
  540. bytes  bytes   bytes    secs.    %-8.8s/s  %% %c      %% %c      us/KB   us/KB\n\n";
  541.   
  542.   char *cpu_fmt_0 =
  543.     "%6.3f %c\n";
  544.  
  545.   char *cpu_fmt_1 =
  546.     "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f\n";
  547.   
  548.   char *ksink_fmt = "\n\
  549. Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
  550. Local  Remote  Local  Remote  Xfered   Per                 Per\n\
  551. Send   Recv    Send   Recv             Send (avg)          Recv (avg)\n\
  552. %5d   %5d  %5d   %5d %6.4g  %6.2f    %6d   %6.2f %6d\n";
  553.  
  554.   char *ksink_fmt2 = "\n\
  555. Maximum\n\
  556. Segment\n\
  557. Size (bytes)\n\
  558. %6d\n";
  559.   
  560.   
  561.   float            elapsed_time;
  562.   
  563. #ifdef INTERVALS
  564.   int interval_count;
  565.   sigset_t signal_set;
  566. #endif
  567.   
  568.   /* what we want is to have a buffer space that is at least one */
  569.   /* send-size greater than our send window. this will insure that we */
  570.   /* are never trying to re-use a buffer that may still be in the hands */
  571.   /* of the transport. This buffer will be malloc'd after we have found */
  572.   /* the size of the local senc socket buffer. We will want to deal */
  573.   /* with alignment and offset concerns as well. */
  574.   
  575. #ifdef DIRTY
  576.   int    *message_int_ptr;
  577. #endif
  578.  
  579.   struct ring_elt *send_ring;
  580.   
  581.   int len;
  582.   unsigned int nummessages = 0;
  583.   int send_socket;
  584.   int bytes_remaining;
  585.   int tcp_mss;
  586.  
  587.   /* with links like fddi, one can send > 32 bits worth of bytes */
  588.   /* during a test... ;-) at some point, this should probably become a */
  589.   /* 64bit integral type, but those are not entirely common yet */
  590.   double    bytes_sent = 0.0;
  591.   
  592. #ifdef DIRTY
  593.   int    i;
  594. #endif /* DIRTY */
  595.   
  596.   float    local_cpu_utilization;
  597.   float    local_service_demand;
  598.   float    remote_cpu_utilization;
  599.   float    remote_service_demand;
  600.  
  601.   double    thruput;
  602.   
  603.   struct    hostent            *hp;
  604.   struct    sockaddr_in    server;
  605.   unsigned      int             addr;
  606.   
  607.   struct    tcp_stream_request_struct    *tcp_stream_request;
  608.   struct    tcp_stream_response_struct    *tcp_stream_response;
  609.   struct    tcp_stream_results_struct    *tcp_stream_result;
  610.   
  611.   tcp_stream_request  = 
  612.     (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
  613.   tcp_stream_response =
  614.     (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
  615.   tcp_stream_result   = 
  616.     (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
  617.   
  618. #ifdef HISTOGRAM
  619.   time_hist = HIST_new();
  620. #endif /* HISTOGRAM */
  621.   /* since we are now disconnected from the code that established the */
  622.   /* control socket, and since we want to be able to use different */
  623.   /* protocols and such, we are passed the name of the remote host and */
  624.   /* must turn that into the test specific addressing information. */
  625.   
  626.   bzero((char *)&server,
  627.     sizeof(server));
  628.   
  629.  /* it would seem that while HP-UX will allow an IP address (as a */
  630.  /* string) in a call to gethostbyname, other, less enlightened */
  631.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  632.   if ((hp = gethostbyname(remote_host)) == NULL) {
  633.     if ((addr = inet_addr(remote_host)) == -1) {
  634.       fprintf(where,
  635.           "send_tcp_stream: could not resolve the name %s\n",
  636.           remote_host);
  637.       fflush(where);
  638.       exit(1);
  639.     }
  640.     server.sin_addr.s_addr = addr;
  641.     server.sin_family = AF_INET;
  642.   }
  643.   else {
  644.     bcopy(hp->h_addr,
  645.       (char *)&server.sin_addr,
  646.       hp->h_length);
  647.     server.sin_family = hp->h_addrtype;
  648.   }
  649.   
  650.   
  651.   
  652.   if ( print_headers ) {
  653.     /* we want to have some additional, interesting information in */
  654.     /* the headers. we know some of it here, but not all, so we will */
  655.     /* only print the test title here and will print the results */
  656.     /* titles after the test is finished */
  657.     fprintf(where,"TCP STREAM TEST");
  658.     fprintf(where," to %s", remote_host);
  659.     if (iteration_max > 1) {
  660.       fprintf(where,
  661.           " : +/-%3.1f%% @ %2d%% conf.",
  662.           interval/0.02,
  663.           confidence_level);
  664.       }
  665.     if (loc_nodelay || rem_nodelay) {
  666.       fprintf(where," : nodelay");
  667.     }
  668.     if (loc_sndavoid || 
  669.     loc_rcvavoid ||
  670.     rem_sndavoid ||
  671.     rem_rcvavoid) {
  672.       fprintf(where," : copy avoidance");
  673.     }
  674. #ifdef HISTOGRAM
  675.     fprintf(where," : histogram");
  676. #endif /* HISTOGRAM */
  677. #ifdef INTERVALS
  678.     fprintf(where," : interval");
  679. #endif /* INTERVALS */
  680. #ifdef DIRTY 
  681.     fprintf(where," : dirty data");
  682. #endif /* DIRTY */
  683.     fprintf(where,"\n");
  684.   }
  685.  
  686.   send_ring = NULL;
  687.   confidence_iteration = 1;
  688.   init_stat();
  689.  
  690.   /* we have a great-big while loop which controls the number of times */
  691.   /* we run a particular test. this is for the calculation of a */
  692.   /* confidence interval (I really should have stayed awake during */
  693.   /* probstats :). If the user did not request confidence measurement */
  694.   /* (no confidence is the default) then we will only go though the */
  695.   /* loop once. the confidence stuff originates from the folks at IBM */
  696.  
  697.   while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
  698.      (confidence_iteration <= iteration_min)) {
  699.  
  700.     /* initialize a few counters. we have to remember that we might be */
  701.     /* going through the loop more than once. */
  702.     
  703.     nummessages    =    0;
  704.     bytes_sent     =    0.0;
  705.     times_up       =     0;
  706.     
  707.     /*set up the data socket                        */
  708.     send_socket = create_data_socket(AF_INET, 
  709.                      SOCK_STREAM);
  710.     
  711.     if (send_socket < 0){
  712.       perror("netperf: send_tcp_stream: tcp stream data socket");
  713.       exit(1);
  714.     }
  715.     
  716.     if (debug) {
  717.       fprintf(where,"send_tcp_stream: send_socket obtained...\n");
  718.     }
  719.     
  720.     /* at this point, we have either retrieved the socket buffer sizes, */
  721.     /* or have tried to set them, so now, we may want to set the send */
  722.     /* size based on that (because the user either did not use a -m */
  723.     /* option, or used one with an argument of 0). If the socket buffer */
  724.     /* size is not available, we will set the send size to 4KB - no */
  725.     /* particular reason, just arbitrary... */
  726.     if (send_size == 0) {
  727.       if (lss_size > 0) {
  728.     send_size = lss_size;
  729.       }
  730.       else {
  731.     send_size = 4096;
  732.       }
  733.     }
  734.     
  735.     /* set-up the data buffer ring with the requested alignment and offset. */
  736.     /* note also that we have allocated a quantity */
  737.     /* of memory that is at least one send-size greater than our socket */
  738.     /* buffer size. We want to be sure that there are at least two */
  739.     /* buffers allocated - this can be a bit of a problem when the */
  740.     /* send_size is bigger than the socket size, so we must check... the */
  741.     /* user may have wanted to explicitly set the "width" of our send */
  742.     /* buffers, we should respect that wish... */
  743.     if (send_width == 0) {
  744.       send_width = (lss_size/send_size) + 1;
  745.       if (send_width == 1) send_width++;
  746.     }
  747.     
  748.     if (send_ring == NULL) {
  749.       /* only allocate the send ring once. this is a networking test, */
  750.       /* not a memory allocation test. this way, we do not need a */
  751.       /* deallocate_buffer_ring() routine, and I don't feel like */
  752.       /* writing one anyway :) raj 11/94 */
  753.       send_ring = allocate_buffer_ring(send_width,
  754.                        send_size,
  755.                        local_send_align,
  756.                        local_send_offset);
  757.     }
  758.  
  759.     /* If the user has requested cpu utilization measurements, we must */
  760.     /* calibrate the cpu(s). We will perform this task within the tests */
  761.     /* themselves. If the user has specified the cpu rate, then */
  762.     /* calibrate_local_cpu will return rather quickly as it will have */
  763.     /* nothing to do. If local_cpu_rate is zero, then we will go through */
  764.     /* all the "normal" calibration stuff and return the rate back. */
  765.     
  766.     if (local_cpu_usage) {
  767.       local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  768.     }
  769.     
  770.     /* Tell the remote end to do a listen. The server alters the socket */
  771.     /* paramters on the other side at this point, hence the reason for */
  772.     /* all the values being passed in the setup message. If the user did */
  773.     /* not specify any of the parameters, they will be passed as 0, which */
  774.     /* will indicate to the remote that no changes beyond the system's */
  775.     /* default should be used. Alignment is the exception, it will */
  776.     /* default to 1, which will be no alignment alterations. */
  777.     
  778.     netperf_request.content.request_type    =    DO_TCP_STREAM;
  779.     tcp_stream_request->send_buf_size    =    rss_size;
  780.     tcp_stream_request->recv_buf_size    =    rsr_size;
  781.     tcp_stream_request->receive_size    =    recv_size;
  782.     tcp_stream_request->no_delay    =    rem_nodelay;
  783.     tcp_stream_request->recv_alignment    =    remote_recv_align;
  784.     tcp_stream_request->recv_offset    =    remote_recv_offset;
  785.     tcp_stream_request->measure_cpu    =    remote_cpu_usage;
  786.     tcp_stream_request->cpu_rate    =    remote_cpu_rate;
  787.     if (test_time) {
  788.       tcp_stream_request->test_length    =    test_time;
  789.     }
  790.     else {
  791.       tcp_stream_request->test_length    =    test_bytes;
  792.     }
  793.     tcp_stream_request->so_rcvavoid    =    rem_rcvavoid;
  794.     tcp_stream_request->so_sndavoid    =    rem_sndavoid;
  795. #ifdef DIRTY
  796.     tcp_stream_request->dirty_count       =       rem_dirty_count;
  797.     tcp_stream_request->clean_count       =       rem_clean_count;
  798. #endif /* DIRTY */
  799.     
  800.     
  801.     if (debug > 1) {
  802.       fprintf(where,
  803.           "netperf: send_tcp_stream: requesting TCP stream test\n");
  804.     }
  805.     
  806.     send_request();
  807.     
  808.     /* The response from the remote will contain all of the relevant     */
  809.     /* socket parameters for this test type. We will put them back into */
  810.     /* the variables here so they can be displayed if desired.  The    */
  811.     /* remote will have calibrated CPU if necessary, and will have done    */
  812.     /* all the needed set-up we will have calibrated the cpu locally    */
  813.     /* before sending the request, and will grab the counter value right*/
  814.     /* after the connect returns. The remote will grab the counter right*/
  815.     /* after the accept call. This saves the hassle of extra messages    */
  816.     /* being sent for the TCP tests.                    */
  817.     
  818.     recv_response();
  819.     
  820.     if (!netperf_response.content.serv_errno) {
  821.       if (debug)
  822.     fprintf(where,"remote listen done.\n");
  823.       rsr_size          =    tcp_stream_response->recv_buf_size;
  824.       rss_size          =    tcp_stream_response->send_buf_size;
  825.       rem_nodelay     =    tcp_stream_response->no_delay;
  826.       remote_cpu_usage=    tcp_stream_response->measure_cpu;
  827.       remote_cpu_rate = tcp_stream_response->cpu_rate;
  828.  
  829.       /* we have to make sure that the server port number is in */
  830.       /* network order */
  831.       server.sin_port   = tcp_stream_response->data_port_number;
  832.       server.sin_port   = htons(server.sin_port); 
  833.       rem_rcvavoid    = tcp_stream_response->so_rcvavoid;
  834.       rem_sndavoid    = tcp_stream_response->so_sndavoid;
  835.     }
  836.     else {
  837.       errno = netperf_response.content.serv_errno;
  838.       fprintf(where,
  839.           "netperf: remote error %d",
  840.           netperf_response.content.serv_errno);
  841.       perror("");
  842.       fflush(where);
  843.       
  844.       exit(1);
  845.     }
  846.     
  847.     /*Connect up to the remote port on the data socket  */
  848.     if (connect(send_socket, 
  849.         (struct sockaddr *)&server,
  850.         sizeof(server)) <0){
  851.       perror("netperf: send_tcp_stream: data socket connect failed");
  852.       printf(" port: %d\n",ntohs(server.sin_port));
  853.       exit(1);
  854.     }
  855.  
  856.     /* Data Socket set-up is finished. If there were problems, either */
  857.     /* the connect would have failed, or the previous response would */
  858.     /* have indicated a problem. I failed to see the value of the */
  859.     /* extra  message after the accept on the remote. If it failed, */
  860.     /* we'll see it here. If it didn't, we might as well start pumping */
  861.     /* data. */ 
  862.     
  863.     /* Set-up the test end conditions. For a stream test, they can be */
  864.     /* either time or byte-count based. */
  865.     
  866.     if (test_time) {
  867.       /* The user wanted to end the test after a period of time. */
  868.       times_up = 0;
  869.       bytes_remaining = 0;
  870.       /* in previous revisions, we had the same code repeated throught */
  871.       /* all the test suites. this was unnecessary, and meant more */
  872.       /* work for me when I wanted to switch to POSIX signals, so I */
  873.       /* have abstracted this out into a routine in netlib.c. if you */
  874.       /* are experiencing signal problems, you might want to look */
  875.       /* there. raj 11/94 */
  876.       start_timer(test_time);
  877.     }
  878.     else {
  879.       /* The tester wanted to send a number of bytes. */
  880.       bytes_remaining = test_bytes;
  881.       times_up = 1;
  882.     }
  883.     
  884.     /* The cpu_start routine will grab the current time and possibly */
  885.     /* value of the idle counter for later use in measuring cpu */
  886.     /* utilization and/or service demand and thruput. */
  887.     
  888.     cpu_start(local_cpu_usage);
  889.     
  890. #ifdef INTERVALS
  891.     if ((interval_burst) || (demo_mode)) {
  892.       /* zero means that we never pause, so we never should need the */
  893.       /* interval timer, unless we are in demo_mode */
  894.       start_itimer(interval_wate);
  895.     }
  896.     interval_count = interval_burst;
  897.     /* get the signal set for the call to sigsuspend */
  898.     if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
  899.       fprintf(where,
  900.           "send_udp_stream: unable to get sigmask errno %d\n",
  901.           errno);
  902.       fflush(where);
  903.       exit(1);
  904.     }
  905. #endif /* INTERVALS */
  906.  
  907. #ifdef DIRTY
  908.     /* initialize the random number generator for putting dirty stuff */
  909.     /* into the send buffer. raj */
  910.     srand((int) getpid());
  911. #endif
  912.     
  913.     /* before we start, initialize a few variables */
  914.  
  915.     /* We use an "OR" to control test execution. When the test is */
  916.     /* controlled by time, the byte count check will always return false. */
  917.     /* When the test is controlled by byte count, the time test will */
  918.     /* always return false. When the test is finished, the whole */
  919.     /* expression will go false and we will stop sending data. */
  920.     
  921.     while ((!times_up) || (bytes_remaining > 0)) {
  922.       
  923. #ifdef DIRTY
  924.       /* we want to dirty some number of consecutive integers in the buffer */
  925.       /* we are about to send. we may also want to bring some number of */
  926.       /* them cleanly into the cache. The clean ones will follow any dirty */
  927.       /* ones into the cache. at some point, we might want to replace */
  928.       /* the rand() call with something from a table to reduce our call */
  929.       /* overhead during the test, but it is not a high priority item. */
  930.       message_int_ptr = (int *)(send_ring->buffer_ptr);
  931.       for (i = 0; i < loc_dirty_count; i++) {
  932.     *message_int_ptr = rand();
  933.     message_int_ptr++;
  934.       }
  935.       for (i = 0; i < loc_clean_count; i++) {
  936.     loc_dirty_count = *message_int_ptr;
  937.     message_int_ptr++;
  938.       }
  939. #endif /* DIRTY */
  940.       
  941. #ifdef HISTOGRAM
  942.       /* timestamp just before we go into send and then again just after */
  943.       /* we come out raj 8/94 */
  944.       gettimeofday(&time_one,NULL);
  945. #endif /* HISTOGRAM */
  946.       
  947.       if((len=send(send_socket,
  948.            send_ring->buffer_ptr,
  949.            send_size,
  950.            0)) != send_size) {
  951. #ifdef WIN32
  952.       if ((len >=0) || 
  953.       (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR)) {
  954. #else
  955.       if ((len >=0) || (errno == EINTR)) {
  956. #endif /* WIN32 */
  957.       /* the test was interrupted, must be the end of test */
  958.       break;
  959.     }
  960.     perror("netperf: data send error");
  961.     printf("len was %d\n",len);
  962.     exit(1);
  963.       }
  964.  
  965. #ifdef HISTOGRAM
  966.       /* timestamp the exit from the send call and update the histogram */
  967.       gettimeofday(&time_two,NULL);
  968.       HIST_add(time_hist,delta_micro(&time_one,&time_two));
  969. #endif /* HISTOGRAM */      
  970.  
  971. #ifdef INTERVALS      
  972.       if (demo_mode) {
  973.     units_this_tick += send_size;
  974.       }
  975.       /* in this case, the interval count is the count-down couter */
  976.       /* to decide to sleep for a little bit */
  977.       if ((interval_burst) && (--interval_count == 0)) {
  978.     /* call sigsuspend and wait for the interval timer to get us */
  979.     /* out */
  980.     if (debug) {
  981.       fprintf(where,"about to suspend\n");
  982.       fflush(where);
  983.     }
  984.     if (sigsuspend(&signal_set) == EFAULT) {
  985.       fprintf(where,
  986.           "send_udp_stream: fault with sigsuspend.\n");
  987.       fflush(where);
  988.       exit(1);
  989.     }
  990.     interval_count = interval_burst;
  991.       }
  992. #endif /* INTERVALS */
  993.       
  994.       /* now we want to move our pointer to the next position in the */
  995.       /* data buffer...we may also want to wrap back to the "beginning" */
  996.       /* of the bufferspace, so we will mod the number of messages sent */
  997.       /* by the send width, and use that to calculate the offset to add */
  998.       /* to the base pointer. */
  999.       nummessages++;          
  1000.       send_ring = send_ring->next;
  1001.       if (bytes_remaining) {
  1002.     bytes_remaining -= send_size;
  1003.       }
  1004.     }
  1005.  
  1006.     /* The test is over. Flush the buffers to the remote end. We do a */
  1007.     /* graceful release to insure that all data has been taken by the */
  1008.     /* remote. */ 
  1009.  
  1010.     /* but first, if the verbosity is greater than 1, find-out what */
  1011.     /* the TCP maximum segment_size was (if possible) */
  1012.     if (verbosity > 1) {
  1013.       tcp_mss = -1;
  1014.       get_tcp_info(send_socket,&tcp_mss);
  1015.     }
  1016.     
  1017.     if (shutdown(send_socket,1) == -1) {
  1018.       perror("netperf: cannot shutdown tcp stream socket");
  1019.       exit(1);
  1020.     }
  1021.     
  1022.     /* hang a recv() off the socket to block until the remote has */
  1023.     /* brought all the data up into the application. it will do a */
  1024.     /* shutdown to cause a FIN to be sent our way. We will assume that */
  1025.     /* any exit from the recv() call is good... raj 4/93 */
  1026.     
  1027.     recv(send_socket, send_ring->buffer_ptr, send_size, 0);
  1028.     
  1029.     /* this call will always give us the elapsed time for the test, and */
  1030.     /* will also store-away the necessaries for cpu utilization */
  1031.     
  1032.     cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
  1033.                         /* measured and how */
  1034.                         /* long did we really */
  1035.                         /* run? */
  1036.     
  1037.     /* we are finished with the socket, so close it to prevent hitting */
  1038.     /* the limit on maximum open files. */
  1039.  
  1040.     close(send_socket);
  1041.  
  1042.     /* Get the statistics from the remote end. The remote will have */
  1043.     /* calculated service demand and all those interesting things. If it */
  1044.     /* wasn't supposed to care, it will return obvious values. */
  1045.     
  1046.     recv_response();
  1047.     if (!netperf_response.content.serv_errno) {
  1048.       if (debug)
  1049.     fprintf(where,"remote results obtained\n");
  1050.     }
  1051.     else {
  1052.       errno = netperf_response.content.serv_errno;
  1053.       fprintf(where,
  1054.           "netperf: remote error %d",
  1055.           netperf_response.content.serv_errno);
  1056.       perror("");
  1057.       fflush(where);
  1058.       
  1059.       exit(1);
  1060.     }
  1061.     
  1062.     /* We now calculate what our thruput was for the test. In the future, */
  1063.     /* we may want to include a calculation of the thruput measured by */
  1064.     /* the remote, but it should be the case that for a TCP stream test, */
  1065.     /* that the two numbers should be *very* close... We calculate */
  1066.     /* bytes_sent regardless of the way the test length was controlled. */
  1067.     /* If it was time, we needed to, and if it was by bytes, the user may */
  1068.     /* have specified a number of bytes that wasn't a multiple of the */
  1069.     /* send_size, so we really didn't send what he asked for ;-) */
  1070.     
  1071.     bytes_sent    = ntohd(tcp_stream_result->bytes_received);
  1072.  
  1073.     thruput    = (double) calc_thruput(bytes_sent);
  1074.     
  1075.     if (local_cpu_usage || remote_cpu_usage) {
  1076.       /* We must now do a little math for service demand and cpu */
  1077.       /* utilization for the system(s) */
  1078.       /* Of course, some of the information might be bogus because */
  1079.       /* there was no idle counter in the kernel(s). We need to make */
  1080.       /* a note of this for the user's benefit...*/
  1081.       if (local_cpu_usage) {
  1082.     
  1083.     local_cpu_utilization    = calc_cpu_util(0.0);
  1084.     local_service_demand    = calc_service_demand(bytes_sent,
  1085.                               0.0,
  1086.                               0.0,
  1087.                               0);
  1088.       }
  1089.       else {
  1090.     local_cpu_utilization    = (float) -1.0;
  1091.     local_service_demand    = (float) -1.0;
  1092.       }
  1093.       
  1094.       if (remote_cpu_usage) {
  1095.     
  1096.     remote_cpu_utilization    = tcp_stream_result->cpu_util;
  1097.     remote_service_demand    = calc_service_demand(bytes_sent,
  1098.                               0.0,
  1099.                               remote_cpu_utilization,
  1100.                               tcp_stream_result->num_cpus);
  1101.       }
  1102.       else {
  1103.     remote_cpu_utilization = (float) -1.0;
  1104.     remote_service_demand  = (float) -1.0;
  1105.       }
  1106.     }    
  1107.     else {
  1108.       /* we were not measuring cpu, for the confidence stuff, we */
  1109.       /* should make it -1.0 */
  1110.       local_cpu_utilization    = (float) -1.0;
  1111.       local_service_demand    = (float) -1.0;
  1112.       remote_cpu_utilization = (float) -1.0;
  1113.       remote_service_demand  = (float) -1.0;
  1114.     }
  1115.  
  1116.     /* at this point, we want to calculate the confidence information. */
  1117.     /* if debugging is on, calculate_confidence will print-out the */
  1118.     /* parameters we pass it */
  1119.     
  1120.     calculate_confidence(confidence_iteration,
  1121.              elapsed_time,
  1122.              thruput,
  1123.              local_cpu_utilization,
  1124.              remote_cpu_utilization,
  1125.              local_service_demand,
  1126.              remote_service_demand);
  1127.     
  1128.     
  1129.     confidence_iteration++;
  1130.   }
  1131.  
  1132.   /* at this point, we have finished making all the runs that we */
  1133.   /* will be making. so, we should extract what the calcuated values */
  1134.   /* are for all the confidence stuff. we could make the values */
  1135.   /* global, but that seemed a little messy, and it did not seem worth */
  1136.   /* all the mucking with header files. so, we create a routine much */
  1137.   /* like calcualte_confidence, which just returns the mean values. */
  1138.   /* raj 11/94 */
  1139.  
  1140.   retrieve_confident_values(&elapsed_time,
  1141.                 &thruput,
  1142.                 &local_cpu_utilization,
  1143.                 &remote_cpu_utilization,
  1144.                 &local_service_demand,
  1145.                 &remote_service_demand);
  1146.  
  1147.   /* We are now ready to print all the information. If the user */
  1148.   /* has specified zero-level verbosity, we will just print the */
  1149.   /* local service demand, or the remote service demand. If the */
  1150.   /* user has requested verbosity level 1, he will get the basic */
  1151.   /* "streamperf" numbers. If the user has specified a verbosity */
  1152.   /* of greater than 1, we will display a veritable plethora of */
  1153.   /* background information from outside of this block as it it */
  1154.   /* not cpu_measurement specific...  */
  1155.  
  1156.   if (confidence < 0) {
  1157.     /* we did not hit confidence, but were we asked to look for it? */
  1158.     if (iteration_max > 1) {
  1159.       display_confidence();
  1160.     }
  1161.   }
  1162.  
  1163.   if (local_cpu_usage || remote_cpu_usage) {
  1164.     local_cpu_method = format_cpu_method(cpu_method);
  1165.     remote_cpu_method = format_cpu_method(tcp_stream_result->cpu_method);
  1166.     
  1167.     switch (verbosity) {
  1168.     case 0:
  1169.       if (local_cpu_usage) {
  1170.     fprintf(where,
  1171.         cpu_fmt_0,
  1172.         local_service_demand,
  1173.         local_cpu_method);
  1174.       }
  1175.       else {
  1176.     fprintf(where,
  1177.         cpu_fmt_0,
  1178.         remote_service_demand,
  1179.         remote_cpu_method);
  1180.       }
  1181.       break;
  1182.     case 1:
  1183.     case 2:
  1184.       if (print_headers) {
  1185.     fprintf(where,
  1186.         cpu_title,
  1187.         format_units(),
  1188.         local_cpu_method,
  1189.         remote_cpu_method);
  1190.       }
  1191.     
  1192.       fprintf(where,
  1193.           cpu_fmt_1,        /* the format string */
  1194.           rsr_size,                /* remote recvbuf size */
  1195.           lss_size,                /* local sendbuf size */
  1196.           send_size,        /* how large were the sends */
  1197.           elapsed_time,        /* how long was the test */
  1198.           thruput,                 /* what was the xfer rate */
  1199.           local_cpu_utilization,    /* local cpu */
  1200.           remote_cpu_utilization,    /* remote cpu */
  1201.           local_service_demand,    /* local service demand */
  1202.           remote_service_demand);    /* remote service demand */
  1203.       break;
  1204.     }
  1205.   }
  1206.   else {
  1207.     /* The tester did not wish to measure service demand. */
  1208.     
  1209.     switch (verbosity) {
  1210.     case 0:
  1211.       fprintf(where,
  1212.           tput_fmt_0,
  1213.           thruput);
  1214.       break;
  1215.     case 1:
  1216.     case 2:
  1217.       if (print_headers) {
  1218.     fprintf(where,tput_title,format_units());
  1219.       }
  1220.       fprintf(where,
  1221.           tput_fmt_1,        /* the format string */
  1222.           rsr_size,         /* remote recvbuf size */
  1223.           lss_size,         /* local sendbuf size */
  1224.           send_size,        /* how large were the sends */
  1225.           elapsed_time,         /* how long did it take */
  1226.           thruput);/* how fast did it go */
  1227.       break;
  1228.     }
  1229.   }
  1230.   
  1231.   /* it would be a good thing to include information about some of the */
  1232.   /* other parameters that may have been set for this test, but at the */
  1233.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  1234.   /* just put this comment here to help remind me that it is something */
  1235.   /* that should be done at a later time. */
  1236.   
  1237.   if (verbosity > 1) {
  1238.     /* The user wanted to know it all, so we will give it to him. */
  1239.     /* This information will include as much as we can find about */
  1240.     /* TCP statistics, the alignments of the sends and receives */
  1241.     /* and all that sort of rot... */
  1242.    
  1243.     /* this stuff needs to be worked-out in the presence of confidence */
  1244.     /* intervals and multiple iterations of the test... raj 11/94 */
  1245.  
  1246.     fprintf(where,
  1247.         ksink_fmt,
  1248.         "Bytes",
  1249.         "Bytes",
  1250.         "Bytes",
  1251.         local_send_align,
  1252.         remote_recv_align,
  1253.         local_send_offset,
  1254.         remote_recv_offset,
  1255.         bytes_sent,
  1256.         bytes_sent / (double)nummessages,
  1257.         nummessages,
  1258.         bytes_sent / (double)tcp_stream_result->recv_calls,
  1259.         tcp_stream_result->recv_calls);
  1260.     fprintf(where,
  1261.         ksink_fmt2,
  1262.         tcp_mss);
  1263.     fflush(where);
  1264. #ifdef HISTOGRAM
  1265.     fprintf(where,"\n\nHistogram of time spent in send() call.\n");
  1266.     fflush(where);
  1267.     HIST_report(time_hist);
  1268. #endif /* HISTOGRAM */
  1269.   }
  1270.   
  1271. }
  1272.  
  1273.  
  1274. /* This is the server-side routine for the tcp stream test. It is */
  1275. /* implemented as one routine. I could break things-out somewhat, but */
  1276. /* didn't feel it was necessary. */
  1277.  
  1278. void
  1279. recv_tcp_stream()
  1280. {
  1281.   
  1282.   struct sockaddr_in myaddr_in, peeraddr_in;
  1283.   int    s_listen,s_data;
  1284.   int     addrlen;
  1285.   int    len;
  1286.   unsigned int    receive_calls;
  1287.   float    elapsed_time;
  1288.   double   bytes_received;
  1289.   
  1290.   struct ring_elt *recv_ring;
  1291.  
  1292. #ifdef DIRTY
  1293.   int   *message_int_ptr;
  1294.   int   dirty_count;
  1295.   int   clean_count;
  1296.   int   i;
  1297. #endif
  1298.   
  1299.   struct    tcp_stream_request_struct    *tcp_stream_request;
  1300.   struct    tcp_stream_response_struct    *tcp_stream_response;
  1301.   struct    tcp_stream_results_struct    *tcp_stream_results;
  1302.   
  1303.   tcp_stream_request    = 
  1304.     (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
  1305.   tcp_stream_response    = 
  1306.     (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
  1307.   tcp_stream_results    = 
  1308.     (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
  1309.   
  1310.   if (debug) {
  1311.     fprintf(where,"netserver: recv_tcp_stream: entered...\n");
  1312.     fflush(where);
  1313.   }
  1314.   
  1315.   /* We want to set-up the listen socket with all the desired */
  1316.   /* parameters and then let the initiator know that all is ready. If */
  1317.   /* socket size defaults are to be used, then the initiator will have */
  1318.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  1319.   /* send-back what they are. If that information cannot be determined, */
  1320.   /* then we send-back -1's for the sizes. If things go wrong for any */
  1321.   /* reason, we will drop back ten yards and punt. */
  1322.   
  1323.   /* If anything goes wrong, we want the remote to know about it. It */
  1324.   /* would be best if the error that the remote reports to the user is */
  1325.   /* the actual error we encountered, rather than some bogus unexpected */
  1326.   /* response type message. */
  1327.   
  1328.   if (debug) {
  1329.     fprintf(where,"recv_tcp_stream: setting the response type...\n");
  1330.     fflush(where);
  1331.   }
  1332.   
  1333.   netperf_response.content.response_type = TCP_STREAM_RESPONSE;
  1334.   
  1335.   if (debug) {
  1336.     fprintf(where,"recv_tcp_stream: the response type is set...\n");
  1337.     fflush(where);
  1338.   }
  1339.   
  1340.   /* We now alter the message_ptr variable to be at the desired */
  1341.   /* alignment with the desired offset. */
  1342.   
  1343.   if (debug) {
  1344.     fprintf(where,"recv_tcp_stream: requested alignment of %d\n",
  1345.         tcp_stream_request->recv_alignment);
  1346.     fflush(where);
  1347.   }
  1348.  
  1349.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  1350.   /* can put in OUR values !-) At some point, we may want to nail this */
  1351.   /* socket to a particular network-level address, but for now, */
  1352.   /* INADDR_ANY should be just fine. */
  1353.   
  1354.   bzero((char *)&myaddr_in,
  1355.     sizeof(myaddr_in));
  1356.   myaddr_in.sin_family      = AF_INET;
  1357.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  1358.   myaddr_in.sin_port        = 0;
  1359.   
  1360.   /* Grab a socket to listen on, and then listen on it. */
  1361.   
  1362.   if (debug) {
  1363.     fprintf(where,"recv_tcp_stream: grabbing a socket...\n");
  1364.     fflush(where);
  1365.   }
  1366.   
  1367.   /* create_data_socket expects to find some things in the global */
  1368.   /* variables, so set the globals based on the values in the request. */
  1369.   /* once the socket has been created, we will set the response values */
  1370.   /* based on the updated value of those globals. raj 7/94 */
  1371.   lss_size = tcp_stream_request->send_buf_size;
  1372.   lsr_size = tcp_stream_request->recv_buf_size;
  1373.   loc_nodelay = tcp_stream_request->no_delay;
  1374.   loc_rcvavoid = tcp_stream_request->so_rcvavoid;
  1375.   loc_sndavoid = tcp_stream_request->so_sndavoid;
  1376.  
  1377.   s_listen = create_data_socket(AF_INET,
  1378.                 SOCK_STREAM);
  1379.   
  1380.   if (s_listen < 0) {
  1381.     netperf_response.content.serv_errno = errno;
  1382.     send_response();
  1383.     exit(1);
  1384.   }
  1385.   
  1386.   /* Let's get an address assigned to this socket so we can tell the */
  1387.   /* initiator how to reach the data socket. There may be a desire to */
  1388.   /* nail this socket to a specific IP address in a multi-homed, */
  1389.   /* multi-connection situation, but for now, we'll ignore the issue */
  1390.   /* and concentrate on single connection testing. */
  1391.   
  1392.   if (bind(s_listen,
  1393.        (struct sockaddr *)&myaddr_in,
  1394.        sizeof(myaddr_in)) == -1) {
  1395.     netperf_response.content.serv_errno = errno;
  1396.     close(s_listen);
  1397.     send_response();
  1398.     
  1399.     exit(1);
  1400.   }
  1401.   
  1402.   /* what sort of sizes did we end-up with? */
  1403.   if (tcp_stream_request->receive_size == 0) {
  1404.     if (lsr_size > 0) {
  1405.       recv_size = lsr_size;
  1406.     }
  1407.     else {
  1408.       recv_size = 4096;
  1409.     }
  1410.   }
  1411.   else {
  1412.     recv_size = tcp_stream_request->receive_size;
  1413.   }
  1414.   
  1415.   /* we want to set-up our recv_ring in a manner analagous to what we */
  1416.   /* do on the sending side. this is more for the sake of symmetry */
  1417.   /* than for the needs of say copy avoidance, but it might also be */
  1418.   /* more realistic - this way one could conceivably go with a */
  1419.   /* double-buffering scheme when taking the data an putting it into */
  1420.   /* the filesystem or something like that. raj 7/94 */
  1421.  
  1422.   if (recv_width == 0) {
  1423.     recv_width = (lsr_size/recv_size) + 1;
  1424.     if (recv_width == 1) recv_width++;
  1425.   }
  1426.  
  1427.   recv_ring = allocate_buffer_ring(recv_width,
  1428.                    recv_size,
  1429.                    tcp_stream_request->recv_alignment,
  1430.                    tcp_stream_request->recv_offset);
  1431.  
  1432.   if (debug) {
  1433.     fprintf(where,"recv_tcp_stream: receive alignment and offset set...\n");
  1434.     fflush(where);
  1435.   }
  1436.   
  1437.   /* Now, let's set-up the socket to listen for connections */
  1438.   if (listen(s_listen, 5) == -1) {
  1439.     netperf_response.content.serv_errno = errno;
  1440.     close(s_listen);
  1441.     send_response();
  1442.     
  1443.     exit(1);
  1444.   }
  1445.   
  1446.   
  1447.   /* now get the port number assigned by the system  */
  1448.   addrlen = sizeof(myaddr_in);
  1449.   if (getsockname(s_listen, 
  1450.           (struct sockaddr *)&myaddr_in,
  1451.           &addrlen) == -1){
  1452.     netperf_response.content.serv_errno = errno;
  1453.     close(s_listen);
  1454.     send_response();
  1455.     
  1456.     exit(1);
  1457.   }
  1458.   
  1459.   /* Now myaddr_in contains the port and the internet address this is */
  1460.   /* returned to the sender also implicitly telling the sender that the */
  1461.   /* socket buffer sizing has been done. */
  1462.   
  1463.   tcp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  1464.   netperf_response.content.serv_errno   = 0;
  1465.   
  1466.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  1467.   /* then we must call the calibrate routine, which will return the max */
  1468.   /* rate back to the initiator. If the CPU was not to be measured, or */
  1469.   /* something went wrong with the calibration, we will return a -1 to */
  1470.   /* the initiator. */
  1471.   
  1472.   tcp_stream_response->cpu_rate = (float)0.0;     /* assume no cpu */
  1473.   if (tcp_stream_request->measure_cpu) {
  1474.     tcp_stream_response->measure_cpu = 1;
  1475.     tcp_stream_response->cpu_rate = 
  1476.       calibrate_local_cpu(tcp_stream_request->cpu_rate);
  1477.   }
  1478.   else {
  1479.     tcp_stream_response->measure_cpu = 0;
  1480.   }
  1481.   
  1482.   /* before we send the response back to the initiator, pull some of */
  1483.   /* the socket parms from the globals */
  1484.   tcp_stream_response->send_buf_size = lss_size;
  1485.   tcp_stream_response->recv_buf_size = lsr_size;
  1486.   tcp_stream_response->no_delay = loc_nodelay;
  1487.   tcp_stream_response->so_rcvavoid = loc_rcvavoid;
  1488.   tcp_stream_response->so_sndavoid = loc_sndavoid;
  1489.   tcp_stream_response->receive_size = recv_size;
  1490.  
  1491.   send_response();
  1492.   
  1493.   addrlen = sizeof(peeraddr_in);
  1494.   
  1495.   if ((s_data=accept(s_listen,
  1496.              (struct sockaddr *)&peeraddr_in,
  1497.              &addrlen)) == -1) {
  1498.     /* Let's just punt. The remote will be given some information */
  1499.     close(s_listen);
  1500.     exit(1);
  1501.   }
  1502.  
  1503. #ifdef KLUDGE_SOCKET_OPTIONS
  1504.   /* this is for those systems which *INCORRECTLY* fail to pass */
  1505.   /* attributes across an accept() call. Including this goes against */
  1506.   /* my better judgement :( raj 11/95 */
  1507.  
  1508.   kludge_socket_options(s_data);
  1509.  
  1510. #endif /* KLUDGE_SOCKET_OPTIONS */
  1511.   
  1512.   /* Now it's time to start receiving data on the connection. We will */
  1513.   /* first grab the apropriate counters and then start grabbing. */
  1514.   
  1515.   cpu_start(tcp_stream_request->measure_cpu);
  1516.   
  1517.   /* The loop will exit when the sender does a shutdown, which will */
  1518.   /* return a length of zero   */
  1519.   
  1520. #ifdef DIRTY
  1521.     /* we want to dirty some number of consecutive integers in the buffer */
  1522.     /* we are about to recv. we may also want to bring some number of */
  1523.     /* them cleanly into the cache. The clean ones will follow any dirty */
  1524.     /* ones into the cache. */
  1525.  
  1526.   dirty_count = tcp_stream_request->dirty_count;
  1527.   clean_count = tcp_stream_request->clean_count;
  1528.   message_int_ptr = (int *)recv_ring->buffer_ptr;
  1529.   for (i = 0; i < dirty_count; i++) {
  1530.     *message_int_ptr = rand();
  1531.     message_int_ptr++;
  1532.   }
  1533.   for (i = 0; i < clean_count; i++) {
  1534.     dirty_count = *message_int_ptr;
  1535.     message_int_ptr++;
  1536.   }
  1537. #endif /* DIRTY */
  1538.  
  1539.   bytes_received = 0;
  1540.   receive_calls  = 0;
  1541.  
  1542.   while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
  1543. #ifdef WIN32
  1544.     if (len == SOCKET_ERROR ){
  1545.       netperf_response.content.serv_errno = WSAGetLastError();
  1546. #else
  1547.     if (len < 0) {
  1548.       netperf_response.content.serv_errno = errno;
  1549. #endif /* WIN32 */
  1550.  
  1551.       netperf_response.content.serv_errno = errno;
  1552.       send_response();
  1553.       exit(1);
  1554.     }
  1555.     bytes_received += len;
  1556.     receive_calls++;
  1557.  
  1558.     /* more to the next buffer in the recv_ring */
  1559.     recv_ring = recv_ring->next;
  1560.  
  1561. #ifdef DIRTY
  1562.     message_int_ptr = (int *)(recv_ring->buffer_ptr);
  1563.     for (i = 0; i < dirty_count; i++) {
  1564.       *message_int_ptr = rand();
  1565.       message_int_ptr++;
  1566.     }
  1567.     for (i = 0; i < clean_count; i++) {
  1568.       dirty_count = *message_int_ptr;
  1569.       message_int_ptr++;
  1570.     }
  1571. #endif /* DIRTY */
  1572.   }
  1573.   
  1574.   /* perform a shutdown to signal the sender that */
  1575.   /* we have received all the data sent. raj 4/93 */
  1576.  
  1577.   if (shutdown(s_data,1) == -1) {
  1578.       netperf_response.content.serv_errno = errno;
  1579.       send_response();
  1580.       exit(1);
  1581.     }
  1582.   
  1583.   cpu_stop(tcp_stream_request->measure_cpu,&elapsed_time);
  1584.   
  1585.   /* send the results to the sender            */
  1586.   
  1587.   if (debug) {
  1588.     fprintf(where,
  1589.         "recv_tcp_stream: got %g bytes\n",
  1590.         bytes_received);
  1591.     fprintf(where,
  1592.         "recv_tcp_stream: got %d recvs\n",
  1593.         receive_calls);
  1594.     fflush(where);
  1595.   }
  1596.   
  1597.   tcp_stream_results->bytes_received    = htond(bytes_received);
  1598.   tcp_stream_results->elapsed_time    = elapsed_time;
  1599.   tcp_stream_results->recv_calls    = receive_calls;
  1600.   
  1601.   if (tcp_stream_request->measure_cpu) {
  1602.     tcp_stream_results->cpu_util    = calc_cpu_util(0.0);
  1603.   };
  1604.   
  1605.   if (debug) {
  1606.     fprintf(where,
  1607.         "recv_tcp_stream: test complete, sending results.\n");
  1608.     fprintf(where,
  1609.         "                 bytes_received %g receive_calls %d\n",
  1610.         bytes_received,
  1611.         receive_calls);
  1612.     fprintf(where,
  1613.         "                 len %d\n",
  1614.         len);
  1615.     fflush(where);
  1616.   }
  1617.   
  1618.   tcp_stream_results->cpu_method = cpu_method;
  1619.   tcp_stream_results->num_cpus   = lib_num_loc_cpus;
  1620.   send_response();
  1621.  
  1622.   /* we are now done with the sockets */
  1623.   close(s_data);
  1624.   close(s_listen);
  1625.  
  1626. }
  1627.  
  1628.  
  1629.  /* this routine implements the sending (netperf) side of the TCP_RR */
  1630.  /* test. */
  1631.  
  1632. void
  1633. send_tcp_rr(remote_host)
  1634.      char    remote_host[];
  1635. {
  1636.   
  1637.   char *tput_title = "\
  1638. Local /Remote\n\
  1639. Socket Size   Request  Resp.   Elapsed  Trans.\n\
  1640. Send   Recv   Size     Size    Time     Rate         \n\
  1641. bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
  1642.   
  1643.   char *tput_fmt_0 =
  1644.     "%7.2f\n";
  1645.   
  1646.   char *tput_fmt_1_line_1 = "\
  1647. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
  1648.   char *tput_fmt_1_line_2 = "\
  1649. %-6d %-6d\n";
  1650.   
  1651.   char *cpu_title = "\
  1652. Local /Remote\n\
  1653. Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
  1654. Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
  1655. bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
  1656.   
  1657.   char *cpu_fmt_0 =
  1658.     "%6.3f %c\n";
  1659.   
  1660.   char *cpu_fmt_1_line_1 = "\
  1661. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f\n";
  1662.   
  1663.   char *cpu_fmt_1_line_2 = "\
  1664. %-6d %-6d\n";
  1665.   
  1666.   char *ksink_fmt = "\
  1667. Alignment      Offset\n\
  1668. Local  Remote  Local  Remote\n\
  1669. Send   Recv    Send   Recv\n\
  1670. %5d  %5d   %5d  %5d";
  1671.   
  1672.   
  1673.   int            timed_out = 0;
  1674.   float            elapsed_time;
  1675.   
  1676.   int    len;
  1677.   char    *temp_message_ptr;
  1678.   int    nummessages;
  1679.   int    send_socket;
  1680.   int    trans_remaining;
  1681.   double    bytes_xferd;
  1682.  
  1683.   struct ring_elt *send_ring;
  1684.   struct ring_elt *recv_ring;
  1685.   
  1686.   int    rsp_bytes_left;
  1687.   int    rsp_bytes_recvd;
  1688.   
  1689.   float    local_cpu_utilization;
  1690.   float    local_service_demand;
  1691.   float    remote_cpu_utilization;
  1692.   float    remote_service_demand;
  1693.   double    thruput;
  1694.   
  1695.   struct    hostent            *hp;
  1696.   struct    sockaddr_in    server;
  1697.   unsigned      int             addr;
  1698.  
  1699.   struct    tcp_rr_request_struct    *tcp_rr_request;
  1700.   struct    tcp_rr_response_struct    *tcp_rr_response;
  1701.   struct    tcp_rr_results_struct    *tcp_rr_result;
  1702.   
  1703. #ifdef INTERVALS
  1704.   int    interval_count;
  1705.   sigset_t signal_set;
  1706. #endif /* INTERVALS */
  1707.  
  1708.   tcp_rr_request = 
  1709.     (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
  1710.   tcp_rr_response=
  1711.     (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
  1712.   tcp_rr_result    =
  1713.     (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
  1714.   
  1715. #ifdef HISTOGRAM
  1716.   time_hist = HIST_new();
  1717. #endif /* HISTOGRAM */
  1718.  
  1719.   /* since we are now disconnected from the code that established the */
  1720.   /* control socket, and since we want to be able to use different */
  1721.   /* protocols and such, we are passed the name of the remote host and */
  1722.   /* must turn that into the test specific addressing information. */
  1723.  
  1724.   bzero((char *)&server,
  1725.     sizeof(server));
  1726.   
  1727.  /* it would seem that while HP-UX will allow an IP address (as a */
  1728.  /* string) in a call to gethostbyname, other, less enlightened */
  1729.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  1730.   if ((hp = gethostbyname(remote_host)) == NULL) {
  1731.     if ((addr = inet_addr(remote_host)) == -1) {
  1732.       fprintf(where,
  1733.           "send_tcp_rr: could not resolve the name %s\n",
  1734.           remote_host);
  1735.       fflush(where);
  1736.       exit(1);
  1737.     }
  1738.     server.sin_addr.s_addr = addr;
  1739.     server.sin_family = AF_INET;
  1740.   }
  1741.   else {
  1742.     bcopy(hp->h_addr,
  1743.       (char *)&server.sin_addr,
  1744.       hp->h_length);
  1745.     server.sin_family = hp->h_addrtype;
  1746.   }
  1747.  
  1748.   
  1749.   
  1750.   if ( print_headers ) {
  1751.     fprintf(where,"TCP REQUEST/RESPONSE TEST");
  1752.     fprintf(where," to %s", remote_host);
  1753.     if (iteration_max > 1) {
  1754.       fprintf(where,
  1755.           " : +/-%3.1f%% @ %2d%% conf.",
  1756.           interval/0.02,
  1757.           confidence_level);
  1758.       }
  1759.     if (loc_nodelay || rem_nodelay) {
  1760.       fprintf(where," : nodelay");
  1761.     }
  1762.     if (loc_sndavoid || 
  1763.     loc_rcvavoid ||
  1764.     rem_sndavoid ||
  1765.     rem_rcvavoid) {
  1766.       fprintf(where," : copy avoidance");
  1767.     }
  1768. #ifdef HISTOGRAM
  1769.     fprintf(where," : histogram");
  1770. #endif /* HISTOGRAM */
  1771. #ifdef INTERVALS
  1772.     fprintf(where," : interval");
  1773. #endif /* INTERVALS */
  1774. #ifdef DIRTY 
  1775.     fprintf(where," : dirty data");
  1776. #endif /* DIRTY */
  1777.     fprintf(where,"\n");
  1778.   }
  1779.   
  1780.   /* initialize a few counters */
  1781.   
  1782.   send_ring = NULL;
  1783.   recv_ring = NULL;
  1784.   confidence_iteration = 1;
  1785.   init_stat();
  1786.  
  1787.   /* we have a great-big while loop which controls the number of times */
  1788.   /* we run a particular test. this is for the calculation of a */
  1789.   /* confidence interval (I really should have stayed awake during */
  1790.   /* probstats :). If the user did not request confidence measurement */
  1791.   /* (no confidence is the default) then we will only go though the */
  1792.   /* loop once. the confidence stuff originates from the folks at IBM */
  1793.  
  1794.   while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
  1795.      (confidence_iteration <= iteration_min)) {
  1796.  
  1797.     /* initialize a few counters. we have to remember that we might be */
  1798.     /* going through the loop more than once. */
  1799.  
  1800.     nummessages     = 0;
  1801.     bytes_xferd     = 0.0;
  1802.     times_up        = 0;
  1803.     timed_out       = 0;
  1804.     trans_remaining = 0;
  1805.  
  1806.     /* set-up the data buffers with the requested alignment and offset. */
  1807.     /* since this is a request/response test, default the send_width and */
  1808.     /* recv_width to 1 and not two raj 7/94 */
  1809.  
  1810.     if (send_width == 0) send_width = 1;
  1811.     if (recv_width == 0) recv_width = 1;
  1812.   
  1813.     if (send_ring == NULL) {
  1814.       send_ring = allocate_buffer_ring(send_width,
  1815.                        req_size,
  1816.                        local_send_align,
  1817.                        local_send_offset);
  1818.     }
  1819.  
  1820.     if (recv_ring == NULL) {
  1821.       recv_ring = allocate_buffer_ring(recv_width,
  1822.                        rsp_size,
  1823.                        local_recv_align,
  1824.                        local_recv_offset);
  1825.     }
  1826.     
  1827.     /*set up the data socket                        */
  1828.     send_socket = create_data_socket(AF_INET, 
  1829.                      SOCK_STREAM);
  1830.   
  1831.     if (send_socket < 0){
  1832.       perror("netperf: send_tcp_rr: tcp stream data socket");
  1833.       exit(1);
  1834.     }
  1835.     
  1836.     if (debug) {
  1837.       fprintf(where,"send_tcp_rr: send_socket obtained...\n");
  1838.     }
  1839.   
  1840.     /* If the user has requested cpu utilization measurements, we must */
  1841.     /* calibrate the cpu(s). We will perform this task within the tests */
  1842.     /* themselves. If the user has specified the cpu rate, then */
  1843.     /* calibrate_local_cpu will return rather quickly as it will have */
  1844.     /* nothing to do. If local_cpu_rate is zero, then we will go through */
  1845.     /* all the "normal" calibration stuff and return the rate back.*/
  1846.     
  1847.     if (local_cpu_usage) {
  1848.       local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  1849.     }
  1850.     
  1851.     /* Tell the remote end to do a listen. The server alters the socket */
  1852.     /* paramters on the other side at this point, hence the reason for */
  1853.     /* all the values being passed in the setup message. If the user did */
  1854.     /* not specify any of the parameters, they will be passed as 0, which */
  1855.     /* will indicate to the remote that no changes beyond the system's */
  1856.     /* default should be used. Alignment is the exception, it will */
  1857.     /* default to 8, which will be no alignment alterations. */
  1858.     
  1859.     netperf_request.content.request_type    =    DO_TCP_RR;
  1860.     tcp_rr_request->recv_buf_size    =    rsr_size;
  1861.     tcp_rr_request->send_buf_size    =    rss_size;
  1862.     tcp_rr_request->recv_alignment      =    remote_recv_align;
  1863.     tcp_rr_request->recv_offset            =    remote_recv_offset;
  1864.     tcp_rr_request->send_alignment      =    remote_send_align;
  1865.     tcp_rr_request->send_offset            =    remote_send_offset;
  1866.     tcp_rr_request->request_size    =    req_size;
  1867.     tcp_rr_request->response_size    =    rsp_size;
  1868.     tcp_rr_request->no_delay            =    rem_nodelay;
  1869.     tcp_rr_request->measure_cpu            =    remote_cpu_usage;
  1870.     tcp_rr_request->cpu_rate            =    remote_cpu_rate;
  1871.     tcp_rr_request->so_rcvavoid            =    rem_rcvavoid;
  1872.     tcp_rr_request->so_sndavoid            =    rem_sndavoid;
  1873.     if (test_time) {
  1874.       tcp_rr_request->test_length    =    test_time;
  1875.     }
  1876.     else {
  1877.       tcp_rr_request->test_length    =    test_trans * -1;
  1878.     }
  1879.     
  1880.     if (debug > 1) {
  1881.       fprintf(where,"netperf: send_tcp_rr: requesting TCP rr test\n");
  1882.     }
  1883.     
  1884.     send_request();
  1885.     
  1886.     /* The response from the remote will contain all of the relevant     */
  1887.     /* socket parameters for this test type. We will put them back into */
  1888.     /* the variables here so they can be displayed if desired.  The    */
  1889.     /* remote will have calibrated CPU if necessary, and will have done    */
  1890.     /* all the needed set-up we will have calibrated the cpu locally    */
  1891.     /* before sending the request, and will grab the counter value right*/
  1892.     /* after the connect returns. The remote will grab the counter right*/
  1893.     /* after the accept call. This saves the hassle of extra messages    */
  1894.     /* being sent for the TCP tests.                    */
  1895.   
  1896.     recv_response();
  1897.   
  1898.     if (!netperf_response.content.serv_errno) {
  1899.       if (debug)
  1900.     fprintf(where,"remote listen done.\n");
  1901.       rsr_size          = tcp_rr_response->recv_buf_size;
  1902.       rss_size          = tcp_rr_response->send_buf_size;
  1903.       rem_nodelay       = tcp_rr_response->no_delay;
  1904.       remote_cpu_usage  = tcp_rr_response->measure_cpu;
  1905.       remote_cpu_rate   = tcp_rr_response->cpu_rate;
  1906.       /* make sure that port numbers are in network order */
  1907.       server.sin_port   = tcp_rr_response->data_port_number;
  1908.       server.sin_port   = htons(server.sin_port);
  1909.     }
  1910.     else {
  1911.       errno = netperf_response.content.serv_errno;
  1912.       fprintf(where,
  1913.           "netperf: remote error %d",
  1914.           netperf_response.content.serv_errno);
  1915.       perror("");
  1916.       fflush(where);
  1917.       
  1918.       exit(1);
  1919.     }
  1920.     
  1921.     /*Connect up to the remote port on the data socket  */
  1922.     if (connect(send_socket, 
  1923.         (struct sockaddr *)&server,
  1924.         sizeof(server)) <0){
  1925.       perror("netperf: data socket connect failed");
  1926.       
  1927.       exit(1);
  1928.     }
  1929.     
  1930.     /* Data Socket set-up is finished. If there were problems, either the */
  1931.     /* connect would have failed, or the previous response would have */
  1932.     /* indicated a problem. I failed to see the value of the extra */
  1933.     /* message after the accept on the remote. If it failed, we'll see it */
  1934.     /* here. If it didn't, we might as well start pumping data. */
  1935.     
  1936.     /* Set-up the test end conditions. For a request/response test, they */
  1937.     /* can be either time or transaction based. */
  1938.     
  1939.     if (test_time) {
  1940.       /* The user wanted to end the test after a period of time. */
  1941.       times_up = 0;
  1942.       trans_remaining = 0;
  1943.       start_timer(test_time);
  1944.     }
  1945.     else {
  1946.       /* The tester wanted to send a number of bytes. */
  1947.       trans_remaining = test_bytes;
  1948.       times_up = 1;
  1949.     }
  1950.     
  1951.     /* The cpu_start routine will grab the current time and possibly */
  1952.     /* value of the idle counter for later use in measuring cpu */
  1953.     /* utilization and/or service demand and thruput. */
  1954.     
  1955.     cpu_start(local_cpu_usage);
  1956.  
  1957. #ifdef INTERVALS
  1958.     if ((interval_burst) || (demo_mode)) {
  1959.       /* zero means that we never pause, so we never should need the */
  1960.       /* interval timer, unless we are in demo_mode */
  1961.       start_itimer(interval_wate);
  1962.     }
  1963.     interval_count = interval_burst;
  1964.     /* get the signal set for the call to sigsuspend */
  1965.     if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
  1966.       fprintf(where,
  1967.           "send_tcp_rr: unable to get sigmask errno %d\n",
  1968.           errno);
  1969.       fflush(where);
  1970.       exit(1);
  1971.     }
  1972. #endif /* INTERVALS */
  1973.     
  1974.     /* We use an "OR" to control test execution. When the test is */
  1975.     /* controlled by time, the byte count check will always return false. */
  1976.     /* When the test is controlled by byte count, the time test will */
  1977.     /* always return false. When the test is finished, the whole */
  1978.     /* expression will go false and we will stop sending data. I think I */
  1979.     /* just arbitrarily decrement trans_remaining for the timed test, but */
  1980.     /* will not do that just yet... One other question is whether or not */
  1981.     /* the send buffer and the receive buffer should be the same buffer. */
  1982.  
  1983.     while ((!times_up) || (trans_remaining > 0)) {
  1984.       /* send the request. we assume that if we use a blocking socket, */
  1985.       /* the request will be sent at one shot. */
  1986.       
  1987. #ifdef HISTOGRAM
  1988.       /* timestamp just before our call to send, and then again just */
  1989.       /* after the receive raj 8/94 */
  1990.       gettimeofday(&time_one,NULL);
  1991. #endif /* HISTOGRAM */
  1992.       
  1993.       if((len=send(send_socket,
  1994.            send_ring->buffer_ptr,
  1995.            req_size,
  1996.            0)) != req_size) {
  1997. #ifdef WIN32
  1998.     if (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  1999.       /* we hit the end of a */
  2000.       /* timed test. */
  2001.       timed_out = 1;
  2002.       break;
  2003.     }
  2004. #else
  2005.     if ((errno == EINTR) || (errno == 0)) {
  2006.       /* we hit the end of a */
  2007.       /* timed test. */
  2008.       timed_out = 1;
  2009.       break;
  2010.     }
  2011. #endif /* WIN32 */
  2012.     perror("send_tcp_rr: data send error");
  2013.     exit(1);
  2014.       }
  2015.       send_ring = send_ring->next;
  2016.       
  2017.       /* receive the response */
  2018.       rsp_bytes_left = rsp_size;
  2019.       temp_message_ptr  = recv_ring->buffer_ptr;
  2020.       while(rsp_bytes_left > 0) {
  2021.     if((rsp_bytes_recvd=recv(send_socket,
  2022.                  temp_message_ptr,
  2023.                  rsp_bytes_left,
  2024.                  0)) < 0) {
  2025. #ifdef WIN32
  2026.       if ( rsp_bytes_recvd == SOCKET_ERROR && 
  2027.           WSAGetLastError() == WSAEINTR ) {
  2028.         /* We hit the end of a timed test. */
  2029.         timed_out = 1;
  2030.         break;
  2031.       }
  2032. #else
  2033.       if (errno == EINTR) {
  2034.         /* We hit the end of a timed test. */
  2035.         timed_out = 1;
  2036.         break;
  2037.       }
  2038. #endif /* WIN32 */
  2039.       perror("send_tcp_rr: data recv error");
  2040.       exit(1);
  2041.     }
  2042.     rsp_bytes_left -= rsp_bytes_recvd;
  2043.     temp_message_ptr  += rsp_bytes_recvd;
  2044.       }    
  2045.       recv_ring = recv_ring->next;
  2046.       
  2047.       if (timed_out) {
  2048.     /* we may have been in a nested while loop - we need */
  2049.     /* another call to break. */
  2050.     break;
  2051.       }
  2052.       
  2053. #ifdef HISTOGRAM
  2054.       gettimeofday(&time_two,NULL);
  2055.       HIST_add(time_hist,delta_micro(&time_one,&time_two));
  2056. #endif /* HISTOGRAM */
  2057. #ifdef INTERVALS      
  2058.       if (demo_mode) {
  2059.     units_this_tick += 1;
  2060.       }
  2061.       /* in this case, the interval count is the count-down couter */
  2062.       /* to decide to sleep for a little bit */
  2063.       if ((interval_burst) && (--interval_count == 0)) {
  2064.     /* call sigsuspend and wait for the interval timer to get us */
  2065.     /* out */
  2066.     if (debug) {
  2067.       fprintf(where,"about to suspend\n");
  2068.       fflush(where);
  2069.     }
  2070.     if (sigsuspend(&signal_set) == EFAULT) {
  2071.       fprintf(where,
  2072.           "send_udp_rr: fault with signal set!\n");
  2073.       fflush(where);
  2074.       exit(1);
  2075.     }
  2076.     interval_count = interval_burst;
  2077.       }
  2078. #endif /* INTERVALS */
  2079.       
  2080.       nummessages++;          
  2081.       if (trans_remaining) {
  2082.     trans_remaining--;
  2083.       }
  2084.       
  2085.       if (debug > 3) {
  2086.     if ((nummessages % 100) == 0) {
  2087.       fprintf(where,
  2088.           "Transaction %d completed\n",
  2089.           nummessages);
  2090.       fflush(where);
  2091.     }
  2092.       }
  2093.     }
  2094.  
  2095.     /* At this point we used to call shutdown on the data socket to be */
  2096.     /* sure all the data was delivered, but this was not germane in a */
  2097.     /* request/response test, and it was causing the tests to "hang" when */
  2098.     /* they were being controlled by time. So, I have replaced this */
  2099.     /* shutdown call with a call to close that can be found later in the */
  2100.     /* procedure. */
  2101.     
  2102.     /* this call will always give us the elapsed time for the test, and */
  2103.     /* will also store-away the necessaries for cpu utilization */
  2104.     
  2105.     cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
  2106.                         /* measured? how long */
  2107.                         /* did we really run? */
  2108.     
  2109.     /* Get the statistics from the remote end. The remote will have */
  2110.     /* calculated CPU utilization. If it wasn't supposed to care, it */
  2111.     /* will return obvious values. */ 
  2112.     
  2113.     recv_response();
  2114.     if (!netperf_response.content.serv_errno) {
  2115.       if (debug)
  2116.     fprintf(where,"remote results obtained\n");
  2117.     }
  2118.     else {
  2119.       errno = netperf_response.content.serv_errno;
  2120.       fprintf(where,"netperf: remote error %d",
  2121.           netperf_response.content.serv_errno);
  2122.       perror("");
  2123.       fflush(where);
  2124.       exit(1);
  2125.     }
  2126.     
  2127.     /* We now calculate what our throughput was for the test. */
  2128.   
  2129.     bytes_xferd    = (req_size * nummessages) + (rsp_size * nummessages);
  2130.     thruput    = nummessages/elapsed_time;
  2131.   
  2132.     if (local_cpu_usage || remote_cpu_usage) {
  2133.       /* We must now do a little math for service demand and cpu */
  2134.       /* utilization for the system(s) */
  2135.       /* Of course, some of the information might be bogus because */
  2136.       /* there was no idle counter in the kernel(s). We need to make */
  2137.       /* a note of this for the user's benefit...*/
  2138.       if (local_cpu_usage) {
  2139.     local_cpu_utilization = calc_cpu_util(0.0);
  2140.     /* since calc_service demand is doing ms/Kunit we will */
  2141.     /* multiply the number of transaction by 1024 to get */
  2142.     /* "good" numbers */
  2143.     local_service_demand  = calc_service_demand((double) nummessages*1024,
  2144.                             0.0,
  2145.                             0.0,
  2146.                             0);
  2147.       }
  2148.       else {
  2149.     local_cpu_utilization    = (float) -1.0;
  2150.     local_service_demand    = (float) -1.0;
  2151.       }
  2152.       
  2153.       if (remote_cpu_usage) {
  2154.     remote_cpu_utilization = tcp_rr_result->cpu_util;
  2155.     /* since calc_service demand is doing ms/Kunit we will */
  2156.     /* multiply the number of transaction by 1024 to get */
  2157.     /* "good" numbers */
  2158.     remote_service_demand = calc_service_demand((double) nummessages*1024,
  2159.                             0.0,
  2160.                             remote_cpu_utilization,
  2161.                             tcp_rr_result->num_cpus);
  2162.       }
  2163.       else {
  2164.     remote_cpu_utilization = (float) -1.0;
  2165.     remote_service_demand  = (float) -1.0;
  2166.       }
  2167.       
  2168.     }
  2169.     else {
  2170.       /* we were not measuring cpu, for the confidence stuff, we */
  2171.       /* should make it -1.0 */
  2172.       local_cpu_utilization    = (float) -1.0;
  2173.       local_service_demand    = (float) -1.0;
  2174.       remote_cpu_utilization = (float) -1.0;
  2175.       remote_service_demand  = (float) -1.0;
  2176.     }
  2177.  
  2178.     /* at this point, we want to calculate the confidence information. */
  2179.     /* if debugging is on, calculate_confidence will print-out the */
  2180.     /* parameters we pass it */
  2181.     
  2182.     calculate_confidence(confidence_iteration,
  2183.              elapsed_time,
  2184.              thruput,
  2185.              local_cpu_utilization,
  2186.              remote_cpu_utilization,
  2187.              local_service_demand,
  2188.              remote_service_demand);
  2189.     
  2190.     
  2191.     confidence_iteration++;
  2192.  
  2193.     /* we are now done with the socket, so close it */
  2194.     close(send_socket);
  2195.  
  2196.   }
  2197.  
  2198.   retrieve_confident_values(&elapsed_time,
  2199.                 &thruput,
  2200.                 &local_cpu_utilization,
  2201.                 &remote_cpu_utilization,
  2202.                 &local_service_demand,
  2203.                 &remote_service_demand);
  2204.  
  2205.   /* We are now ready to print all the information. If the user */
  2206.   /* has specified zero-level verbosity, we will just print the */
  2207.   /* local service demand, or the remote service demand. If the */
  2208.   /* user has requested verbosity level 1, he will get the basic */
  2209.   /* "streamperf" numbers. If the user has specified a verbosity */
  2210.   /* of greater than 1, we will display a veritable plethora of */
  2211.   /* background information from outside of this block as it it */
  2212.   /* not cpu_measurement specific...  */
  2213.  
  2214.   if (confidence < 0) {
  2215.     /* we did not hit confidence, but were we asked to look for it? */
  2216.     if (iteration_max > 1) {
  2217.       display_confidence();
  2218.     }
  2219.   }
  2220.  
  2221.   if (local_cpu_usage || remote_cpu_usage) {
  2222.     local_cpu_method = format_cpu_method(cpu_method);
  2223.     remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method);
  2224.     
  2225.     switch (verbosity) {
  2226.     case 0:
  2227.       if (local_cpu_usage) {
  2228.     fprintf(where,
  2229.         cpu_fmt_0,
  2230.         local_service_demand,
  2231.         local_cpu_method);
  2232.       }
  2233.       else {
  2234.     fprintf(where,
  2235.         cpu_fmt_0,
  2236.         remote_service_demand,
  2237.         remote_cpu_method);
  2238.       }
  2239.       break;
  2240.     case 1:
  2241.     case 2:
  2242.       if (print_headers) {
  2243.     fprintf(where,
  2244.         cpu_title,
  2245.         local_cpu_method,
  2246.         remote_cpu_method);
  2247.       }
  2248.  
  2249.       fprintf(where,
  2250.           cpu_fmt_1_line_1,        /* the format string */
  2251.           lss_size,        /* local sendbuf size */
  2252.           lsr_size,
  2253.           req_size,        /* how large were the requests */
  2254.           rsp_size,        /* guess */
  2255.           elapsed_time,        /* how long was the test */
  2256.           thruput,
  2257.           local_cpu_utilization,    /* local cpu */
  2258.           remote_cpu_utilization,    /* remote cpu */
  2259.           local_service_demand,    /* local service demand */
  2260.           remote_service_demand);    /* remote service demand */
  2261.       fprintf(where,
  2262.           cpu_fmt_1_line_2,
  2263.           rss_size,
  2264.           rsr_size);
  2265.       break;
  2266.     }
  2267.   }
  2268.   else {
  2269.     /* The tester did not wish to measure service demand. */
  2270.     
  2271.     switch (verbosity) {
  2272.     case 0:
  2273.       fprintf(where,
  2274.           tput_fmt_0,
  2275.           thruput);
  2276.       break;
  2277.     case 1:
  2278.     case 2:
  2279.       if (print_headers) {
  2280.     fprintf(where,tput_title,format_units());
  2281.       }
  2282.  
  2283.       fprintf(where,
  2284.           tput_fmt_1_line_1,    /* the format string */
  2285.           lss_size,
  2286.           lsr_size,
  2287.           req_size,        /* how large were the requests */
  2288.           rsp_size,        /* how large were the responses */
  2289.           elapsed_time,         /* how long did it take */
  2290.           thruput);
  2291.       fprintf(where,
  2292.           tput_fmt_1_line_2,
  2293.           rss_size,         /* remote recvbuf size */
  2294.           rsr_size);
  2295.       
  2296.       break;
  2297.     }
  2298.   }
  2299.   
  2300.   /* it would be a good thing to include information about some of the */
  2301.   /* other parameters that may have been set for this test, but at the */
  2302.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  2303.   /* just put this comment here to help remind me that it is something */
  2304.   /* that should be done at a later time. */
  2305.   
  2306.   /* how to handle the verbose information in the presence of */
  2307.   /* confidence intervals is yet to be determined... raj 11/94 */
  2308.   if (verbosity > 1) {
  2309.     /* The user wanted to know it all, so we will give it to him. */
  2310.     /* This information will include as much as we can find about */
  2311.     /* TCP statistics, the alignments of the sends and receives */
  2312.     /* and all that sort of rot... */
  2313.     
  2314.     fprintf(where,
  2315.         ksink_fmt,
  2316.         local_send_align,
  2317.         remote_recv_offset,
  2318.         local_send_offset,
  2319.         remote_recv_offset);
  2320.  
  2321. #ifdef HISTOGRAM
  2322.     fprintf(where,"\nHistogram of request/response times\n");
  2323.     fflush(where);
  2324.     HIST_report(time_hist);
  2325. #endif /* HISTOGRAM */
  2326.  
  2327.   }
  2328.   
  2329. }
  2330.  
  2331. void
  2332. send_udp_stream(remote_host)
  2333. char    remote_host[];
  2334. {
  2335.   /**********************************************************************/
  2336.   /*                                    */
  2337.   /*                   UDP Unidirectional Send Test                    */
  2338.   /*                                    */
  2339.   /**********************************************************************/
  2340.   char *tput_title = "\
  2341. Socket  Message  Elapsed      Messages                \n\
  2342. Size    Size     Time         Okay Errors   Throughput\n\
  2343. bytes   bytes    secs            #      #   %s/sec\n\n";
  2344.   
  2345.   char *tput_fmt_0 =
  2346.     "%7.2f\n";
  2347.   
  2348.   char *tput_fmt_1 = "\
  2349. %6d  %6d   %-7.2f   %7d %6d    %7.2f\n\
  2350. %6d           %-7.2f   %7d           %7.2f\n\n";
  2351.   
  2352.   
  2353.   char *cpu_title = "\
  2354. Socket  Message  Elapsed      Messages                   CPU      Service\n\
  2355. Size    Size     Time         Okay Errors   Throughput   Util     Demand\n\
  2356. bytes   bytes    secs            #      #   %s/sec %% %c%c     us/KB\n\n";
  2357.   
  2358.   char *cpu_fmt_0 =
  2359.     "%6.2f %c\n";
  2360.   
  2361.   char *cpu_fmt_1 = "\
  2362. %6d  %6d   %-7.2f   %7d %6d    %7.1f     %-6.2f   %-6.3f\n\
  2363. %6d           %-7.2f   %7d           %7.1f     %-6.2f   %-6.3f\n\n";
  2364.   
  2365.   unsigned int    messages_recvd;
  2366.   unsigned int     messages_sent;
  2367.   unsigned int    failed_sends;
  2368.  
  2369.   float    elapsed_time,  
  2370.         local_cpu_utilization,
  2371.         remote_cpu_utilization;
  2372.   
  2373.   float     local_service_demand, remote_service_demand;
  2374.   double local_thruput, remote_thruput;
  2375.   double bytes_sent;
  2376.   double bytes_recvd;
  2377.   
  2378.   
  2379.   int    len;
  2380.   struct ring_elt *send_ring;
  2381.   int     data_socket;
  2382.   
  2383.   unsigned int sum_messages_sent;
  2384.   unsigned int sum_messages_recvd;
  2385.   unsigned int sum_failed_sends;
  2386.   double sum_local_thruput;
  2387.  
  2388. #ifdef INTERVALS
  2389.   int    interval_count;
  2390.   sigset_t signal_set;
  2391. #endif /* INTERVALS */
  2392. #ifdef DIRTY
  2393.   int    *message_int_ptr;
  2394.   int    i;
  2395. #endif /* DIRTY */
  2396.   
  2397.   struct    hostent            *hp;
  2398.   struct    sockaddr_in    server;
  2399.   unsigned      int             addr;
  2400.   
  2401.   struct    udp_stream_request_struct    *udp_stream_request;
  2402.   struct    udp_stream_response_struct    *udp_stream_response;
  2403.   struct    udp_stream_results_struct    *udp_stream_results;
  2404.   
  2405.   udp_stream_request    = 
  2406.     (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
  2407.   udp_stream_response    = 
  2408.     (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
  2409.   udp_stream_results    = 
  2410.     (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
  2411.   
  2412. #ifdef HISTOGRAM
  2413.   time_hist = HIST_new();
  2414. #endif /* HISTOGRAM */
  2415.  
  2416.   /* since we are now disconnected from the code that established the */
  2417.   /* control socket, and since we want to be able to use different */
  2418.   /* protocols and such, we are passed the name of the remote host and */
  2419.   /* must turn that into the test specific addressing information. */
  2420.   
  2421.   bzero((char *)&server,
  2422.     sizeof(server));
  2423.   
  2424.  /* it would seem that while HP-UX will allow an IP address (as a */
  2425.  /* string) in a call to gethostbyname, other, less enlightened */
  2426.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  2427.   if ((hp = gethostbyname(remote_host)) == NULL) {
  2428.     if ((addr = inet_addr(remote_host)) == -1) {
  2429.       fprintf(where,
  2430.           "send_udp_stream: could not resolve the name %s\n",
  2431.           remote_host);
  2432.       fflush(where);
  2433.       exit(1);
  2434.     }
  2435.     server.sin_addr.s_addr = addr;
  2436.     server.sin_family = AF_INET;
  2437.   }
  2438.   else {
  2439.     bcopy(hp->h_addr,
  2440.       (char *)&server.sin_addr,
  2441.       hp->h_length);
  2442.     server.sin_family = hp->h_addrtype;
  2443.   }
  2444.  
  2445.   
  2446.   if ( print_headers ) {
  2447.     fprintf(where,"UDP UNIDIRECTIONAL SEND TEST");
  2448.     fprintf(where," to %s", remote_host);
  2449.     if (iteration_max > 1) {
  2450.       fprintf(where,
  2451.           " : +/-%3.1f%% @ %2d%% conf.",
  2452.           interval/0.02,
  2453.           confidence_level);
  2454.       }
  2455.     if (loc_sndavoid || 
  2456.     loc_rcvavoid ||
  2457.     rem_sndavoid ||
  2458.     rem_rcvavoid) {
  2459.       fprintf(where," : copy avoidance");
  2460.     }
  2461. #ifdef HISTOGRAM
  2462.     fprintf(where," : histogram");
  2463. #endif /* HISTOGRAM */
  2464. #ifdef INTERVALS
  2465.     fprintf(where," : interval");
  2466. #endif /* INTERVALS */
  2467. #ifdef DIRTY 
  2468.     fprintf(where," : dirty data");
  2469. #endif /* DIRTY */
  2470.     fprintf(where,"\n");
  2471.   }    
  2472.   
  2473.   send_ring            = NULL;
  2474.   confidence_iteration = 1;
  2475.   init_stat();
  2476.   sum_messages_sent    = 0;
  2477.   sum_messages_recvd   = 0;
  2478.   sum_failed_sends     = 0;
  2479.   sum_local_thruput    = 0.0;
  2480.  
  2481.   /* we have a great-big while loop which controls the number of times */
  2482.   /* we run a particular test. this is for the calculation of a */
  2483.   /* confidence interval (I really should have stayed awake during */
  2484.   /* probstats :). If the user did not request confidence measurement */
  2485.   /* (no confidence is the default) then we will only go though the */
  2486.   /* loop once. the confidence stuff originates from the folks at IBM */
  2487.  
  2488.   while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
  2489.      (confidence_iteration <= iteration_min)) {
  2490.     
  2491.     /* initialize a few counters. we have to remember that we might be */
  2492.     /* going through the loop more than once. */
  2493.     messages_sent  = 0;
  2494.     messages_recvd = 0;
  2495.     failed_sends   = 0;
  2496.     times_up       = 0;
  2497.     
  2498.     /*set up the data socket            */
  2499.     data_socket = create_data_socket(AF_INET,
  2500.                      SOCK_DGRAM);
  2501.     
  2502.     if (data_socket < 0){
  2503.       perror("udp_send: data socket");
  2504.       exit(1);
  2505.     }
  2506.     
  2507.     /* now, we want to see if we need to set the send_size */
  2508.     if (send_size == 0) {
  2509.       if (lss_size > 0) {
  2510.     send_size = lss_size;
  2511.       }
  2512.       else {
  2513.     send_size = 4096;
  2514.       }
  2515.     }
  2516.     
  2517.     
  2518.     /* set-up the data buffer with the requested alignment and offset, */
  2519.     /* most of the numbers here are just a hack to pick something nice */
  2520.     /* and big in an attempt to never try to send a buffer a second time */
  2521.     /* before it leaves the node...unless the user set the width */
  2522.     /* explicitly. */
  2523.     if (send_width == 0) send_width = 32;
  2524.     
  2525.     if (send_ring == NULL ) {
  2526.       send_ring = allocate_buffer_ring(send_width,
  2527.                        send_size,
  2528.                        local_send_align,
  2529.                        local_send_offset);
  2530.     }
  2531.     
  2532.     
  2533.     /* if the user supplied a cpu rate, this call will complete rather */
  2534.     /* quickly, otherwise, the cpu rate will be retured to us for */
  2535.     /* possible display. The Library will keep it's own copy of this data */
  2536.     /* for use elsewhere. We will only display it. (Does that make it */
  2537.     /* "opaque" to us?) */
  2538.     
  2539.     if (local_cpu_usage)
  2540.       local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  2541.     
  2542.     /* Tell the remote end to set up the data connection. The server */
  2543.     /* sends back the port number and alters the socket parameters there. */
  2544.     /* Of course this is a datagram service so no connection is actually */
  2545.     /* set up, the server just sets up the socket and binds it. */
  2546.     
  2547.     netperf_request.content.request_type      = DO_UDP_STREAM;
  2548.     udp_stream_request->recv_buf_size  = rsr_size;
  2549.     udp_stream_request->message_size   = send_size;
  2550.     udp_stream_request->recv_alignment = remote_recv_align;
  2551.     udp_stream_request->recv_offset    = remote_recv_offset;
  2552.     udp_stream_request->measure_cpu    = remote_cpu_usage;
  2553.     udp_stream_request->cpu_rate       = remote_cpu_rate;
  2554.     udp_stream_request->test_length    = test_time;
  2555.     udp_stream_request->so_rcvavoid    = rem_rcvavoid;
  2556.     udp_stream_request->so_sndavoid    = rem_sndavoid;
  2557.     
  2558.     send_request();
  2559.     
  2560.     recv_response();
  2561.     
  2562.     if (!netperf_response.content.serv_errno) {
  2563.       if (debug)
  2564.     fprintf(where,"send_udp_stream: remote data connection done.\n");
  2565.     }
  2566.     else {
  2567.       errno = netperf_response.content.serv_errno;
  2568.       perror("send_udp_stream: error on remote");
  2569.       exit(1);
  2570.     }
  2571.     
  2572.     /* Place the port number returned by the remote into the sockaddr */
  2573.     /* structure so our sends can be sent to the correct place. Also get */
  2574.     /* some of the returned socket buffer information for user display. */
  2575.     
  2576.     /* make sure that port numbers are in the proper order */
  2577.     server.sin_port = udp_stream_response->data_port_number;
  2578.     server.sin_port = htons(server.sin_port);
  2579.     rsr_size        = udp_stream_response->recv_buf_size;
  2580.     rss_size        = udp_stream_response->send_buf_size;
  2581.     remote_cpu_rate = udp_stream_response->cpu_rate;
  2582.     
  2583.     /* We "connect" up to the remote post to allow is to use the send */
  2584.     /* call instead of the sendto call. Presumeably, this is a little */
  2585.     /* simpler, and a little more efficient. I think that it also means */
  2586.     /* that we can be informed of certain things, but am not sure */
  2587.     /* yet...also, this is the way I would expect a client to behave */
  2588.     /* when talking to a server */
  2589.     
  2590.     if (connect(data_socket,
  2591.         (struct sockaddr *)&server,
  2592.         sizeof(server)) <0){
  2593.       perror("send_udp_stream: data socket connect failed");
  2594.       exit(1);
  2595.     }
  2596.     
  2597.     /* set up the timer to call us after test_time. one of these days, */
  2598.     /* it might be nice to figure-out a nice reliable way to have the */
  2599.     /* test controlled by a byte count as well, but since UDP is not */
  2600.     /* reliable, that could prove difficult. so, in the meantime, we */
  2601.     /* only allow a UDP_STREAM test to be a timed test. */
  2602.     
  2603.     if (test_time) {
  2604.       times_up = 0;
  2605.       start_timer(test_time);
  2606.     }
  2607.     else {
  2608.       fprintf(where,"Sorry, UDP_STREAM tests must be timed.\n");
  2609.       fflush(where);
  2610.     }
  2611.     
  2612.     /* Get the start count for the idle counter and the start time */
  2613.     
  2614.     cpu_start(local_cpu_usage);
  2615.     
  2616. #ifdef INTERVALS
  2617.     if ((interval_burst) || (demo_mode)) {
  2618.       /* zero means that we never pause, so we never should need the */
  2619.       /* interval timer, unless we are in demo_mode */
  2620.       start_itimer(interval_wate);
  2621.     }
  2622.     interval_count = interval_burst;
  2623.     /* get the signal set for the call to sigsuspend */
  2624.     if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
  2625.       fprintf(where,
  2626.           "send_udp_stream: unable to get sigmask errno %d\n",
  2627.           errno);
  2628.       fflush(where);
  2629.       exit(1);
  2630.     }
  2631. #endif /* INTERVALS */
  2632.     
  2633.     /* Send datagrams like there was no tomorrow. at somepoint it might */
  2634.     /* be nice to set this up so that a quantity of bytes could be sent, */
  2635.     /* but we still need some sort of end of test trigger on the receive */
  2636.     /* side. that could be a select with a one second timeout, but then */
  2637.     /* if there is a test where none of the data arrives for awile and */
  2638.     /* then starts again, we would end the test too soon. something to */
  2639.     /* think about... */
  2640.     while (!times_up) {
  2641.       
  2642. #ifdef DIRTY
  2643.       /* we want to dirty some number of consecutive integers in the buffer */
  2644.       /* we are about to send. we may also want to bring some number of */
  2645.       /* them cleanly into the cache. The clean ones will follow any dirty */
  2646.       /* ones into the cache. */
  2647.       message_int_ptr = (int *)(send_ring->buffer_ptr);
  2648.       for (i = 0; i < loc_dirty_count; i++) {
  2649.     *message_int_ptr = 4;
  2650.     message_int_ptr++;
  2651.       }
  2652.       for (i = 0; i < loc_clean_count; i++) {
  2653.     loc_dirty_count = *message_int_ptr;
  2654.     message_int_ptr++;
  2655.       }
  2656. #endif /* DIRTY */
  2657.       
  2658. #ifdef HISTOGRAM
  2659.       gettimeofday(&time_one,NULL);
  2660. #endif /* HISTOGRAM */
  2661.       
  2662.       if ((len=send(data_socket,
  2663.             send_ring->buffer_ptr,
  2664.             send_size,
  2665.             0))  != send_size) {
  2666.       if ((len >= 0) || 
  2667. #ifdef WIN32
  2668.           (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ))
  2669. #else
  2670.       (errno == EINTR))
  2671. #endif /* WIN32 */
  2672.               break;
  2673. #ifdef WIN32
  2674.       if (WSAGetLastError() == WSAENOBUFS) {
  2675. #else
  2676.     if (errno == ENOBUFS) {
  2677. #endif /* WIN32 */
  2678.       failed_sends++;
  2679.       continue;
  2680.     }
  2681.     perror("udp_send: data send error");
  2682.     exit(1);
  2683.       }
  2684.       messages_sent++;          
  2685.       
  2686.       /* now we want to move our pointer to the next position in the */
  2687.       /* data buffer... */
  2688.       
  2689.       send_ring = send_ring->next;
  2690.       
  2691.       
  2692. #ifdef HISTOGRAM
  2693.       /* get the second timestamp */
  2694.       gettimeofday(&time_two,NULL);
  2695.       HIST_add(time_hist,delta_micro(&time_one,&time_two));
  2696. #endif /* HISTOGRAM */
  2697. #ifdef INTERVALS      
  2698.       if (demo_mode) {
  2699.     units_this_tick += send_size;
  2700.       }
  2701.       /* in this case, the interval count is the count-down couter */
  2702.       /* to decide to sleep for a little bit */
  2703.       if ((interval_burst) && (--interval_count == 0)) {
  2704.     /* call sigsuspend and wait for the interval timer to get us */
  2705.     /* out */
  2706.     if (debug) {
  2707.       fprintf(where,"about to suspend\n");
  2708.       fflush(where);
  2709.     }
  2710.     if (sigsuspend(&signal_set) == EFAULT) {
  2711.       fprintf(where,
  2712.           "send_udp_stream: fault with signal set!\n");
  2713.       fflush(where);
  2714.       exit(1);
  2715.     }
  2716.     interval_count = interval_burst;
  2717.       }
  2718. #endif /* INTERVALS */
  2719.       
  2720.     }
  2721.     
  2722.     /* This is a timed test, so the remote will be returning to us after */
  2723.     /* a time. We should not need to send any "strange" messages to tell */
  2724.     /* the remote that the test is completed, unless we decide to add a */
  2725.     /* number of messages to the test. */
  2726.     
  2727.     /* the test is over, so get stats and stuff */
  2728.     cpu_stop(local_cpu_usage,    
  2729.          &elapsed_time);
  2730.     
  2731.     /* Get the statistics from the remote end    */
  2732.     recv_response();
  2733.     if (!netperf_response.content.serv_errno) {
  2734.       if (debug)
  2735.     fprintf(where,"send_udp_stream: remote results obtained\n");
  2736.     }
  2737.     else {
  2738.       errno = netperf_response.content.serv_errno;
  2739.       perror("send_udp_stream: error on remote");
  2740.       exit(1);
  2741.     }
  2742.     
  2743.     bytes_sent    = (double) send_size * (double) messages_sent;
  2744.     local_thruput = (double) calc_thruput(bytes_sent);
  2745.     
  2746.     messages_recvd = udp_stream_results->messages_recvd;
  2747.     bytes_recvd    = (double) send_size * (double) messages_recvd;
  2748.     
  2749.     /* we asume that the remote ran for as long as we did */
  2750.     
  2751.     remote_thruput = (double) calc_thruput(bytes_recvd);
  2752.     
  2753.     /* print the results for this socket and message size */
  2754.     
  2755.     if (local_cpu_usage || remote_cpu_usage) {
  2756.       /* We must now do a little math for service demand and cpu */
  2757.       /* utilization for the system(s) We pass zeros for the local */
  2758.       /* cpu utilization and elapsed time to tell the routine to use */
  2759.       /* the libraries own values for those. */
  2760.       if (local_cpu_usage) {
  2761.     local_cpu_utilization    = calc_cpu_util(0.0);
  2762.     /* shouldn't this really be based on bytes_recvd, since that is */
  2763.     /* the effective throughput of the test? I think that it should, */
  2764.     /* so will make the change raj 11/94 */
  2765.     local_service_demand    = calc_service_demand(bytes_recvd,
  2766.                               0.0,
  2767.                               0.0,
  2768.                               0);
  2769.       }
  2770.       else {
  2771.     local_cpu_utilization    = (float) -1.0;
  2772.     local_service_demand    = (float) -1.0;
  2773.       }
  2774.       
  2775.       /* The local calculations could use variables being kept by */
  2776.       /* the local netlib routines. The remote calcuations need to */
  2777.       /* have a few things passed to them. */
  2778.       if (remote_cpu_usage) {
  2779.     remote_cpu_utilization    = udp_stream_results->cpu_util;
  2780.     remote_service_demand    = calc_service_demand(bytes_recvd,
  2781.                               0.0,
  2782.                               remote_cpu_utilization,
  2783.                               udp_stream_results->num_cpus);
  2784.       }
  2785.       else {
  2786.     remote_cpu_utilization    = (float) -1.0;
  2787.     remote_service_demand    = (float) -1.0;
  2788.       }
  2789.     }
  2790.     else {
  2791.       /* we were not measuring cpu, for the confidence stuff, we */
  2792.       /* should make it -1.0 */
  2793.       local_cpu_utilization  = (float) -1.0;
  2794.       local_service_demand   = (float) -1.0;
  2795.       remote_cpu_utilization = (float) -1.0;
  2796.       remote_service_demand  = (float) -1.0;
  2797.     }
  2798.     
  2799.     /* at this point, we want to calculate the confidence information. */
  2800.     /* if debugging is on, calculate_confidence will print-out the */
  2801.     /* parameters we pass it */
  2802.     
  2803.     calculate_confidence(confidence_iteration,
  2804.              elapsed_time,
  2805.              remote_thruput,
  2806.              local_cpu_utilization,
  2807.              remote_cpu_utilization,
  2808.              local_service_demand,
  2809.              remote_service_demand);
  2810.     
  2811.     /* since the routine calculate_confidence is rather generic, and */
  2812.     /* we have a few other parms of interest, we will do a little work */
  2813.     /* here to caclulate their average. */
  2814.     sum_messages_sent  += messages_sent;
  2815.     sum_messages_recvd += messages_recvd;
  2816.     sum_failed_sends   += failed_sends;
  2817.     sum_local_thruput  += local_thruput;
  2818.     
  2819.     confidence_iteration++;
  2820.  
  2821.     /* this datapoint is done, so we don't need the socket any longer */
  2822.     close(data_socket);
  2823.  
  2824.   }
  2825.  
  2826.   /* we should reach this point once the test is finished */
  2827.  
  2828.   retrieve_confident_values(&elapsed_time,
  2829.                 &remote_thruput,
  2830.                 &local_cpu_utilization,
  2831.                 &remote_cpu_utilization,
  2832.                 &local_service_demand,
  2833.                 &remote_service_demand);
  2834.  
  2835.   /* some of the interesting values aren't covered by the generic */
  2836.   /* confidence routine */
  2837.   messages_sent    = sum_messages_sent / (confidence_iteration -1);
  2838.   messages_recvd   = sum_messages_recvd / (confidence_iteration -1);
  2839.   failed_sends     = sum_failed_sends / (confidence_iteration -1);
  2840.   local_thruput    = sum_local_thruput / (confidence_iteration -1);
  2841.  
  2842.   /* We are now ready to print all the information. If the user */
  2843.   /* has specified zero-level verbosity, we will just print the */
  2844.   /* local service demand, or the remote service demand. If the */
  2845.   /* user has requested verbosity level 1, he will get the basic */
  2846.   /* "streamperf" numbers. If the user has specified a verbosity */
  2847.   /* of greater than 1, we will display a veritable plethora of */
  2848.   /* background information from outside of this block as it it */
  2849.   /* not cpu_measurement specific...  */
  2850.     
  2851.   
  2852.   if (confidence < 0) {
  2853.     /* we did not hit confidence, but were we asked to look for it? */
  2854.     if (iteration_max > 1) {
  2855.       display_confidence();
  2856.     }
  2857.   }
  2858.  
  2859.   if (local_cpu_usage || remote_cpu_usage) {
  2860.     local_cpu_method = format_cpu_method(cpu_method);
  2861.     remote_cpu_method = format_cpu_method(udp_stream_results->cpu_method);
  2862.     
  2863.     switch (verbosity) {
  2864.     case 0:
  2865.       if (local_cpu_usage) {
  2866.     fprintf(where,
  2867.         cpu_fmt_0,
  2868.         local_service_demand,
  2869.         local_cpu_method);
  2870.       }
  2871.       else {
  2872.     fprintf(where,
  2873.         cpu_fmt_0,
  2874.         remote_service_demand,
  2875.         local_cpu_method);
  2876.       }
  2877.       break;
  2878.     case 1:
  2879.     case 2:
  2880.       if (print_headers) {
  2881.     fprintf(where,
  2882.         cpu_title,
  2883.         format_units(),
  2884.         local_cpu_method,
  2885.         remote_cpu_method);
  2886.       }
  2887.  
  2888.       fprintf(where,
  2889.           cpu_fmt_1,        /* the format string */
  2890.           lss_size,                /* local sendbuf size */
  2891.           send_size,        /* how large were the sends */
  2892.           elapsed_time,        /* how long was the test */
  2893.           messages_sent,
  2894.           failed_sends,
  2895.           local_thruput,         /* what was the xfer rate */
  2896.           local_cpu_utilization,    /* local cpu */
  2897.           local_service_demand,    /* local service demand */
  2898.           rsr_size,
  2899.           elapsed_time,
  2900.           messages_recvd,
  2901.           remote_thruput,
  2902.           remote_cpu_utilization,    /* remote cpu */
  2903.           remote_service_demand);    /* remote service demand */
  2904.       break;
  2905.     }
  2906.   }
  2907.   else {
  2908.     /* The tester did not wish to measure service demand. */
  2909.     switch (verbosity) {
  2910.     case 0:
  2911.       fprintf(where,
  2912.           tput_fmt_0,
  2913.           local_thruput);
  2914.       break;
  2915.     case 1:
  2916.     case 2:
  2917.       if (print_headers) {
  2918.     fprintf(where,tput_title,format_units());
  2919.       }
  2920.       fprintf(where,
  2921.           tput_fmt_1,        /* the format string */
  2922.           lss_size,         /* local sendbuf size */
  2923.           send_size,        /* how large were the sends */
  2924.           elapsed_time,         /* how long did it take */
  2925.           messages_sent,
  2926.           failed_sends,
  2927.           local_thruput,
  2928.           rsr_size,         /* remote recvbuf size */
  2929.           elapsed_time,
  2930.           messages_recvd,
  2931.           remote_thruput);
  2932.       break;
  2933.     }
  2934.   }
  2935.  
  2936.   fflush(where);
  2937. #ifdef HISTOGRAM
  2938.   if (verbosity > 1) {
  2939.     fprintf(where,"\nHistogram of time spent in send() call\n");
  2940.     fflush(where);
  2941.     HIST_report(time_hist);
  2942.   }
  2943. #endif /* HISTOGRAM */
  2944.  
  2945. }
  2946.  
  2947.  
  2948.  /* this routine implements the receive side (netserver) of the */
  2949.  /* UDP_STREAM performance test. */
  2950.  
  2951. void
  2952. recv_udp_stream()
  2953. {
  2954.   struct ring_elt *recv_ring;
  2955.  
  2956.   struct sockaddr_in myaddr_in;
  2957.   int    s_data;
  2958.   int     addrlen;
  2959.   int    len = 0;
  2960.   unsigned int    bytes_received = 0;
  2961.   float    elapsed_time;
  2962.   
  2963.   unsigned int    message_size;
  2964.   unsigned int    messages_recvd = 0;
  2965.   
  2966.   struct    udp_stream_request_struct    *udp_stream_request;
  2967.   struct    udp_stream_response_struct    *udp_stream_response;
  2968.   struct    udp_stream_results_struct    *udp_stream_results;
  2969.   
  2970.   udp_stream_request  = 
  2971.     (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
  2972.   udp_stream_response = 
  2973.     (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
  2974.   udp_stream_results  = 
  2975.     (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
  2976.   
  2977.   if (debug) {
  2978.     fprintf(where,"netserver: recv_udp_stream: entered...\n");
  2979.     fflush(where);
  2980.   }
  2981.   
  2982.   /* We want to set-up the listen socket with all the desired */
  2983.   /* parameters and then let the initiator know that all is ready. If */
  2984.   /* socket size defaults are to be used, then the initiator will have */
  2985.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  2986.   /* send-back what they are. If that information cannot be determined, */
  2987.   /* then we send-back -1's for the sizes. If things go wrong for any */
  2988.   /* reason, we will drop back ten yards and punt. */
  2989.   
  2990.   /* If anything goes wrong, we want the remote to know about it. It */
  2991.   /* would be best if the error that the remote reports to the user is */
  2992.   /* the actual error we encountered, rather than some bogus unexpected */
  2993.   /* response type message. */
  2994.   
  2995.   if (debug > 1) {
  2996.     fprintf(where,"recv_udp_stream: setting the response type...\n");
  2997.     fflush(where);
  2998.   }
  2999.   
  3000.   netperf_response.content.response_type = UDP_STREAM_RESPONSE;
  3001.   
  3002.   if (debug > 2) {
  3003.     fprintf(where,"recv_udp_stream: the response type is set...\n");
  3004.     fflush(where);
  3005.   }
  3006.   
  3007.   /* We now alter the message_ptr variable to be at the desired */
  3008.   /* alignment with the desired offset. */
  3009.   
  3010.   if (debug > 1) {
  3011.     fprintf(where,"recv_udp_stream: requested alignment of %d\n",
  3012.         udp_stream_request->recv_alignment);
  3013.     fflush(where);
  3014.   }
  3015.  
  3016.   if (recv_width == 0) recv_width = 1;
  3017.  
  3018.   recv_ring = allocate_buffer_ring(recv_width,
  3019.                    udp_stream_request->message_size,
  3020.                    udp_stream_request->recv_alignment,
  3021.                    udp_stream_request->recv_offset);
  3022.  
  3023.   if (debug > 1) {
  3024.     fprintf(where,"recv_udp_stream: receive alignment and offset set...\n");
  3025.     fflush(where);
  3026.   }
  3027.   
  3028.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  3029.   /* can put in OUR values !-) At some point, we may want to nail this */
  3030.   /* socket to a particular network-level address, but for now, */
  3031.   /* INADDR_ANY should be just fine. */
  3032.   
  3033.   bzero((char *)&myaddr_in,
  3034.     sizeof(myaddr_in));
  3035.   myaddr_in.sin_family      = AF_INET;
  3036.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  3037.   myaddr_in.sin_port        = 0;
  3038.   
  3039.   /* Grab a socket to listen on, and then listen on it. */
  3040.   
  3041.   if (debug > 1) {
  3042.     fprintf(where,"recv_udp_stream: grabbing a socket...\n");
  3043.     fflush(where);
  3044.   }
  3045.  
  3046.   /* create_data_socket expects to find some things in the global */
  3047.   /* variables, so set the globals based on the values in the request. */
  3048.   /* once the socket has been created, we will set the response values */
  3049.   /* based on the updated value of those globals. raj 7/94 */
  3050.   lsr_size = udp_stream_request->recv_buf_size;
  3051.   loc_rcvavoid = udp_stream_request->so_rcvavoid;
  3052.   loc_sndavoid = udp_stream_request->so_sndavoid;
  3053.     
  3054.   s_data = create_data_socket(AF_INET,
  3055.                   SOCK_DGRAM);
  3056.   
  3057.   if (s_data < 0) {
  3058.     netperf_response.content.serv_errno = errno;
  3059.     send_response();
  3060.     exit(1);
  3061.   }
  3062.   
  3063.   /* Let's get an address assigned to this socket so we can tell the */
  3064.   /* initiator how to reach the data socket. There may be a desire to */
  3065.   /* nail this socket to a specific IP address in a multi-homed, */
  3066.   /* multi-connection situation, but for now, we'll ignore the issue */
  3067.   /* and concentrate on single connection testing. */
  3068.   
  3069.   if (bind(s_data,
  3070.        (struct sockaddr *)&myaddr_in,
  3071.        sizeof(myaddr_in)) == -1) {
  3072.     netperf_response.content.serv_errno = errno;
  3073.     send_response();
  3074.     exit(1);
  3075.   }
  3076.   
  3077.   udp_stream_response->test_length = udp_stream_request->test_length;
  3078.   
  3079.   /* now get the port number assigned by the system  */
  3080.   addrlen = sizeof(myaddr_in);
  3081.   if (getsockname(s_data, 
  3082.           (struct sockaddr *)&myaddr_in,
  3083.           &addrlen) == -1){
  3084.     netperf_response.content.serv_errno = errno;
  3085.     close(s_data);
  3086.     send_response();
  3087.     
  3088.     exit(1);
  3089.   }
  3090.   
  3091.   /* Now myaddr_in contains the port and the internet address this is */
  3092.   /* returned to the sender also implicitly telling the sender that the */
  3093.   /* socket buffer sizing has been done. */
  3094.   
  3095.   udp_stream_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  3096.   netperf_response.content.serv_errno   = 0;
  3097.   
  3098.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  3099.   /* then we must call the calibrate routine, which will return the max */
  3100.   /* rate back to the initiator. If the CPU was not to be measured, or */
  3101.   /* something went wrong with the calibration, we will return a -1 to */
  3102.   /* the initiator. */
  3103.   
  3104.   udp_stream_response->cpu_rate    = (float)0.0; /* assume no cpu */
  3105.   udp_stream_response->measure_cpu = 0;
  3106.   if (udp_stream_request->measure_cpu) {
  3107.     /* We will pass the rate into the calibration routine. If the */
  3108.     /* user did not specify one, it will be 0.0, and we will do a */
  3109.     /* "real" calibration. Otherwise, all it will really do is */
  3110.     /* store it away... */
  3111.     udp_stream_response->measure_cpu = 1;
  3112.     udp_stream_response->cpu_rate = 
  3113.       calibrate_local_cpu(udp_stream_request->cpu_rate);
  3114.   }
  3115.   
  3116.   message_size    = udp_stream_request->message_size;
  3117.   test_time    = udp_stream_request->test_length;
  3118.   
  3119.   /* before we send the response back to the initiator, pull some of */
  3120.   /* the socket parms from the globals */
  3121.   udp_stream_response->send_buf_size = lss_size;
  3122.   udp_stream_response->recv_buf_size = lsr_size;
  3123.   udp_stream_response->so_rcvavoid = loc_rcvavoid;
  3124.   udp_stream_response->so_sndavoid = loc_sndavoid;
  3125.  
  3126.   send_response();
  3127.   
  3128.   /* Now it's time to start receiving data on the connection. We will */
  3129.   /* first grab the apropriate counters and then start grabbing. */
  3130.   
  3131.   cpu_start(udp_stream_request->measure_cpu);
  3132.   
  3133.   /* The loop will exit when the timer pops, or if we happen to recv a */
  3134.   /* message of less than send_size bytes... */
  3135.   
  3136.   times_up = 0;
  3137.   start_timer(test_time + PAD_TIME);
  3138.   
  3139. #ifdef WIN32
  3140.   /* this is used so the timer thread can close the socket out from */
  3141.   /* under us, which to date is the easiest/cleanest/least */
  3142.   /* Windows-specific way I can find to force the winsock calls to */
  3143.   /* return WSAEINTR with the test is over. anything that will run on */
  3144.   /* 95 and NT and is closer to what netperf expects from Unix signals */
  3145.   /* and such would be appreciated raj 1/96 */
  3146.   win_kludge_socket = s_data;
  3147. #endif /* WIN32 */
  3148.  
  3149.   if (debug) {
  3150.     fprintf(where,"recv_udp_stream: about to enter inner sanctum.\n");
  3151.     fflush(where);
  3152.   }
  3153.   
  3154.   while (!times_up) {
  3155. #ifdef WIN32
  3156.     /* for some reason, winsock does not like calling recv() on a UDP */
  3157.     /* socket, unlike BSD sockets. NIH strikes again :( raj 1/96 */
  3158.     if((len = recvfrom(s_data,
  3159.                recv_ring->buffer_ptr,
  3160.                message_size, 
  3161.                0,0,0)        
  3162.     ) != message_size) {    
  3163.       if ((len == SOCKET_ERROR) &&           
  3164.       (WSAGetLastError() != WSAEINTR))   
  3165.     {                                      
  3166.           netperf_response.content.serv_errno = WSAGetLastError();
  3167.     send_response();
  3168.     exit(1);
  3169.       }
  3170.       break;
  3171.     }
  3172.  
  3173. #else
  3174.       
  3175.     if ((len = recv(s_data, 
  3176.             recv_ring->buffer_ptr,
  3177.             message_size, 
  3178.             0)) != message_size) {
  3179.       if ((len == -1) && (errno != EINTR)) {
  3180.     netperf_response.content.serv_errno = errno;
  3181.     send_response();
  3182.     exit(1);
  3183.       }
  3184.       break;
  3185.     }
  3186. #endif /* WIN32 */
  3187.     messages_recvd++;
  3188.     recv_ring = recv_ring->next;
  3189.   }
  3190.   
  3191.   if (debug) {
  3192.     fprintf(where,"recv_udp_stream: got %d messages.\n",messages_recvd);
  3193.     fflush(where);
  3194.   }
  3195.   
  3196.   
  3197.   /* The loop now exits due timer or < send_size bytes received. in */
  3198.   /* reality, we only really support a timed UDP_STREAM test. raj */
  3199.   /* 12/95 */
  3200.   
  3201.   cpu_stop(udp_stream_request->measure_cpu,&elapsed_time);
  3202.   
  3203.   if (times_up) {
  3204.     /* we ended on a timer, subtract the PAD_TIME */
  3205.     elapsed_time -= (float)PAD_TIME;
  3206.   }
  3207.   else {
  3208.     stop_timer();
  3209.   }
  3210.   
  3211.   if (debug) {
  3212.     fprintf(where,"recv_udp_stream: test ended in %f seconds.\n",elapsed_time);
  3213.     fflush(where);
  3214.   }
  3215.   
  3216.   
  3217.   /* We will count the "off" message that got us out of the loop */
  3218.   bytes_received = (messages_recvd * message_size) + len;
  3219.   
  3220.   /* send the results to the sender            */
  3221.   
  3222.   if (debug) {
  3223.     fprintf(where,
  3224.         "recv_udp_stream: got %d bytes\n",
  3225.         bytes_received);
  3226.     fflush(where);
  3227.   }
  3228.   
  3229.   netperf_response.content.response_type    = UDP_STREAM_RESULTS;
  3230.   udp_stream_results->bytes_received    = htond(bytes_received);
  3231.   udp_stream_results->messages_recvd    = messages_recvd;
  3232.   udp_stream_results->elapsed_time    = elapsed_time;
  3233.   udp_stream_results->cpu_method        = cpu_method;
  3234.   udp_stream_results->num_cpus          = lib_num_loc_cpus;
  3235.   if (udp_stream_request->measure_cpu) {
  3236.     udp_stream_results->cpu_util    = calc_cpu_util(elapsed_time);
  3237.   }
  3238.   else {
  3239.     udp_stream_results->cpu_util    = (float) -1.0;
  3240.   }
  3241.   
  3242.   if (debug > 1) {
  3243.     fprintf(where,
  3244.         "recv_udp_stream: test complete, sending results.\n");
  3245.     fflush(where);
  3246.   }
  3247.   
  3248.   send_response();
  3249.  
  3250.   close(s_data);
  3251.  
  3252. }
  3253.  
  3254. void
  3255. send_udp_rr(remote_host)
  3256. char    remote_host[];
  3257. {
  3258.   
  3259.   char *tput_title = "\
  3260. Local /Remote\n\
  3261. Socket Size   Request  Resp.   Elapsed  Trans.\n\
  3262. Send   Recv   Size     Size    Time     Rate         \n\
  3263. bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
  3264.   
  3265.   char *tput_fmt_0 =
  3266.     "%7.2f\n";
  3267.   
  3268.   char *tput_fmt_1_line_1 = "\
  3269. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
  3270.   char *tput_fmt_1_line_2 = "\
  3271. %-6d %-6d\n";
  3272.   
  3273.   char *cpu_title = "\
  3274. Local /Remote\n\
  3275. Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
  3276. Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
  3277. bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
  3278.   
  3279.   char *cpu_fmt_0 =
  3280.     "%6.3f %c\n";
  3281.   
  3282.   char *cpu_fmt_1_line_1 = "\
  3283. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
  3284.   
  3285.   char *cpu_fmt_1_line_2 = "\
  3286. %-6d %-6d\n";
  3287.   
  3288.   float            elapsed_time;
  3289.   
  3290.   struct ring_elt *send_ring;
  3291.   struct ring_elt *recv_ring;
  3292.  
  3293.   int    len;
  3294.   int    nummessages;
  3295.   int    send_socket;
  3296.   int    trans_remaining;
  3297.   int    bytes_xferd;
  3298.   
  3299.   int    rsp_bytes_recvd;
  3300.   
  3301.   float    local_cpu_utilization;
  3302.   float    local_service_demand;
  3303.   float    remote_cpu_utilization;
  3304.   float    remote_service_demand;
  3305.   double    thruput;
  3306.   
  3307.   struct    hostent            *hp;
  3308.   struct    sockaddr_in    server, myaddr_in;
  3309.   unsigned      int             addr;
  3310.   int                            addrlen;
  3311.   
  3312.   struct    udp_rr_request_struct    *udp_rr_request;
  3313.   struct    udp_rr_response_struct    *udp_rr_response;
  3314.   struct    udp_rr_results_struct    *udp_rr_result;
  3315.  
  3316. #ifdef INTERVALS
  3317.   int    interval_count;
  3318.   sigset_t signal_set;
  3319. #endif /* INTERVALS */
  3320.   
  3321.   udp_rr_request  =
  3322.     (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
  3323.   udp_rr_response =
  3324.     (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
  3325.   udp_rr_result     =
  3326.     (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
  3327.   
  3328. #ifdef HISTOGRAM
  3329.   time_hist = HIST_new();
  3330. #endif
  3331.   
  3332.   /* since we are now disconnected from the code that established the */
  3333.   /* control socket, and since we want to be able to use different */
  3334.   /* protocols and such, we are passed the name of the remote host and */
  3335.   /* must turn that into the test specific addressing information. */
  3336.   
  3337.   bzero((char *)&server,
  3338.     sizeof(server));
  3339.   
  3340.  /* it would seem that while HP-UX will allow an IP address (as a */
  3341.  /* string) in a call to gethostbyname, other, less enlightened */
  3342.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  3343.   if ((hp = gethostbyname(remote_host)) == NULL) {
  3344.     if ((addr = inet_addr(remote_host)) == -1) {
  3345.       fprintf(where,
  3346.           "send_udp_rr: could not resolve the name %s\n",
  3347.           remote_host);
  3348.       fflush(where);
  3349.       exit(1);
  3350.     }
  3351.     server.sin_addr.s_addr = addr;
  3352.     server.sin_family = AF_INET;
  3353.   }
  3354.   else {
  3355.     bcopy(hp->h_addr,
  3356.       (char *)&server.sin_addr,
  3357.       hp->h_length);
  3358.     server.sin_family = hp->h_addrtype;
  3359.   }
  3360.   
  3361.   
  3362.   if ( print_headers ) {
  3363.     fprintf(where,"UDP REQUEST/RESPONSE TEST");
  3364.         fprintf(where," to %s", remote_host);
  3365.     if (iteration_max > 1) {
  3366.       fprintf(where,
  3367.           " : +/-%3.1f%% @ %2d%% conf.",
  3368.           interval/0.02,
  3369.           confidence_level);
  3370.       }
  3371.     if (loc_sndavoid || 
  3372.     loc_rcvavoid ||
  3373.     rem_sndavoid ||
  3374.     rem_rcvavoid) {
  3375.       fprintf(where," : copy avoidance");
  3376.     }
  3377. #ifdef HISTOGRAM
  3378.     fprintf(where," : histogram");
  3379. #endif /* HISTOGRAM */
  3380. #ifdef INTERVALS
  3381.     fprintf(where," : interval");
  3382. #endif /* INTERVALS */
  3383. #ifdef DIRTY 
  3384.     fprintf(where," : dirty data");
  3385. #endif /* DIRTY */
  3386.     fprintf(where,"\n");
  3387.   }
  3388.   
  3389.   /* initialize a few counters */
  3390.   
  3391.   send_ring     = NULL;
  3392.   recv_ring     = NULL;
  3393.   nummessages    = 0;
  3394.   bytes_xferd    = 0;
  3395.   times_up     = 0;
  3396.   confidence_iteration = 1;
  3397.   init_stat();
  3398.  
  3399.   /* we have a great-big while loop which controls the number of times */
  3400.   /* we run a particular test. this is for the calculation of a */
  3401.   /* confidence interval (I really should have stayed awake during */
  3402.   /* probstats :). If the user did not request confidence measurement */
  3403.   /* (no confidence is the default) then we will only go though the */
  3404.   /* loop once. the confidence stuff originates from the folks at IBM */
  3405.  
  3406.   while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
  3407.      (confidence_iteration <= iteration_min)) {
  3408.     
  3409.     nummessages     = 0;
  3410.     bytes_xferd     = 0.0;
  3411.     times_up        = 0;
  3412.     trans_remaining = 0;
  3413.     
  3414.     /* set-up the data buffers with the requested alignment and offset */
  3415.     
  3416.     if (send_width == 0) send_width = 1;
  3417.     if (recv_width == 0) recv_width = 1;
  3418.     
  3419.     if (send_ring == NULL) {
  3420.       send_ring = allocate_buffer_ring(send_width,
  3421.                        req_size,
  3422.                        local_send_align,
  3423.                        local_send_offset);
  3424.     }
  3425.     
  3426.     if (recv_ring == NULL) {
  3427.       recv_ring = allocate_buffer_ring(recv_width,
  3428.                        rsp_size,
  3429.                        local_recv_align,
  3430.                        local_recv_offset);
  3431.     }
  3432.     
  3433.     /*set up the data socket                        */
  3434.     send_socket = create_data_socket(AF_INET, 
  3435.                      SOCK_DGRAM);
  3436.     
  3437.     if (send_socket < 0){
  3438.       perror("netperf: send_udp_rr: udp rr data socket");
  3439.       exit(1);
  3440.     }
  3441.     
  3442.     if (debug) {
  3443.       fprintf(where,"send_udp_rr: send_socket obtained...\n");
  3444.     }
  3445.     
  3446.     /* If the user has requested cpu utilization measurements, we must */
  3447.     /* calibrate the cpu(s). We will perform this task within the tests */
  3448.     /* themselves. If the user has specified the cpu rate, then */
  3449.     /* calibrate_local_cpu will return rather quickly as it will have */
  3450.     /* nothing to do. If local_cpu_rate is zero, then we will go through */
  3451.     /* all the "normal" calibration stuff and return the rate back. If */
  3452.     /* there is no idle counter in the kernel idle loop, the */
  3453.     /* local_cpu_rate will be set to -1. */
  3454.     
  3455.     if (local_cpu_usage) {
  3456.       local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  3457.     }
  3458.     
  3459.     /* Tell the remote end to do a listen. The server alters the socket */
  3460.     /* paramters on the other side at this point, hence the reason for */
  3461.     /* all the values being passed in the setup message. If the user did */
  3462.     /* not specify any of the parameters, they will be passed as 0, which */
  3463.     /* will indicate to the remote that no changes beyond the system's */
  3464.     /* default should be used. Alignment is the exception, it will */
  3465.     /* default to 8, which will be no alignment alterations. */
  3466.     
  3467.     netperf_request.content.request_type    = DO_UDP_RR;
  3468.     udp_rr_request->recv_buf_size    = rsr_size;
  3469.     udp_rr_request->send_buf_size    = rss_size;
  3470.     udp_rr_request->recv_alignment      = remote_recv_align;
  3471.     udp_rr_request->recv_offset            = remote_recv_offset;
  3472.     udp_rr_request->send_alignment      = remote_send_align;
  3473.     udp_rr_request->send_offset            = remote_send_offset;
  3474.     udp_rr_request->request_size    = req_size;
  3475.     udp_rr_request->response_size    = rsp_size;
  3476.     udp_rr_request->measure_cpu            = remote_cpu_usage;
  3477.     udp_rr_request->cpu_rate            = remote_cpu_rate;
  3478.     udp_rr_request->so_rcvavoid            = rem_rcvavoid;
  3479.     udp_rr_request->so_sndavoid            = rem_sndavoid;
  3480.     if (test_time) {
  3481.       udp_rr_request->test_length    = test_time;
  3482.     }
  3483.     else {
  3484.       udp_rr_request->test_length    = test_trans * -1;
  3485.     }
  3486.     
  3487.     if (debug > 1) {
  3488.       fprintf(where,"netperf: send_udp_rr: requesting UDP r/r test\n");
  3489.     }
  3490.     
  3491.     send_request();
  3492.     
  3493.     /* The response from the remote will contain all of the relevant     */
  3494.     /* socket parameters for this test type. We will put them back into */
  3495.     /* the variables here so they can be displayed if desired.  The    */
  3496.     /* remote will have calibrated CPU if necessary, and will have done    */
  3497.     /* all the needed set-up we will have calibrated the cpu locally    */
  3498.     /* before sending the request, and will grab the counter value right*/
  3499.     /* after the connect returns. The remote will grab the counter right*/
  3500.     /* after the accept call. This saves the hassle of extra messages    */
  3501.     /* being sent for the UDP tests.                    */
  3502.     
  3503.     recv_response();
  3504.     
  3505.     if (!netperf_response.content.serv_errno) {
  3506.       if (debug)
  3507.     fprintf(where,"remote listen done.\n");
  3508.       rsr_size           =    udp_rr_response->recv_buf_size;
  3509.       rss_size           =    udp_rr_response->send_buf_size;
  3510.       remote_cpu_usage =    udp_rr_response->measure_cpu;
  3511.       remote_cpu_rate  =     udp_rr_response->cpu_rate;
  3512.       /* port numbers in proper order */
  3513.       server.sin_port  =    udp_rr_response->data_port_number;
  3514.       server.sin_port  =     htons(server.sin_port);
  3515.     }
  3516.     else {
  3517.       errno = netperf_response.content.serv_errno;
  3518.       fprintf(where,
  3519.           "netperf: remote error %d",
  3520.           netperf_response.content.serv_errno);
  3521.       perror("");
  3522.       fflush(where);
  3523.       exit(1);
  3524.     }
  3525.     
  3526.     /* Connect up to the remote port on the data socket. This will set */
  3527.     /* the default destination address on this socket. With UDP, this */
  3528.     /* does make a performance difference as we may not have to do as */
  3529.     /* many routing lookups, however, I expect that a client would */
  3530.     /* behave this way. raj 1/94 */
  3531.     
  3532.     if ( connect(send_socket, 
  3533.          (struct sockaddr *)&server,
  3534.          sizeof(server)) < 0 ) {
  3535.       perror("netperf: data socket connect failed");
  3536.       exit(1);
  3537.     }
  3538.     
  3539.     /* now get the port number assigned by the system  */
  3540.     addrlen = sizeof(myaddr_in);
  3541.     if (getsockname(send_socket, 
  3542.             (struct sockaddr *)&myaddr_in,
  3543.             &addrlen) == -1){
  3544.       perror("send_udp_rr: getsockname");
  3545.       exit(1);
  3546.     }
  3547.     
  3548.     /* Data Socket set-up is finished. If there were problems, either the */
  3549.     /* connect would have failed, or the previous response would have */
  3550.     /* indicated a problem. I failed to see the value of the extra */
  3551.     /* message after the accept on the remote. If it failed, we'll see it */
  3552.     /* here. If it didn't, we might as well start pumping data. */
  3553.     
  3554.     /* Set-up the test end conditions. For a request/response test, they */
  3555.     /* can be either time or transaction based. */
  3556.     
  3557.     if (test_time) {
  3558.       /* The user wanted to end the test after a period of time. */
  3559.       times_up = 0;
  3560.       trans_remaining = 0;
  3561.       start_timer(test_time);
  3562.     }
  3563.     else {
  3564.       /* The tester wanted to send a number of bytes. */
  3565.       trans_remaining = test_bytes;
  3566.       times_up = 1;
  3567.     }
  3568.     
  3569.     /* The cpu_start routine will grab the current time and possibly */
  3570.     /* value of the idle counter for later use in measuring cpu */
  3571.     /* utilization and/or service demand and thruput. */
  3572.     
  3573.     cpu_start(local_cpu_usage);
  3574.  
  3575. #ifdef INTERVALS
  3576.     if ((interval_burst) || (demo_mode)) {
  3577.       /* zero means that we never pause, so we never should need the */
  3578.       /* interval timer, unless we are in demo_mode */
  3579.       start_itimer(interval_wate);
  3580.     }
  3581.     interval_count = interval_burst;
  3582.     /* get the signal set for the call to sigsuspend */
  3583.     if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
  3584.       fprintf(where,
  3585.           "send_udp_rr: unable to get sigmask errno %d\n",
  3586.           errno);
  3587.       fflush(where);
  3588.       exit(1);
  3589.     }
  3590. #endif /* INTERVALS */
  3591.     
  3592.     /* We use an "OR" to control test execution. When the test is */
  3593.     /* controlled by time, the byte count check will always return */
  3594.     /* false. When the test is controlled by byte count, the time test */
  3595.     /* will always return false. When the test is finished, the whole */
  3596.     /* expression will go false and we will stop sending data. I think */
  3597.     /* I just arbitrarily decrement trans_remaining for the timed */
  3598.     /* test, but will not do that just yet... One other question is */
  3599.     /* whether or not the send buffer and the receive buffer should be */
  3600.     /* the same buffer. */
  3601.  
  3602.     while ((!times_up) || (trans_remaining > 0)) {
  3603.       /* send the request */
  3604. #ifdef HISTOGRAM
  3605.       gettimeofday(&time_one,NULL);
  3606. #endif
  3607.       if((len=send(send_socket,
  3608.            send_ring->buffer_ptr,
  3609.            req_size,
  3610.            0)) != req_size) {
  3611. #ifdef WIN32
  3612.       if (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  3613. #else
  3614.       if (errno == EINTR) {
  3615. #endif /* WIN32 */
  3616.       /* We likely hit */
  3617.       /* test-end time. */
  3618.       break;
  3619.     }
  3620.     perror("send_udp_rr: data send error");
  3621.     exit(1);
  3622.       }
  3623.       send_ring = send_ring->next;
  3624.       
  3625.       /* receive the response. with UDP we will get it all, or nothing */
  3626.       
  3627.       if((rsp_bytes_recvd=recv(send_socket,
  3628.                    recv_ring->buffer_ptr,
  3629.                    rsp_size,
  3630.                    0)) != rsp_size) {
  3631. #ifdef WIN32
  3632.     if (rsp_bytes_recvd == SOCKET_ERROR && 
  3633.         WSAGetLastError() == WSAEINTR) {
  3634. #else
  3635.     if (errno == EINTR) {
  3636. #endif /* WIN32 */
  3637.       /* Again, we have likely hit test-end time */
  3638.       break;
  3639.     }
  3640.     perror("send_udp_rr: data recv error");
  3641.     exit(1);
  3642.       }
  3643.       recv_ring = recv_ring->next;
  3644.       
  3645. #ifdef HISTOGRAM
  3646.       gettimeofday(&time_two,NULL);
  3647.       HIST_add(time_hist,delta_micro(&time_one,&time_two));
  3648.       
  3649.       /* at this point, we may wish to sleep for some period of */
  3650.       /* time, so we see how long that last transaction just took, */
  3651.       /* and sleep for the difference of that and the interval. We */
  3652.       /* will not sleep if the time would be less than a */
  3653.       /* millisecond.  */
  3654. #endif
  3655. #ifdef INTERVALS      
  3656.       if (demo_mode) {
  3657.     units_this_tick += 1;
  3658.       }
  3659.       /* in this case, the interval count is the count-down couter */
  3660.       /* to decide to sleep for a little bit */
  3661.       if ((interval_burst) && (--interval_count == 0)) {
  3662.     /* call sigsuspend and wait for the interval timer to get us */
  3663.     /* out */
  3664.     if (debug) {
  3665.       fprintf(where,"about to suspend\n");
  3666.       fflush(where);
  3667.     }
  3668.     if (sigsuspend(&signal_set) == EFAULT) {
  3669.       fprintf(where,
  3670.           "send_udp_rr: fault with signal set!\n");
  3671.       fflush(where);
  3672.       exit(1);
  3673.     }
  3674.     interval_count = interval_burst;
  3675.       }
  3676. #endif /* INTERVALS */
  3677.       
  3678.       nummessages++;          
  3679.       if (trans_remaining) {
  3680.     trans_remaining--;
  3681.       }
  3682.       
  3683.       if (debug > 3) {
  3684.     if ((nummessages % 100) == 0) {
  3685.       fprintf(where,"Transaction %d completed\n",nummessages);
  3686.       fflush(where);
  3687.     }
  3688.       }
  3689.       
  3690.     }
  3691.     
  3692.     /* for some strange reason, I used to call shutdown on the UDP */
  3693.     /* data socket here. I'm not sure why, because it would not have */
  3694.     /* any effect... raj 11/94 */
  3695.     
  3696.     /* this call will always give us the elapsed time for the test, and */
  3697.     /* will also store-away the necessaries for cpu utilization */
  3698.     
  3699.     cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
  3700.                         /* measured? how long */
  3701.                         /* did we really run? */
  3702.     
  3703.     /* Get the statistics from the remote end. The remote will have */
  3704.     /* calculated service demand and all those interesting things. If */
  3705.     /* it wasn't supposed to care, it will return obvious values. */
  3706.     
  3707.     recv_response();
  3708.     if (!netperf_response.content.serv_errno) {
  3709.       if (debug)
  3710.     fprintf(where,"remote results obtained\n");
  3711.     }
  3712.     else {
  3713.       errno = netperf_response.content.serv_errno;
  3714.       fprintf(where,
  3715.           "netperf: remote error %d",
  3716.           netperf_response.content.serv_errno);
  3717.       perror("");
  3718.       fflush(where);
  3719.       exit(1);
  3720.     }
  3721.     
  3722.     /* We now calculate what our thruput was for the test. In the */
  3723.     /* future, we may want to include a calculation of the thruput */
  3724.     /* measured by the remote, but it should be the case that for a */
  3725.     /* UDP rr test, that the two numbers should be *very* close... */
  3726.     /* We calculate bytes_sent regardless of the way the test length */
  3727.     /* was controlled.  */
  3728.     
  3729.     bytes_xferd    = (req_size * nummessages) + (rsp_size * nummessages);
  3730.     thruput    = nummessages / elapsed_time;
  3731.     
  3732.     if (local_cpu_usage || remote_cpu_usage) {
  3733.  
  3734.       /* We must now do a little math for service demand and cpu */
  3735.       /* utilization for the system(s) Of course, some of the */
  3736.       /* information might be bogus because there was no idle counter */
  3737.       /* in the kernel(s). We need to make a note of this for the */
  3738.       /* user's benefit by placing a code for the metod used in the */
  3739.       /* test banner */
  3740.  
  3741.       if (local_cpu_usage) {
  3742.     local_cpu_utilization = calc_cpu_util(0.0);
  3743.     
  3744.     /* since calc_service demand is doing ms/Kunit we will */
  3745.     /* multiply the number of transaction by 1024 to get */
  3746.     /* "good" numbers */
  3747.     
  3748.     local_service_demand  = calc_service_demand((double) nummessages*1024,
  3749.                             0.0,
  3750.                             0.0,
  3751.                             0);
  3752.       }
  3753.       else {
  3754.     local_cpu_utilization    = (float) -1.0;
  3755.     local_service_demand    = (float) -1.0;
  3756.       }
  3757.       
  3758.       if (remote_cpu_usage) {
  3759.     remote_cpu_utilization = udp_rr_result->cpu_util;
  3760.     
  3761.     /* since calc_service demand is doing ms/Kunit we will */
  3762.     /* multiply the number of transaction by 1024 to get */
  3763.     /* "good" numbers */
  3764.     
  3765.     remote_service_demand  = calc_service_demand((double) nummessages*1024,
  3766.                              0.0,
  3767.                              remote_cpu_utilization,
  3768.                              udp_rr_result->num_cpus);
  3769.       }
  3770.       else {
  3771.     remote_cpu_utilization = (float) -1.0;
  3772.     remote_service_demand  = (float) -1.0;
  3773.       }
  3774.     }
  3775.     else {
  3776.       /* we were not measuring cpu, for the confidence stuff, we */
  3777.       /* should make it -1.0 */
  3778.       local_cpu_utilization    = (float) -1.0;
  3779.       local_service_demand    = (float) -1.0;
  3780.       remote_cpu_utilization = (float) -1.0;
  3781.       remote_service_demand  = (float) -1.0;
  3782.     }
  3783.     
  3784.     /* at this point, we want to calculate the confidence information. */
  3785.     /* if debugging is on, calculate_confidence will print-out the */
  3786.     /* parameters we pass it */
  3787.     
  3788.     calculate_confidence(confidence_iteration,
  3789.              elapsed_time,
  3790.              thruput,
  3791.              local_cpu_utilization,
  3792.              remote_cpu_utilization,
  3793.              local_service_demand,
  3794.              remote_service_demand);
  3795.     
  3796.     
  3797.     confidence_iteration++;
  3798.     
  3799.     /* we are done with the socket */
  3800.     close(send_socket);
  3801.   }
  3802.  
  3803.   /* at this point, we have made all the iterations we are going to */
  3804.   /* make. */
  3805.   retrieve_confident_values(&elapsed_time,
  3806.                 &thruput,
  3807.                 &local_cpu_utilization,
  3808.                 &remote_cpu_utilization,
  3809.                 &local_service_demand,
  3810.                 &remote_service_demand);
  3811.   
  3812.   /* We are now ready to print all the information. If the user */
  3813.   /* has specified zero-level verbosity, we will just print the */
  3814.   /* local service demand, or the remote service demand. If the */
  3815.   /* user has requested verbosity level 1, he will get the basic */
  3816.   /* "streamperf" numbers. If the user has specified a verbosity */
  3817.   /* of greater than 1, we will display a veritable plethora of */
  3818.   /* background information from outside of this block as it it */
  3819.   /* not cpu_measurement specific...  */
  3820.   
  3821.   if (confidence < 0) {
  3822.     /* we did not hit confidence, but were we asked to look for it? */
  3823.     if (iteration_max > 1) {
  3824.       display_confidence();
  3825.     }
  3826.   }
  3827.   
  3828.   if (local_cpu_usage || remote_cpu_usage) {
  3829.     local_cpu_method = format_cpu_method(cpu_method);
  3830.     remote_cpu_method = format_cpu_method(udp_rr_result->cpu_method);
  3831.     
  3832.     switch (verbosity) {
  3833.     case 0:
  3834.       if (local_cpu_usage) {
  3835.     fprintf(where,
  3836.         cpu_fmt_0,
  3837.         local_service_demand,
  3838.         local_cpu_method);
  3839.       }
  3840.       else {
  3841.     fprintf(where,
  3842.         cpu_fmt_0,
  3843.         remote_service_demand,
  3844.         remote_cpu_method);
  3845.       }
  3846.       break;
  3847.     case 1:
  3848.     case 2:
  3849.       if (print_headers) {
  3850.     fprintf(where,
  3851.         cpu_title,
  3852.         local_cpu_method,
  3853.         remote_cpu_method);
  3854.       }
  3855.     
  3856.       fprintf(where,
  3857.           cpu_fmt_1_line_1,        /* the format string */
  3858.           lss_size,        /* local sendbuf size */
  3859.           lsr_size,
  3860.           req_size,        /* how large were the requests */
  3861.           rsp_size,        /* guess */
  3862.           elapsed_time,        /* how long was the test */
  3863.           nummessages/elapsed_time,
  3864.           local_cpu_utilization,    /* local cpu */
  3865.           remote_cpu_utilization,    /* remote cpu */
  3866.           local_service_demand,    /* local service demand */
  3867.           remote_service_demand);    /* remote service demand */
  3868.       fprintf(where,
  3869.           cpu_fmt_1_line_2,
  3870.           rss_size,
  3871.           rsr_size);
  3872.       break;
  3873.     }
  3874.   }
  3875.   else {
  3876.     /* The tester did not wish to measure service demand. */
  3877.     switch (verbosity) {
  3878.     case 0:
  3879.       fprintf(where,
  3880.           tput_fmt_0,
  3881.           nummessages/elapsed_time);
  3882.       break;
  3883.     case 1:
  3884.     case 2:
  3885.       if (print_headers) {
  3886.     fprintf(where,tput_title,format_units());
  3887.       }
  3888.     
  3889.       fprintf(where,
  3890.           tput_fmt_1_line_1,    /* the format string */
  3891.           lss_size,
  3892.           lsr_size,
  3893.           req_size,        /* how large were the requests */
  3894.           rsp_size,        /* how large were the responses */
  3895.           elapsed_time,         /* how long did it take */
  3896.           nummessages/elapsed_time);
  3897.       fprintf(where,
  3898.           tput_fmt_1_line_2,
  3899.           rss_size,         /* remote recvbuf size */
  3900.           rsr_size);
  3901.       
  3902.       break;
  3903.     }
  3904.   }
  3905.   fflush(where);
  3906.  
  3907.   /* it would be a good thing to include information about some of the */
  3908.   /* other parameters that may have been set for this test, but at the */
  3909.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  3910.   /* just put this comment here to help remind me that it is something */
  3911.   /* that should be done at a later time. */
  3912.   
  3913.   /* how to handle the verbose information in the presence of */
  3914.   /* confidence intervals is yet to be determined... raj 11/94 */
  3915.  
  3916.   if (verbosity > 1) {
  3917.     /* The user wanted to know it all, so we will give it to him. */
  3918.     /* This information will include as much as we can find about */
  3919.     /* UDP statistics, the alignments of the sends and receives */
  3920.     /* and all that sort of rot... */
  3921.     
  3922. #ifdef HISTOGRAM
  3923.     fprintf(where,"\nHistogram of reqeuest/reponse times.\n");
  3924.     fflush(where);
  3925.     HIST_report(time_hist);
  3926. #endif /* HISTOGRAM */
  3927.   }
  3928. }
  3929.  
  3930.  /* this routine implements the receive side (netserver) of a UDP_RR */
  3931.  /* test. */
  3932. void
  3933. recv_udp_rr()
  3934. {
  3935.   
  3936.   struct ring_elt *recv_ring;
  3937.   struct ring_elt *send_ring;
  3938.  
  3939.   struct    sockaddr_in        myaddr_in,
  3940.   peeraddr_in;
  3941.   int    s_data;
  3942.   int     addrlen;
  3943.   int    trans_received;
  3944.   int    trans_remaining;
  3945.   int   request_bytes_recvd;
  3946.   int   response_bytes_sent;
  3947.   float    elapsed_time;
  3948.   
  3949.   struct    udp_rr_request_struct    *udp_rr_request;
  3950.   struct    udp_rr_response_struct    *udp_rr_response;
  3951.   struct    udp_rr_results_struct    *udp_rr_results;
  3952.   
  3953.   udp_rr_request  = 
  3954.     (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
  3955.   udp_rr_response = 
  3956.     (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
  3957.   udp_rr_results  = 
  3958.     (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
  3959.   
  3960.   if (debug) {
  3961.     fprintf(where,"netserver: recv_udp_rr: entered...\n");
  3962.     fflush(where);
  3963.   }
  3964.   
  3965.   /* We want to set-up the listen socket with all the desired */
  3966.   /* parameters and then let the initiator know that all is ready. If */
  3967.   /* socket size defaults are to be used, then the initiator will have */
  3968.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  3969.   /* send-back what they are. If that information cannot be determined, */
  3970.   /* then we send-back -1's for the sizes. If things go wrong for any */
  3971.   /* reason, we will drop back ten yards and punt. */
  3972.   
  3973.   /* If anything goes wrong, we want the remote to know about it. It */
  3974.   /* would be best if the error that the remote reports to the user is */
  3975.   /* the actual error we encountered, rather than some bogus unexpected */
  3976.   /* response type message. */
  3977.   
  3978.   if (debug) {
  3979.     fprintf(where,"recv_udp_rr: setting the response type...\n");
  3980.     fflush(where);
  3981.   }
  3982.   
  3983.   netperf_response.content.response_type = UDP_RR_RESPONSE;
  3984.   
  3985.   if (debug) {
  3986.     fprintf(where,"recv_udp_rr: the response type is set...\n");
  3987.     fflush(where);
  3988.   }
  3989.   
  3990.   /* We now alter the message_ptr variables to be at the desired */
  3991.   /* alignments with the desired offsets. */
  3992.   
  3993.   if (debug) {
  3994.     fprintf(where,"recv_udp_rr: requested recv alignment of %d offset %d\n",
  3995.         udp_rr_request->recv_alignment,
  3996.         udp_rr_request->recv_offset);
  3997.     fprintf(where,"recv_udp_rr: requested send alignment of %d offset %d\n",
  3998.         udp_rr_request->send_alignment,
  3999.         udp_rr_request->send_offset);
  4000.     fflush(where);
  4001.   }
  4002.  
  4003.   if (send_width == 0) send_width = 1;
  4004.   if (recv_width == 0) recv_width = 1;
  4005.  
  4006.   recv_ring = allocate_buffer_ring(recv_width,
  4007.                    udp_rr_request->request_size,
  4008.                    udp_rr_request->recv_alignment,
  4009.                    udp_rr_request->recv_offset);
  4010.  
  4011.   send_ring = allocate_buffer_ring(send_width,
  4012.                    udp_rr_request->response_size,
  4013.                    udp_rr_request->send_alignment,
  4014.                    udp_rr_request->send_offset);
  4015.  
  4016.   if (debug) {
  4017.     fprintf(where,"recv_udp_rr: receive alignment and offset set...\n");
  4018.     fflush(where);
  4019.   }
  4020.   
  4021.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  4022.   /* can put in OUR values !-) At some point, we may want to nail this */
  4023.   /* socket to a particular network-level address, but for now, */
  4024.   /* INADDR_ANY should be just fine. */
  4025.   
  4026.   bzero((char *)&myaddr_in,
  4027.     sizeof(myaddr_in));
  4028.   myaddr_in.sin_family      = AF_INET;
  4029.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  4030.   myaddr_in.sin_port        = 0;
  4031.   
  4032.   /* Grab a socket to listen on, and then listen on it. */
  4033.   
  4034.   if (debug) {
  4035.     fprintf(where,"recv_udp_rr: grabbing a socket...\n");
  4036.     fflush(where);
  4037.   }
  4038.   
  4039.  
  4040.   /* create_data_socket expects to find some things in the global */
  4041.   /* variables, so set the globals based on the values in the request. */
  4042.   /* once the socket has been created, we will set the response values */
  4043.   /* based on the updated value of those globals. raj 7/94 */
  4044.   lss_size = udp_rr_request->send_buf_size;
  4045.   lsr_size = udp_rr_request->recv_buf_size;
  4046.   loc_rcvavoid = udp_rr_request->so_rcvavoid;
  4047.   loc_sndavoid = udp_rr_request->so_sndavoid;
  4048.  
  4049.   s_data = create_data_socket(AF_INET,
  4050.                   SOCK_DGRAM);
  4051.   
  4052.   if (s_data < 0) {
  4053.     netperf_response.content.serv_errno = errno;
  4054.     send_response();
  4055.     
  4056.     exit(1);
  4057.   }
  4058.   
  4059.   /* Let's get an address assigned to this socket so we can tell the */
  4060.   /* initiator how to reach the data socket. There may be a desire to */
  4061.   /* nail this socket to a specific IP address in a multi-homed, */
  4062.   /* multi-connection situation, but for now, we'll ignore the issue */
  4063.   /* and concentrate on single connection testing. */
  4064.   
  4065.   if (bind(s_data,
  4066.        (struct sockaddr *)&myaddr_in,
  4067.        sizeof(myaddr_in)) == -1) {
  4068.     netperf_response.content.serv_errno = errno;
  4069.     close(s_data);
  4070.     send_response();
  4071.     
  4072.     exit(1);
  4073.   }
  4074.   
  4075.   /* now get the port number assigned by the system  */
  4076.   addrlen = sizeof(myaddr_in);
  4077.   if (getsockname(s_data, 
  4078.           (struct sockaddr *)&myaddr_in,
  4079.           &addrlen) == -1){
  4080.     netperf_response.content.serv_errno = errno;
  4081.     close(s_data);
  4082.     send_response();
  4083.     
  4084.     exit(1);
  4085.   }
  4086.   
  4087.   /* Now myaddr_in contains the port and the internet address this is */
  4088.   /* returned to the sender also implicitly telling the sender that the */
  4089.   /* socket buffer sizing has been done. */
  4090.   
  4091.   udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  4092.   netperf_response.content.serv_errno   = 0;
  4093.   
  4094.   fprintf(where,"recv port number %d\n",myaddr_in.sin_port);
  4095.   fflush(where);
  4096.   
  4097.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  4098.   /* then we must call the calibrate routine, which will return the max */
  4099.   /* rate back to the initiator. If the CPU was not to be measured, or */
  4100.   /* something went wrong with the calibration, we will return a 0.0 to */
  4101.   /* the initiator. */
  4102.   
  4103.   udp_rr_response->cpu_rate    = (float)0.0;     /* assume no cpu */
  4104.   udp_rr_response->measure_cpu = 0;
  4105.   if (udp_rr_request->measure_cpu) {
  4106.     udp_rr_response->measure_cpu = 1;
  4107.     udp_rr_response->cpu_rate = calibrate_local_cpu(udp_rr_request->cpu_rate);
  4108.   }
  4109.    
  4110.   /* before we send the response back to the initiator, pull some of */
  4111.   /* the socket parms from the globals */
  4112.   udp_rr_response->send_buf_size = lss_size;
  4113.   udp_rr_response->recv_buf_size = lsr_size;
  4114.   udp_rr_response->so_rcvavoid   = loc_rcvavoid;
  4115.   udp_rr_response->so_sndavoid   = loc_sndavoid;
  4116.  
  4117.   send_response();
  4118.   
  4119.   
  4120.   /* Now it's time to start receiving data on the connection. We will */
  4121.   /* first grab the apropriate counters and then start grabbing. */
  4122.   
  4123.   cpu_start(udp_rr_request->measure_cpu);
  4124.   
  4125.   if (udp_rr_request->test_length > 0) {
  4126.     times_up = 0;
  4127.     trans_remaining = 0;
  4128.     start_timer(udp_rr_request->test_length + PAD_TIME);
  4129.   }
  4130.   else {
  4131.     times_up = 1;
  4132.     trans_remaining = udp_rr_request->test_length * -1;
  4133.   }
  4134.   
  4135. #ifdef WIN32
  4136.   /* this is used so the timer thread can close the socket out from */
  4137.   /* under us, which to date is the easiest/cleanest/least */
  4138.   /* Windows-specific way I can find to force the winsock calls to */
  4139.   /* return WSAEINTR with the test is over. anything that will run on */
  4140.   /* 95 and NT and is closer to what netperf expects from Unix signals */
  4141.   /* and such would be appreciated raj 1/96 */
  4142.   win_kludge_socket = s_data;
  4143. #endif /* WIN32 */
  4144.  
  4145.   addrlen = sizeof(peeraddr_in);
  4146.   bzero((char *)&peeraddr_in, addrlen);
  4147.   
  4148.   trans_received = 0;
  4149.  
  4150.   while ((!times_up) || (trans_remaining > 0)) {
  4151.     
  4152.     /* receive the request from the other side */
  4153.     if ((request_bytes_recvd = recvfrom(s_data,
  4154.          recv_ring->buffer_ptr,
  4155.          udp_rr_request->request_size,
  4156.          0,
  4157.          (struct sockaddr *)&peeraddr_in,
  4158.          &addrlen)) != udp_rr_request->request_size) {
  4159. #ifdef WIN32
  4160.     if ( request_bytes_recvd == SOCKET_ERROR &&
  4161.          WSAGetLastError() == WSAEINTR ) {
  4162. #else
  4163.     if (errno == EINTR) {
  4164. #endif /* WIN32 */
  4165.     /* we must have hit the end of test time. */
  4166.     break;
  4167.       }
  4168.       netperf_response.content.serv_errno = errno;
  4169.       send_response();
  4170.       exit(1);
  4171.     }
  4172.     recv_ring = recv_ring->next;
  4173.  
  4174.     /* Now, send the response to the remote */
  4175.     if ((response_bytes_sent = sendto(s_data,
  4176.                       send_ring->buffer_ptr,
  4177.                       udp_rr_request->response_size,
  4178.                       0,
  4179.                       (struct sockaddr *)&peeraddr_in,
  4180.                       addrlen)) != 
  4181.     udp_rr_request->response_size) {
  4182. #ifdef WIN32
  4183.       if ( response_bytes_sent == SOCKET_ERROR &&
  4184.       WSAGetLastError() == WSAEINTR ) {
  4185. #else
  4186.       if (errno == EINTR) {
  4187. #endif 
  4188.     /* we have hit end of test time. */
  4189.     break;
  4190.       }
  4191.       netperf_response.content.serv_errno = errno;
  4192.       send_response();
  4193.       exit(1);
  4194.     }
  4195.     send_ring = send_ring->next;
  4196.     
  4197.     trans_received++;
  4198.     if (trans_remaining) {
  4199.       trans_remaining--;
  4200.     }
  4201.     
  4202.     if (debug) {
  4203.       fprintf(where,
  4204.           "recv_udp_rr: Transaction %d complete.\n",
  4205.           trans_received);
  4206.       fflush(where);
  4207.     }
  4208.     
  4209.   }
  4210.   
  4211.   
  4212.   /* The loop now exits due to timeout or transaction count being */
  4213.   /* reached */
  4214.   
  4215.   cpu_stop(udp_rr_request->measure_cpu,&elapsed_time);
  4216.   
  4217.   if (times_up) {
  4218.     /* we ended the test by time, which was at least 2 seconds */
  4219.     /* longer than we wanted to run. so, we want to subtract */
  4220.     /* PAD_TIME from the elapsed_time. */
  4221.     elapsed_time -= PAD_TIME;
  4222.   }
  4223.   /* send the results to the sender            */
  4224.   
  4225.   if (debug) {
  4226.     fprintf(where,
  4227.         "recv_udp_rr: got %d transactions\n",
  4228.         trans_received);
  4229.     fflush(where);
  4230.   }
  4231.   
  4232.   udp_rr_results->bytes_received = (trans_received * 
  4233.                     (udp_rr_request->request_size + 
  4234.                      udp_rr_request->response_size));
  4235.   udp_rr_results->trans_received = trans_received;
  4236.   udp_rr_results->elapsed_time     = elapsed_time;
  4237.   udp_rr_results->cpu_method     = cpu_method;
  4238.   udp_rr_results->num_cpus       = lib_num_loc_cpus;
  4239.   if (udp_rr_request->measure_cpu) {
  4240.     udp_rr_results->cpu_util    = calc_cpu_util(elapsed_time);
  4241.   }
  4242.   
  4243.   if (debug) {
  4244.     fprintf(where,
  4245.         "recv_udp_rr: test complete, sending results.\n");
  4246.     fflush(where);
  4247.   }
  4248.   
  4249.   send_response();
  4250.  
  4251.   /* we are done with the socket now */
  4252.   close(s_data);
  4253.  
  4254.       }
  4255.  
  4256.  
  4257.  /* this routine implements the receive (netserver) side of a TCP_RR */
  4258.  /* test */
  4259. void
  4260. recv_tcp_rr()
  4261. {
  4262.   
  4263.   struct ring_elt *send_ring;
  4264.   struct ring_elt *recv_ring;
  4265.  
  4266.   struct    sockaddr_in        myaddr_in,
  4267.   peeraddr_in;
  4268.   int    s_listen,s_data;
  4269.   int     addrlen;
  4270.   char    *temp_message_ptr;
  4271.   int    trans_received;
  4272.   int    trans_remaining;
  4273.   int    bytes_sent;
  4274.   int    request_bytes_recvd;
  4275.   int    request_bytes_remaining;
  4276.   int    timed_out = 0;
  4277.   float    elapsed_time;
  4278.   
  4279.   struct    tcp_rr_request_struct    *tcp_rr_request;
  4280.   struct    tcp_rr_response_struct    *tcp_rr_response;
  4281.   struct    tcp_rr_results_struct    *tcp_rr_results;
  4282.   
  4283.   tcp_rr_request = 
  4284.     (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
  4285.   tcp_rr_response =
  4286.     (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
  4287.   tcp_rr_results =
  4288.     (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
  4289.   
  4290.   if (debug) {
  4291.     fprintf(where,"netserver: recv_tcp_rr: entered...\n");
  4292.     fflush(where);
  4293.   }
  4294.   
  4295.   /* We want to set-up the listen socket with all the desired */
  4296.   /* parameters and then let the initiator know that all is ready. If */
  4297.   /* socket size defaults are to be used, then the initiator will have */
  4298.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  4299.   /* send-back what they are. If that information cannot be determined, */
  4300.   /* then we send-back -1's for the sizes. If things go wrong for any */
  4301.   /* reason, we will drop back ten yards and punt. */
  4302.   
  4303.   /* If anything goes wrong, we want the remote to know about it. It */
  4304.   /* would be best if the error that the remote reports to the user is */
  4305.   /* the actual error we encountered, rather than some bogus unexpected */
  4306.   /* response type message. */
  4307.   
  4308.   if (debug) {
  4309.     fprintf(where,"recv_tcp_rr: setting the response type...\n");
  4310.     fflush(where);
  4311.   }
  4312.   
  4313.   netperf_response.content.response_type = TCP_RR_RESPONSE;
  4314.   
  4315.   if (debug) {
  4316.     fprintf(where,"recv_tcp_rr: the response type is set...\n");
  4317.     fflush(where);
  4318.   }
  4319.   
  4320.   /* allocate the recv and send rings with the requested alignments */
  4321.   /* and offsets. raj 7/94 */
  4322.   if (debug) {
  4323.     fprintf(where,"recv_tcp_rr: requested recv alignment of %d offset %d\n",
  4324.         tcp_rr_request->recv_alignment,
  4325.         tcp_rr_request->recv_offset);
  4326.     fprintf(where,"recv_tcp_rr: requested send alignment of %d offset %d\n",
  4327.         tcp_rr_request->send_alignment,
  4328.         tcp_rr_request->send_offset);
  4329.     fflush(where);
  4330.   }
  4331.  
  4332.   /* at some point, these need to come to us from the remote system */
  4333.   if (send_width == 0) send_width = 1;
  4334.   if (recv_width == 0) recv_width = 1;
  4335.  
  4336.   send_ring = allocate_buffer_ring(send_width,
  4337.                    tcp_rr_request->response_size,
  4338.                    tcp_rr_request->send_alignment,
  4339.                    tcp_rr_request->send_offset);
  4340.  
  4341.   recv_ring = allocate_buffer_ring(recv_width,
  4342.                    tcp_rr_request->request_size,
  4343.                    tcp_rr_request->recv_alignment,
  4344.                    tcp_rr_request->recv_offset);
  4345.  
  4346.   
  4347.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  4348.   /* can put in OUR values !-) At some point, we may want to nail this */
  4349.   /* socket to a particular network-level address, but for now, */
  4350.   /* INADDR_ANY should be just fine. */
  4351.   
  4352.   bzero((char *)&myaddr_in,
  4353.     sizeof(myaddr_in));
  4354.   myaddr_in.sin_family      = AF_INET;
  4355.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  4356.   myaddr_in.sin_port        = 0;
  4357.   
  4358.   /* Grab a socket to listen on, and then listen on it. */
  4359.   
  4360.   if (debug) {
  4361.     fprintf(where,"recv_tcp_rr: grabbing a socket...\n");
  4362.     fflush(where);
  4363.   }
  4364.  
  4365.   /* create_data_socket expects to find some things in the global */
  4366.   /* variables, so set the globals based on the values in the request. */
  4367.   /* once the socket has been created, we will set the response values */
  4368.   /* based on the updated value of those globals. raj 7/94 */
  4369.   lss_size = tcp_rr_request->send_buf_size;
  4370.   lsr_size = tcp_rr_request->recv_buf_size;
  4371.   loc_nodelay = tcp_rr_request->no_delay;
  4372.   loc_rcvavoid = tcp_rr_request->so_rcvavoid;
  4373.   loc_sndavoid = tcp_rr_request->so_sndavoid;
  4374.   
  4375.   s_listen = create_data_socket(AF_INET,
  4376.                 SOCK_STREAM);
  4377.   
  4378.   if (s_listen < 0) {
  4379.     netperf_response.content.serv_errno = errno;
  4380.     send_response();
  4381.     
  4382.     exit(1);
  4383.   }
  4384.   
  4385.   /* Let's get an address assigned to this socket so we can tell the */
  4386.   /* initiator how to reach the data socket. There may be a desire to */
  4387.   /* nail this socket to a specific IP address in a multi-homed, */
  4388.   /* multi-connection situation, but for now, we'll ignore the issue */
  4389.   /* and concentrate on single connection testing. */
  4390.   
  4391.   if (bind(s_listen,
  4392.        (struct sockaddr *)&myaddr_in,
  4393.        sizeof(myaddr_in)) == -1) {
  4394.     netperf_response.content.serv_errno = errno;
  4395.     close(s_listen);
  4396.     send_response();
  4397.     
  4398.     exit(1);
  4399.   }
  4400.   
  4401.   /* Now, let's set-up the socket to listen for connections */
  4402.   if (listen(s_listen, 5) == -1) {
  4403.     netperf_response.content.serv_errno = errno;
  4404.     close(s_listen);
  4405.     send_response();
  4406.     
  4407.     exit(1);
  4408.   }
  4409.   
  4410.   
  4411.   /* now get the port number assigned by the system  */
  4412.   addrlen = sizeof(myaddr_in);
  4413.   if (getsockname(s_listen,
  4414.           (struct sockaddr *)&myaddr_in, &addrlen) == -1){
  4415.     netperf_response.content.serv_errno = errno;
  4416.     close(s_listen);
  4417.     send_response();
  4418.     
  4419.     exit(1);
  4420.   }
  4421.   
  4422.   /* Now myaddr_in contains the port and the internet address this is */
  4423.   /* returned to the sender also implicitly telling the sender that the */
  4424.   /* socket buffer sizing has been done. */
  4425.   
  4426.   tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  4427.   netperf_response.content.serv_errno   = 0;
  4428.   
  4429.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  4430.   /* then we must call the calibrate routine, which will return the max */
  4431.   /* rate back to the initiator. If the CPU was not to be measured, or */
  4432.   /* something went wrong with the calibration, we will return a 0.0 to */
  4433.   /* the initiator. */
  4434.   
  4435.   tcp_rr_response->cpu_rate = (float)0.0;     /* assume no cpu */
  4436.   tcp_rr_response->measure_cpu = 0;
  4437.  
  4438.   if (tcp_rr_request->measure_cpu) {
  4439.     tcp_rr_response->measure_cpu = 1;
  4440.     tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
  4441.   }
  4442.   
  4443.   
  4444.   /* before we send the response back to the initiator, pull some of */
  4445.   /* the socket parms from the globals */
  4446.   tcp_rr_response->send_buf_size = lss_size;
  4447.   tcp_rr_response->recv_buf_size = lsr_size;
  4448.   tcp_rr_response->no_delay = loc_nodelay;
  4449.   tcp_rr_response->so_rcvavoid = loc_rcvavoid;
  4450.   tcp_rr_response->so_sndavoid = loc_sndavoid;
  4451.   tcp_rr_response->test_length = tcp_rr_request->test_length;
  4452.   send_response();
  4453.   
  4454.   addrlen = sizeof(peeraddr_in);
  4455.   
  4456.   if ((s_data = accept(s_listen,
  4457.                (struct sockaddr *)&peeraddr_in,
  4458.                &addrlen)) ==
  4459.       -1) {
  4460.     /* Let's just punt. The remote will be given some information */
  4461.     close(s_listen);
  4462.     
  4463.     exit(1);
  4464.   }
  4465.   
  4466. #ifdef KLUDGE_SOCKET_OPTIONS
  4467.   /* this is for those systems which *INCORRECTLY* fail to pass */
  4468.   /* attributes across an accept() call. Including this goes against */
  4469.   /* my better judgement :( raj 11/95 */
  4470.  
  4471.   kludge_socket_options(s_data);
  4472.  
  4473. #endif /* KLUDGE_SOCKET_OPTIONS */
  4474.  
  4475. #ifdef WIN32
  4476.   /* this is used so the timer thread can close the socket out from */
  4477.   /* under us, which to date is the easiest/cleanest/least */
  4478.   /* Windows-specific way I can find to force the winsock calls to */
  4479.   /* return WSAEINTR with the test is over. anything that will run on */
  4480.   /* 95 and NT and is closer to what netperf expects from Unix signals */
  4481.   /* and such would be appreciated raj 1/96 */
  4482.   win_kludge_socket = s_data;
  4483. #endif /* WIN32 */
  4484.  
  4485.   if (debug) {
  4486.     fprintf(where,"recv_tcp_rr: accept completes on the data connection.\n");
  4487.     fflush(where);
  4488.   }
  4489.   
  4490.   /* Now it's time to start receiving data on the connection. We will */
  4491.   /* first grab the apropriate counters and then start grabbing. */
  4492.   
  4493.   cpu_start(tcp_rr_request->measure_cpu);
  4494.   
  4495.   /* The loop will exit when we hit the end of the test time, or when */
  4496.   /* we have exchanged the requested number of transactions. */
  4497.   
  4498.   if (tcp_rr_request->test_length > 0) {
  4499.     times_up = 0;
  4500.     trans_remaining = 0;
  4501.     start_timer(tcp_rr_request->test_length + PAD_TIME);
  4502.   }
  4503.   else {
  4504.     times_up = 1;
  4505.     trans_remaining = tcp_rr_request->test_length * -1;
  4506.   }
  4507.  
  4508.   trans_received = 0;
  4509.   
  4510.   while ((!times_up) || (trans_remaining > 0)) {
  4511.     temp_message_ptr = recv_ring->buffer_ptr;
  4512.     request_bytes_remaining    = tcp_rr_request->request_size;
  4513.     while(request_bytes_remaining > 0) {
  4514.       if((request_bytes_recvd=recv(s_data,
  4515.                    temp_message_ptr,
  4516.                    request_bytes_remaining,
  4517.                    0)) < 0) {
  4518. #ifdef WIN32
  4519.     if (request_bytes_recvd == SOCKET_ERROR &&
  4520.         ((WSAGetLastError() == WSAEINTR ) ||
  4521.          (WSAGetLastError() == WSAECONNABORTED))) {
  4522.       /* the timer popped. seems that when the other thread */
  4523.       /* closesocket's the socket, we get a WSAECONNABORTED */
  4524.       /* (instead of WSAEINTR?) raj 1/96 */
  4525.       timed_out = 1;
  4526.       break;
  4527.     }
  4528.     netperf_response.content.serv_errno = WSAGetLastError();
  4529. #else
  4530.     if (errno == EINTR) {
  4531.       /* the timer popped */
  4532.       timed_out = 1;
  4533.       break;
  4534.     }
  4535.     netperf_response.content.serv_errno = errno;
  4536. #endif /* WIN32 */
  4537.     send_response();
  4538.     exit(1);
  4539.       }
  4540.       else {
  4541.     request_bytes_remaining -= request_bytes_recvd;
  4542.     temp_message_ptr  += request_bytes_recvd;
  4543.       }
  4544.     }
  4545.  
  4546.     recv_ring = recv_ring->next;
  4547.  
  4548.     if (timed_out) {
  4549.       /* we hit the end of the test based on time - lets */
  4550.       /* bail out of here now... */
  4551.       if (debug) {
  4552.     fprintf(where,"yo5\n");
  4553.     fflush(where);
  4554.       }                        
  4555.       break;
  4556.     }
  4557.     
  4558.     /* Now, send the response to the remote */
  4559.     if((bytes_sent=send(s_data,
  4560.             send_ring->buffer_ptr,
  4561.             tcp_rr_request->response_size,
  4562.             0)) == -1) {
  4563. #ifdef WIN32
  4564.       if (bytes_sent == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  4565.     /* the test timer has popped */
  4566.     timed_out = 1;
  4567.     fprintf(where,"yo6\n");
  4568.     fflush(where);                        
  4569.     break;
  4570.       }
  4571. #else
  4572.       if (errno == EINTR) {
  4573.     /* the test timer has popped */
  4574.     timed_out = 1;
  4575.     fprintf(where,"yo6\n");
  4576.     fflush(where);                        
  4577.     break;
  4578.       }
  4579. #endif /* WIN32 */
  4580.       netperf_response.content.serv_errno = 992;
  4581.       send_response();
  4582.       exit(1);
  4583.     }
  4584.     
  4585.     send_ring = send_ring->next;
  4586.  
  4587.     trans_received++;
  4588.     if (trans_remaining) {
  4589.       trans_remaining--;
  4590.     }
  4591.   }
  4592.   
  4593.   
  4594.   /* The loop now exits due to timeout or transaction count being */
  4595.   /* reached */
  4596.   
  4597.   cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time);
  4598.   
  4599.   stop_timer();
  4600.  
  4601.   if (timed_out) {
  4602.     /* we ended the test by time, which was at least 2 seconds */
  4603.     /* longer than we wanted to run. so, we want to subtract */
  4604.     /* PAD_TIME from the elapsed_time. */
  4605.     elapsed_time -= PAD_TIME;
  4606.   }
  4607.  
  4608.   /* send the results to the sender            */
  4609.   
  4610.   if (debug) {
  4611.     fprintf(where,
  4612.         "recv_tcp_rr: got %d transactions\n",
  4613.         trans_received);
  4614.     fflush(where);
  4615.   }
  4616.   
  4617.   tcp_rr_results->bytes_received = (trans_received * 
  4618.                     (tcp_rr_request->request_size + 
  4619.                      tcp_rr_request->response_size));
  4620.   tcp_rr_results->trans_received = trans_received;
  4621.   tcp_rr_results->elapsed_time   = elapsed_time;
  4622.   tcp_rr_results->cpu_method     = cpu_method;
  4623.   tcp_rr_results->num_cpus       = lib_num_loc_cpus;
  4624.   if (tcp_rr_request->measure_cpu) {
  4625.     tcp_rr_results->cpu_util    = calc_cpu_util(elapsed_time);
  4626.   }
  4627.   
  4628.   if (debug) {
  4629.     fprintf(where,
  4630.         "recv_tcp_rr: test complete, sending results.\n");
  4631.     fflush(where);
  4632.   }
  4633.   
  4634.   /* we are now done with the sockets */
  4635.   close(s_data);
  4636.   close(s_listen);
  4637.  
  4638.   send_response();
  4639.   
  4640. }
  4641.  
  4642.  
  4643. void
  4644. loc_cpu_rate()
  4645. {
  4646.   float dummy;
  4647.  
  4648.   /* a rather simple little test - it merely calibrates the local cpu */
  4649.   /* and prints the results. There are no headers to allow someone to */
  4650.   /* find a rate and use it in other tests automagically by setting a */
  4651.   /* variable equal to the output of this test. We ignore any rates */
  4652.   /* that may have been specified. In fact, we ignore all of the */
  4653.   /* command line args! */
  4654.   
  4655.   fprintf(where,
  4656.       "%g",
  4657.       calibrate_local_cpu(0.0));
  4658.   
  4659.   /* we need the cpu_start, cpu_stop in the looper case to kill the */
  4660.   /* child proceses raj 4/95 */
  4661.  
  4662.   cpu_start(1);
  4663.   cpu_stop(1,&dummy);
  4664. }    
  4665.  
  4666. void
  4667. rem_cpu_rate()
  4668. {
  4669.   /* this test is much like the local variant, except that it works for */
  4670.   /* the remote system, so in this case, we do pay attention to the */
  4671.   /* value of the '-H' command line argument. */
  4672.   
  4673.   fprintf(where,
  4674.       "%g",
  4675.       calibrate_remote_cpu(0.0));
  4676.   
  4677. }
  4678.  
  4679.  
  4680.  /* this test is intended to test the performance of establishing a */
  4681.  /* connection, exchanging a reqeuest/response pair, and repeating. it */
  4682.  /* is expected that this would be a good starting-point for */
  4683.  /* comparision of T/TCP with classic TCP for transactional workloads. */
  4684.  /* it will also look (can look) much like the communication pattern */
  4685.  /* of http for www access. */
  4686.  
  4687. void
  4688. send_tcp_conn_rr(remote_host)
  4689.      char    remote_host[];
  4690. {
  4691.   
  4692.   char *tput_title = "\
  4693. Local /Remote\n\
  4694. Socket Size   Request  Resp.   Elapsed  Trans.\n\
  4695. Send   Recv   Size     Size    Time     Rate         \n\
  4696. bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
  4697.   
  4698.   char *tput_fmt_0 =
  4699.     "%7.2f\n";
  4700.   
  4701.   char *tput_fmt_1_line_1 = "\
  4702. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
  4703.   char *tput_fmt_1_line_2 = "\
  4704. %-6d %-6d\n";
  4705.   
  4706.   char *cpu_title = "\
  4707. Local /Remote\n\
  4708. Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
  4709. Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
  4710. bytes  bytes  bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
  4711.   
  4712.   char *cpu_fmt_0 =
  4713.     "%6.3f\n";
  4714.   
  4715.   char *cpu_fmt_1_line_1 = "\
  4716. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
  4717.   
  4718.   char *cpu_fmt_1_line_2 = "\
  4719. %-6d %-6d\n";
  4720.   
  4721.   char *ksink_fmt = "\n\
  4722. Alignment      Offset\n\
  4723. Local  Remote  Local  Remote\n\
  4724. Send   Recv    Send   Recv\n\
  4725. %5d  %5d   %5d  %5d\n";
  4726.   
  4727.   
  4728.   int             one = 1;
  4729.   int            timed_out = 0;
  4730.   float            elapsed_time;
  4731.   
  4732.   int    len;
  4733.   struct ring_elt *send_ring;
  4734.   struct ring_elt *recv_ring;
  4735.   char    *temp_message_ptr;
  4736.   int    nummessages;
  4737.   int    send_socket;
  4738.   int    trans_remaining;
  4739.   double    bytes_xferd;
  4740.   int    sock_opt_len = sizeof(int);
  4741.   int    rsp_bytes_left;
  4742.   int    rsp_bytes_recvd;
  4743.   
  4744.   float    local_cpu_utilization;
  4745.   float    local_service_demand;
  4746.   float    remote_cpu_utilization;
  4747.   float    remote_service_demand;
  4748.   double    thruput;
  4749.   
  4750.   struct    hostent            *hp;
  4751.   struct    sockaddr_in    server;
  4752.   struct        sockaddr_in     *myaddr;
  4753.   unsigned      int             addr;
  4754.   int                           myport;
  4755.   int                           ret;
  4756.  
  4757.   struct    tcp_conn_rr_request_struct    *tcp_conn_rr_request;
  4758.   struct    tcp_conn_rr_response_struct    *tcp_conn_rr_response;
  4759.   struct    tcp_conn_rr_results_struct    *tcp_conn_rr_result;
  4760.   
  4761.   tcp_conn_rr_request = 
  4762.     (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
  4763.   tcp_conn_rr_response = 
  4764.     (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
  4765.   tcp_conn_rr_result =
  4766.     (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
  4767.   
  4768.   
  4769. #ifdef HISTOGRAM
  4770.   time_hist = HIST_new();
  4771. #endif /* HISTOGRAM */
  4772.  
  4773.   /* since we are now disconnected from the code that established the */
  4774.   /* control socket, and since we want to be able to use different */
  4775.   /* protocols and such, we are passed the name of the remote host and */
  4776.   /* must turn that into the test specific addressing information. */
  4777.   
  4778.   myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
  4779.  
  4780.   bzero((char *)&server,
  4781.     sizeof(server));
  4782.   bzero((char *)myaddr,
  4783.     sizeof(struct sockaddr_in));
  4784.   myaddr->sin_family = AF_INET;
  4785.  
  4786.  /* it would seem that while HP-UX will allow an IP address (as a */
  4787.  /* string) in a call to gethostbyname, other, less enlightened */
  4788.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  4789.   if ((hp = gethostbyname(remote_host)) == NULL) {
  4790.     if ((addr = inet_addr(remote_host)) == -1) {
  4791.       fprintf(where,
  4792.           "send_tcp_conn_rr: could not resolve the name %s\n",
  4793.           remote_host);
  4794.       fflush(where);
  4795.       exit(1);
  4796.     }
  4797.     server.sin_addr.s_addr = addr;
  4798.     server.sin_family = AF_INET;
  4799.   }
  4800.   else {
  4801.     bcopy(hp->h_addr,
  4802.       (char *)&server.sin_addr,
  4803.       hp->h_length);
  4804.     server.sin_family = hp->h_addrtype;
  4805.   }
  4806.   
  4807.   
  4808.   if ( print_headers ) {
  4809.     fprintf(where,"TCP Connect/Request/Response TEST");
  4810.     fprintf(where," to %s", remote_host);
  4811.     if (iteration_max > 1) {
  4812.       fprintf(where,
  4813.           " : +/-%3.1f%% @ %2d%% conf.",
  4814.           interval/0.02,
  4815.           confidence_level);
  4816.       }
  4817.     if (loc_nodelay || rem_nodelay) {
  4818.       fprintf(where," : nodelay");
  4819.     }
  4820.     if (loc_sndavoid || 
  4821.     loc_rcvavoid ||
  4822.     rem_sndavoid ||
  4823.     rem_rcvavoid) {
  4824.       fprintf(where," : copy avoidance");
  4825.     }
  4826. #ifdef HISTOGRAM
  4827.     fprintf(where," : histogram");
  4828. #endif /* HISTOGRAM */
  4829. #ifdef INTERVALS
  4830.     fprintf(where," : interval");
  4831. #endif /* INTERVALS */
  4832. #ifdef DIRTY 
  4833.     fprintf(where," : dirty data");
  4834. #endif /* DIRTY */
  4835.     fprintf(where,"\n");
  4836.   }
  4837.   
  4838.   /* initialize a few counters */
  4839.   
  4840.   nummessages    =    0;
  4841.   bytes_xferd    =    0.0;
  4842.   times_up     =     0;
  4843.   
  4844.   /* set-up the data buffers with the requested alignment and offset */
  4845.   if (send_width == 0) send_width = 1;
  4846.   if (recv_width == 0) recv_width = 1;
  4847.  
  4848.   send_ring = allocate_buffer_ring(send_width,
  4849.                    req_size,
  4850.                    local_send_align,
  4851.                    local_send_offset);
  4852.  
  4853.   recv_ring = allocate_buffer_ring(recv_width,
  4854.                    rsp_size,
  4855.                    local_recv_align,
  4856.                    local_recv_offset);
  4857.  
  4858.  
  4859.   if (debug) {
  4860.     fprintf(where,"send_tcp_conn_rr: send_socket obtained...\n");
  4861.   }
  4862.   
  4863.   /* If the user has requested cpu utilization measurements, we must */
  4864.   /* calibrate the cpu(s). We will perform this task within the tests */
  4865.   /* themselves. If the user has specified the cpu rate, then */
  4866.   /* calibrate_local_cpu will return rather quickly as it will have */
  4867.   /* nothing to do. If local_cpu_rate is zero, then we will go through */
  4868.   /* all the "normal" calibration stuff and return the rate back.*/
  4869.   
  4870.   if (local_cpu_usage) {
  4871.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  4872.   }
  4873.   
  4874.   /* Tell the remote end to do a listen. The server alters the socket */
  4875.   /* paramters on the other side at this point, hence the reason for */
  4876.   /* all the values being passed in the setup message. If the user did */
  4877.   /* not specify any of the parameters, they will be passed as 0, which */
  4878.   /* will indicate to the remote that no changes beyond the system's */
  4879.   /* default should be used. Alignment is the exception, it will */
  4880.   /* default to 8, which will be no alignment alterations. */
  4881.   
  4882.   netperf_request.content.request_type            =    DO_TCP_CRR;
  4883.   tcp_conn_rr_request->recv_buf_size    =    rsr_size;
  4884.   tcp_conn_rr_request->send_buf_size    =    rss_size;
  4885.   tcp_conn_rr_request->recv_alignment    =    remote_recv_align;
  4886.   tcp_conn_rr_request->recv_offset    =    remote_recv_offset;
  4887.   tcp_conn_rr_request->send_alignment    =    remote_send_align;
  4888.   tcp_conn_rr_request->send_offset    =    remote_send_offset;
  4889.   tcp_conn_rr_request->request_size    =    req_size;
  4890.   tcp_conn_rr_request->response_size    =    rsp_size;
  4891.   tcp_conn_rr_request->no_delay            =    rem_nodelay;
  4892.   tcp_conn_rr_request->measure_cpu    =    remote_cpu_usage;
  4893.   tcp_conn_rr_request->cpu_rate            =    remote_cpu_rate;
  4894.   tcp_conn_rr_request->so_rcvavoid    =    rem_rcvavoid;
  4895.   tcp_conn_rr_request->so_sndavoid    =    rem_sndavoid;
  4896.   if (test_time) {
  4897.     tcp_conn_rr_request->test_length    =    test_time;
  4898.   }
  4899.   else {
  4900.     tcp_conn_rr_request->test_length    =    test_trans * -1;
  4901.   }
  4902.   
  4903.   if (debug > 1) {
  4904.     fprintf(where,"netperf: send_tcp_conn_rr: requesting TCP crr test\n");
  4905.   }
  4906.   
  4907.   send_request();
  4908.   
  4909.   /* The response from the remote will contain all of the relevant     */
  4910.   /* socket parameters for this test type. We will put them back into     */
  4911.   /* the variables here so they can be displayed if desired.  The    */
  4912.   /* remote will have calibrated CPU if necessary, and will have done    */
  4913.   /* all the needed set-up we will have calibrated the cpu locally    */
  4914.   /* before sending the request, and will grab the counter value right    */
  4915.   /* after the connect returns. The remote will grab the counter right    */
  4916.   /* after the accept call. This saves the hassle of extra messages    */
  4917.   /* being sent for the TCP tests.                    */
  4918.   
  4919.   recv_response();
  4920.   
  4921.   if (!netperf_response.content.serv_errno) {
  4922.     rsr_size    =    tcp_conn_rr_response->recv_buf_size;
  4923.     rss_size    =    tcp_conn_rr_response->send_buf_size;
  4924.     rem_nodelay    =    tcp_conn_rr_response->no_delay;
  4925.     remote_cpu_usage=    tcp_conn_rr_response->measure_cpu;
  4926.     remote_cpu_rate =     tcp_conn_rr_response->cpu_rate;
  4927.     /* make sure that port numbers are in network order */
  4928.     server.sin_port    =    tcp_conn_rr_response->data_port_number;
  4929.     server.sin_port =    htons(server.sin_port);
  4930.     if (debug) {
  4931.       fprintf(where,"remote listen done.\n");
  4932.       fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
  4933.       fflush(where);
  4934.     }
  4935.   }
  4936.   else {
  4937.     errno = netperf_response.content.serv_errno;
  4938.     fprintf(where,
  4939.         "netperf: remote error %d",
  4940.         netperf_response.content.serv_errno);
  4941.     perror("");
  4942.     fflush(where);
  4943.     exit(1);
  4944.   }
  4945.   
  4946.   /* pick a nice random spot between client_port_min and */
  4947.   /* client_port_max for our initial port number */
  4948.   srand(getpid());
  4949.   if (client_port_max - client_port_min) {
  4950.     myport = client_port_min + 
  4951.       (rand() % (client_port_max - client_port_min));
  4952.   }
  4953.   else {
  4954.     myport = client_port_min;
  4955.   }
  4956.   /* there will be a ++ before the first call to bind, so subtract one */
  4957.   myport--;
  4958.   myaddr->sin_port = htons((unsigned short)myport);
  4959.   
  4960.   /* Set-up the test end conditions. For a request/response test, they */
  4961.   /* can be either time or transaction based. */
  4962.   
  4963.   if (test_time) {
  4964.     /* The user wanted to end the test after a period of time. */
  4965.     times_up = 0;
  4966.     trans_remaining = 0;
  4967.     start_timer(test_time);
  4968.   }
  4969.   else {
  4970.     /* The tester wanted to send a number of bytes. */
  4971.     trans_remaining = test_bytes;
  4972.     times_up = 1;
  4973.   }
  4974.   
  4975.   /* The cpu_start routine will grab the current time and possibly */
  4976.   /* value of the idle counter for later use in measuring cpu */
  4977.   /* utilization and/or service demand and thruput. */
  4978.   
  4979.   cpu_start(local_cpu_usage);
  4980.   
  4981.   /* We use an "OR" to control test execution. When the test is */
  4982.   /* controlled by time, the byte count check will always return false. */
  4983.   /* When the test is controlled by byte count, the time test will */
  4984.   /* always return false. When the test is finished, the whole */
  4985.   /* expression will go false and we will stop sending data. I think I */
  4986.   /* just arbitrarily decrement trans_remaining for the timed test, but */
  4987.   /* will not do that just yet... One other question is whether or not */
  4988.   /* the send buffer and the receive buffer should be the same buffer. */
  4989.  
  4990.   while ((!times_up) || (trans_remaining > 0)) {
  4991.  
  4992. #ifdef HISTOGRAM
  4993.     /* timestamp just before our call to create the socket, and then */
  4994.     /* again just after the receive raj 3/95 */
  4995.     gettimeofday(&time_one,NULL);
  4996. #endif /* HISTOGRAM */
  4997.  
  4998.     /* set up the data socket */
  4999.     send_socket = create_data_socket(AF_INET, 
  5000.                      SOCK_STREAM);
  5001.   
  5002.     if (send_socket < 0) {
  5003.       perror("netperf: send_tcp_conn_rr: tcp stream data socket");
  5004.       exit(1);
  5005.     }
  5006.  
  5007.     /* we set SO_REUSEADDR on the premis that no unreserved port */
  5008.     /* number on the local system is going to be already connected to */
  5009.     /* the remote netserver's port number. One thing that I might */
  5010.     /* try later is to have the remote actually allocate a couple of */
  5011.     /* port numbers and cycle through those as well. depends on if we */
  5012.     /* can get through all the unreserved port numbers in less than */
  5013.     /* the length of the TIME_WAIT state raj 8/94 */
  5014.     one = 1;
  5015.     if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
  5016.           (char *)&one, sock_opt_len) < 0) {
  5017.       perror("netperf: send_tcp_conn_rr: so_reuseaddr");
  5018.       exit(1);
  5019.     }
  5020.  
  5021. newport:
  5022.     /* pick a new port number */
  5023.     myport = ntohs(myaddr->sin_port);
  5024.     myport++;
  5025.  
  5026.     /* wrap the port number when we get to client_port_max. NOTE, some */
  5027.     /* broken TCP's might treat the port number as a signed 16 bit */
  5028.     /* quantity.  we aren't interested in testing such broken */
  5029.     /* implementations :) so we won't make sure that it is below 32767 */
  5030.     /* raj 8/94  */
  5031.     if (myport >= client_port_max) {
  5032.       myport = client_port_min;
  5033.     }
  5034.  
  5035.     /* we do not want to use the port number that the server is */
  5036.     /* sitting at - this would cause us to fail in a loopback test. we */
  5037.     /* could just rely on the failure of the bind to get us past this, */
  5038.     /* but I'm guessing that in this one case at least, it is much */
  5039.     /* faster, given that we *know* that port number is already in use */
  5040.     /* (or rather would be in a loopback test) */
  5041.  
  5042.     if (myport == ntohs(server.sin_port)) myport++;
  5043.  
  5044.     myaddr->sin_port = htons(myport);
  5045.  
  5046.     if (debug) {
  5047.       if ((nummessages % 100) == 0) {
  5048.     printf("port %d\n",myport);
  5049.       }
  5050.     }
  5051.  
  5052.     /* we want to bind our socket to a particular port number. */
  5053.     if ((ret = bind(send_socket,
  5054.            (struct sockaddr *)myaddr,
  5055.            sizeof(struct sockaddr_in))) < 0) {
  5056.       /* if the bind failed, someone else must have that port number */
  5057.       /* - perhaps in the listen state. since we can't use it, skip to */
  5058.       /* the next port number. we may have to do this again later, but */
  5059.       /* that's just too bad :) */
  5060. #ifdef WIN32
  5061.       if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  5062. #else
  5063.       if (errno == EINTR) {
  5064. #endif /* WIN32 */
  5065.     /* we hit the end of a */
  5066.     /* timed test. */
  5067.     timed_out = 1;
  5068.     break;
  5069.       }
  5070.       if (debug > 1) {
  5071.     fprintf(where,
  5072.         "send_tcp_conn_rr: tried to bind to port %d errno %d\n",
  5073.         ntohs(myaddr->sin_port),
  5074.         errno);
  5075.     fflush(where);
  5076.       }
  5077.     /* yes, goto's are supposed to be evil, but they do have their */
  5078.     /* uses from time to time. the real world doesn't always have */
  5079.     /* to code to ge tthe A in CS 101 :) raj 3/95 */
  5080.     goto newport;
  5081.     }
  5082.  
  5083.     /* Connect up to the remote port on the data socket  */
  5084.     if ((ret = connect(send_socket, 
  5085.         (struct sockaddr *)&server,
  5086.         sizeof(server))) <0){
  5087. #ifdef WIN32
  5088.       if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  5089. #else
  5090.       if (errno == EINTR) {
  5091. #endif /* WIN32 */
  5092.     /* we hit the end of a */
  5093.     /* timed test. */
  5094.     timed_out = 1;
  5095.     break;
  5096.       }
  5097.       perror("netperf: data socket connect failed");
  5098.       printf("\tattempted to connect on socket %d to port %d",
  5099.          send_socket,
  5100.          ntohs(server.sin_port));
  5101.       printf(" from port %d \n",ntohs(myaddr->sin_port));
  5102.       exit(1);
  5103.     }
  5104.  
  5105.     /* send the request */
  5106.     if((len=send(send_socket,
  5107.          send_ring->buffer_ptr,
  5108.          req_size,
  5109.          0)) != req_size) {
  5110. #ifdef WIN32
  5111.       if (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  5112. #else
  5113.       if (errno == EINTR) {
  5114. #endif /* WIN32 */
  5115.     /* we hit the end of a */
  5116.     /* timed test. */
  5117.     timed_out = 1;
  5118.     break;
  5119.       }
  5120.       perror("send_tcp_conn_rr: data send error");
  5121.       exit(1);
  5122.     }
  5123.     send_ring = send_ring->next;
  5124.  
  5125.     /* receive the response */
  5126.     rsp_bytes_left = rsp_size;
  5127.     temp_message_ptr  = recv_ring->buffer_ptr;
  5128.     while(rsp_bytes_left > 0) {
  5129.       if((rsp_bytes_recvd=recv(send_socket,
  5130.                    temp_message_ptr,
  5131.                    rsp_bytes_left,
  5132.                    0)) < 0) {
  5133. #ifdef WIN32
  5134.     if (rsp_bytes_recvd == SOCKET_ERROR && WSAGetLastError() == WSAEINTR) {
  5135. #else
  5136.     if (errno == EINTR) {
  5137. #endif /* WIN32 */
  5138.       /* We hit the end of a timed test. */
  5139.       timed_out = 1;
  5140.       break;
  5141.     }
  5142.     perror("send_tcp_conn_rr: data recv error");
  5143.     exit(1);
  5144.       }
  5145.       rsp_bytes_left -= rsp_bytes_recvd;
  5146.       temp_message_ptr  += rsp_bytes_recvd;
  5147.     }    
  5148.     recv_ring = recv_ring->next;
  5149.  
  5150.     if (timed_out) {
  5151.       /* we may have been in a nested while loop - we need */
  5152.       /* another call to break. */
  5153.       break;
  5154.     }
  5155.  
  5156.     /* we will have gotten a zero in the receive loop which will be */
  5157.     /* the server  telling us that there is no more data. we can */
  5158.     /* simply call close on the socket instead of going through a */
  5159.     /* shutdown call first. if someone has information indicating that */
  5160.     /* www browsers actually call shutdown, and *then* close, I would */
  5161.     /* like to hear about it raj 10/95 */
  5162.  
  5163.     close(send_socket);
  5164.  
  5165. #ifdef HISTOGRAM
  5166.     gettimeofday(&time_two,NULL);
  5167.     HIST_add(time_hist,delta_micro(&time_one,&time_two));
  5168. #endif /* HISTOGRAM */
  5169.  
  5170.     nummessages++;          
  5171.     if (trans_remaining) {
  5172.       trans_remaining--;
  5173.     }
  5174.     
  5175.     if (debug > 3) {
  5176.       fprintf(where,
  5177.           "Transaction %d completed on local port %d\n",
  5178.           nummessages,
  5179.           ntohs(myaddr->sin_port));
  5180.       fflush(where);
  5181.     }
  5182.  
  5183.  
  5184.   }
  5185.   
  5186.   /* this call will always give us the elapsed time for the test, and */
  5187.   /* will also store-away the necessaries for cpu utilization */
  5188.  
  5189.   cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being measured? */
  5190.   /* how long did we really run? */
  5191.   
  5192.   /* Get the statistics from the remote end. The remote will have */
  5193.   /* calculated service demand and all those interesting things. If it */
  5194.   /* wasn't supposed to care, it will return obvious values. */
  5195.   
  5196.   recv_response();
  5197.   if (!netperf_response.content.serv_errno) {
  5198.     if (debug)
  5199.       fprintf(where,"remote results obtained\n");
  5200.   }
  5201.   else {
  5202.     errno = netperf_response.content.serv_errno;
  5203.     fprintf(where,
  5204.         "netperf: remote error %d",
  5205.          netperf_response.content.serv_errno);
  5206.     perror("");
  5207.     fflush(where);
  5208.       
  5209.     exit(1);
  5210.   }
  5211.   
  5212.   /* We now calculate what our thruput was for the test. In the future, */
  5213.   /* we may want to include a calculation of the thruput measured by */
  5214.   /* the remote, but it should be the case that for a TCP stream test, */
  5215.   /* that the two numbers should be *very* close... We calculate */
  5216.   /* bytes_sent regardless of the way the test length was controlled. */
  5217.   /* If it was time, we needed to, and if it was by bytes, the user may */
  5218.   /* have specified a number of bytes that wasn't a multiple of the */
  5219.   /* send_size, so we really didn't send what he asked for ;-) We use */
  5220.   /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
  5221.   /* 1024. A future enhancement *might* be to choose from a couple of */
  5222.   /* unit selections. */ 
  5223.   
  5224.   bytes_xferd    = (req_size * nummessages) + (rsp_size * nummessages);
  5225.   thruput    = (double) calc_thruput(bytes_xferd);
  5226.   
  5227.   if (local_cpu_usage || remote_cpu_usage) {
  5228.     /* We must now do a little math for service demand and cpu */
  5229.     /* utilization for the system(s) */
  5230.     /* Of course, some of the information might be bogus because */
  5231.     /* there was no idle counter in the kernel(s). We need to make */
  5232.     /* a note of this for the user's benefit...*/
  5233.     if (local_cpu_usage) {
  5234.       if (local_cpu_rate == 0.0) {
  5235.     fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
  5236.     fprintf(where,"Local CPU usage numbers based on process information only!\n");
  5237.     fflush(where);
  5238.       }
  5239.       local_cpu_utilization = calc_cpu_util(0.0);
  5240.       /* since calc_service demand is doing ms/Kunit we will */
  5241.       /* multiply the number of transaction by 1024 to get */
  5242.       /* "good" numbers */
  5243.       local_service_demand  = calc_service_demand((double) nummessages*1024,
  5244.                           0.0,
  5245.                           0.0,
  5246.                           0);
  5247.     }
  5248.     else {
  5249.       local_cpu_utilization    = (float) -1.0;
  5250.       local_service_demand    = (float) -1.0;
  5251.     }
  5252.     
  5253.     if (remote_cpu_usage) {
  5254.       if (remote_cpu_rate == 0.0) {
  5255.     fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
  5256.     fprintf(where,"Remote CPU usage numbers based on process information only!\n");
  5257.     fflush(where);
  5258.       }
  5259.       remote_cpu_utilization = tcp_conn_rr_result->cpu_util;
  5260.       /* since calc_service demand is doing ms/Kunit we will */
  5261.       /* multiply the number of transaction by 1024 to get */
  5262.       /* "good" numbers */
  5263.       remote_service_demand = calc_service_demand((double) nummessages*1024,
  5264.                           0.0,
  5265.                           remote_cpu_utilization,
  5266.                           tcp_conn_rr_result->num_cpus);
  5267.     }
  5268.     else {
  5269.       remote_cpu_utilization = (float) -1.0;
  5270.       remote_service_demand  = (float) -1.0;
  5271.     }
  5272.     
  5273.     /* We are now ready to print all the information. If the user */
  5274.     /* has specified zero-level verbosity, we will just print the */
  5275.     /* local service demand, or the remote service demand. If the */
  5276.     /* user has requested verbosity level 1, he will get the basic */
  5277.     /* "streamperf" numbers. If the user has specified a verbosity */
  5278.     /* of greater than 1, we will display a veritable plethora of */
  5279.     /* background information from outside of this block as it it */
  5280.     /* not cpu_measurement specific...  */
  5281.     
  5282.     switch (verbosity) {
  5283.     case 0:
  5284.       if (local_cpu_usage) {
  5285.     fprintf(where,
  5286.         cpu_fmt_0,
  5287.         local_service_demand);
  5288.       }
  5289.       else {
  5290.     fprintf(where,
  5291.         cpu_fmt_0,
  5292.         remote_service_demand);
  5293.       }
  5294.       break;
  5295.     case 1:
  5296.     case 2:
  5297.  
  5298.       if (print_headers) {
  5299.     fprintf(where,
  5300.         cpu_title,
  5301.         local_cpu_method,
  5302.         remote_cpu_method);
  5303.       }
  5304.       
  5305.       fprintf(where,
  5306.           cpu_fmt_1_line_1,        /* the format string */
  5307.           lss_size,        /* local sendbuf size */
  5308.           lsr_size,
  5309.           req_size,        /* how large were the requests */
  5310.           rsp_size,        /* guess */
  5311.           elapsed_time,        /* how long was the test */
  5312.           nummessages/elapsed_time,
  5313.           local_cpu_utilization,    /* local cpu */
  5314.           remote_cpu_utilization,    /* remote cpu */
  5315.           local_service_demand,    /* local service demand */
  5316.           remote_service_demand);    /* remote service demand */
  5317.       fprintf(where,
  5318.           cpu_fmt_1_line_2,
  5319.           rss_size,
  5320.           rsr_size);
  5321.       break;
  5322.     }
  5323.   }
  5324.   else {
  5325.     /* The tester did not wish to measure service demand. */
  5326.     switch (verbosity) {
  5327.     case 0:
  5328.       fprintf(where,
  5329.           tput_fmt_0,
  5330.           nummessages/elapsed_time);
  5331.       break;
  5332.     case 1:
  5333.     case 2:
  5334.       if (print_headers) {
  5335.     fprintf(where,tput_title,format_units());
  5336.       }
  5337.  
  5338.       fprintf(where,
  5339.           tput_fmt_1_line_1,    /* the format string */
  5340.           lss_size,
  5341.           lsr_size,
  5342.           req_size,        /* how large were the requests */
  5343.           rsp_size,        /* how large were the responses */
  5344.           elapsed_time,         /* how long did it take */
  5345.           nummessages/elapsed_time);
  5346.       fprintf(where,
  5347.           tput_fmt_1_line_2,
  5348.           rss_size,         /* remote recvbuf size */
  5349.           rsr_size);
  5350.       
  5351.       break;
  5352.     }
  5353.   }
  5354.   
  5355.   /* it would be a good thing to include information about some of the */
  5356.   /* other parameters that may have been set for this test, but at the */
  5357.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  5358.   /* just put this comment here to help remind me that it is something */
  5359.   /* that should be done at a later time. */
  5360.   
  5361.   if (verbosity > 1) {
  5362.     /* The user wanted to know it all, so we will give it to him. */
  5363.     /* This information will include as much as we can find about */
  5364.     /* TCP statistics, the alignments of the sends and receives */
  5365.     /* and all that sort of rot... */
  5366.     
  5367.     fprintf(where,
  5368.         ksink_fmt,
  5369.         local_send_align,
  5370.         remote_recv_offset,
  5371.         local_send_offset,
  5372.         remote_recv_offset);
  5373.  
  5374. #ifdef HISTOGRAM
  5375.     fprintf(where,"\nHistogram of request/response times\n");
  5376.     fflush(where);
  5377.     HIST_report(time_hist);
  5378. #endif /* HISTOGRAM */
  5379.  
  5380.   }
  5381.   
  5382. }
  5383.  
  5384.  
  5385. void
  5386. recv_tcp_conn_rr()
  5387. {
  5388.   
  5389.   char message[MAXMESSAGESIZE+MAXALIGNMENT+MAXOFFSET];
  5390.   struct    sockaddr_in        myaddr_in,
  5391.   peeraddr_in;
  5392.   int    s_listen,s_data;
  5393.   int     addrlen;
  5394.   char    *recv_message_ptr;
  5395.   char    *send_message_ptr;
  5396.   char    *temp_message_ptr;
  5397.   int    trans_received;
  5398.   int    trans_remaining;
  5399.   int    bytes_sent;
  5400.   int    request_bytes_recvd;
  5401.   int    request_bytes_remaining;
  5402.   int    timed_out = 0;
  5403.   float    elapsed_time;
  5404.   
  5405.   struct    tcp_conn_rr_request_struct    *tcp_conn_rr_request;
  5406.   struct    tcp_conn_rr_response_struct    *tcp_conn_rr_response;
  5407.   struct    tcp_conn_rr_results_struct    *tcp_conn_rr_results;
  5408.   
  5409.   tcp_conn_rr_request = 
  5410.     (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
  5411.   tcp_conn_rr_response = 
  5412.     (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
  5413.   tcp_conn_rr_results = 
  5414.     (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
  5415.   
  5416.   if (debug) {
  5417.     fprintf(where,"netserver: recv_tcp_conn_rr: entered...\n");
  5418.     fflush(where);
  5419.   }
  5420.   
  5421.   /* We want to set-up the listen socket with all the desired */
  5422.   /* parameters and then let the initiator know that all is ready. If */
  5423.   /* socket size defaults are to be used, then the initiator will have */
  5424.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  5425.   /* send-back what they are. If that information cannot be determined, */
  5426.   /* then we send-back -1's for the sizes. If things go wrong for any */
  5427.   /* reason, we will drop back ten yards and punt. */
  5428.   
  5429.   /* If anything goes wrong, we want the remote to know about it. It */
  5430.   /* would be best if the error that the remote reports to the user is */
  5431.   /* the actual error we encountered, rather than some bogus unexpected */
  5432.   /* response type message. */
  5433.   
  5434.   if (debug) {
  5435.     fprintf(where,"recv_tcp_conn_rr: setting the response type...\n");
  5436.     fflush(where);
  5437.   }
  5438.   
  5439.   netperf_response.content.response_type = TCP_CRR_RESPONSE;
  5440.   
  5441.   if (debug) {
  5442.     fprintf(where,"recv_tcp_conn_rr: the response type is set...\n");
  5443.     fflush(where);
  5444.   }
  5445.   
  5446.   /* We now alter the message_ptr variables to be at the desired */
  5447.   /* alignments with the desired offsets. */
  5448.   
  5449.   if (debug) {
  5450.     fprintf(where,
  5451.         "recv_tcp_conn_rr: requested recv alignment of %d offset %d\n",
  5452.         tcp_conn_rr_request->recv_alignment,
  5453.         tcp_conn_rr_request->recv_offset);
  5454.     fprintf(where,
  5455.         "recv_tcp_conn_rr: requested send alignment of %d offset %d\n",
  5456.         tcp_conn_rr_request->send_alignment,
  5457.         tcp_conn_rr_request->send_offset);
  5458.     fflush(where);
  5459.   }
  5460.   recv_message_ptr = (char *)(( (long)message + 
  5461.             (long) tcp_conn_rr_request->recv_alignment -1) & 
  5462.             ~((long) tcp_conn_rr_request->recv_alignment - 1));
  5463.   recv_message_ptr = recv_message_ptr + tcp_conn_rr_request->recv_offset;
  5464.   
  5465.   send_message_ptr = (char *)(( (long)message + 
  5466.             (long) tcp_conn_rr_request->send_alignment -1) & 
  5467.             ~((long) tcp_conn_rr_request->send_alignment - 1));
  5468.   send_message_ptr = send_message_ptr + tcp_conn_rr_request->send_offset;
  5469.   
  5470.   if (debug) {
  5471.     fprintf(where,"recv_tcp_conn_rr: receive alignment and offset set...\n");
  5472.     fflush(where);
  5473.   }
  5474.   
  5475.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  5476.   /* can put in OUR values !-) At some point, we may want to nail this */
  5477.   /* socket to a particular network-level address, but for now, */
  5478.   /* INADDR_ANY should be just fine. */
  5479.   
  5480.   bzero((char *)&myaddr_in,
  5481.     sizeof(myaddr_in));
  5482.   myaddr_in.sin_family      = AF_INET;
  5483.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  5484.   myaddr_in.sin_port        = 0;
  5485.   
  5486.   /* Grab a socket to listen on, and then listen on it. */
  5487.   
  5488.   if (debug) {
  5489.     fprintf(where,"recv_tcp_conn_rr: grabbing a socket...\n");
  5490.     fflush(where);
  5491.   }
  5492.  
  5493.   /* create_data_socket expects to find some things in the global */
  5494.   /* variables, so set the globals based on the values in the request. */
  5495.   /* once the socket has been created, we will set the response values */
  5496.   /* based on the updated value of those globals. raj 7/94 */
  5497.   lss_size = tcp_conn_rr_request->send_buf_size;
  5498.   lsr_size = tcp_conn_rr_request->recv_buf_size;
  5499.   loc_nodelay = tcp_conn_rr_request->no_delay;
  5500.   loc_rcvavoid = tcp_conn_rr_request->so_rcvavoid;
  5501.   loc_sndavoid = tcp_conn_rr_request->so_sndavoid;
  5502.   
  5503.   s_listen = create_data_socket(AF_INET,
  5504.                 SOCK_STREAM);
  5505.   
  5506.   if (s_listen < 0) {
  5507.     netperf_response.content.serv_errno = errno;
  5508.     send_response();
  5509.     if (debug) {
  5510.       fprintf(where,"could not create data socket\n");
  5511.       fflush(where);
  5512.     }
  5513.     exit(1);
  5514.   }
  5515.  
  5516.   /* Let's get an address assigned to this socket so we can tell the */
  5517.   /* initiator how to reach the data socket. There may be a desire to */
  5518.   /* nail this socket to a specific IP address in a multi-homed, */
  5519.   /* multi-connection situation, but for now, we'll ignore the issue */
  5520.   /* and concentrate on single connection testing. */
  5521.   
  5522.   if (bind(s_listen,
  5523.        (struct sockaddr *)&myaddr_in,
  5524.        sizeof(myaddr_in)) == -1) {
  5525.     netperf_response.content.serv_errno = errno;
  5526.     close(s_listen);
  5527.     send_response();
  5528.     if (debug) {
  5529.       fprintf(where,"could not bind\n");
  5530.       fflush(where);
  5531.     }
  5532.     exit(1);
  5533.   }
  5534.  
  5535.   /* Now, let's set-up the socket to listen for connections */
  5536.   if (listen(s_listen, 5) == -1) {
  5537.     netperf_response.content.serv_errno = errno;
  5538.     close(s_listen);
  5539.     send_response();
  5540.     if (debug) {
  5541.       fprintf(where,"could not listen\n");
  5542.       fflush(where);
  5543.     }
  5544.     exit(1);
  5545.   }
  5546.   
  5547.   /* now get the port number assigned by the system  */
  5548.   addrlen = sizeof(myaddr_in);
  5549.   if (getsockname(s_listen,
  5550.           (struct sockaddr *)&myaddr_in,
  5551.           &addrlen) == -1){
  5552.     netperf_response.content.serv_errno = errno;
  5553.     close(s_listen);
  5554.     send_response();
  5555.     if (debug) {
  5556.       fprintf(where,"could not geetsockname\n");
  5557.       fflush(where);
  5558.     }
  5559.     exit(1);
  5560.   }
  5561.   
  5562.   /* Now myaddr_in contains the port and the internet address this is */
  5563.   /* returned to the sender also implicitly telling the sender that the */
  5564.   /* socket buffer sizing has been done. */
  5565.   
  5566.   tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  5567.   if (debug) {
  5568.     fprintf(where,"telling the remote to call me at %d\n",
  5569.         tcp_conn_rr_response->data_port_number);
  5570.     fflush(where);
  5571.   }
  5572.   netperf_response.content.serv_errno   = 0;
  5573.   
  5574.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  5575.   /* then we must call the calibrate routine, which will return the max */
  5576.   /* rate back to the initiator. If the CPU was not to be measured, or */
  5577.   /* something went wrong with the calibration, we will return a 0.0 to */
  5578.   /* the initiator. */
  5579.   
  5580.   tcp_conn_rr_response->cpu_rate = (float)0.0;     /* assume no cpu */
  5581.   if (tcp_conn_rr_request->measure_cpu) {
  5582.     tcp_conn_rr_response->measure_cpu = 1;
  5583.     tcp_conn_rr_response->cpu_rate = 
  5584.       calibrate_local_cpu(tcp_conn_rr_request->cpu_rate);
  5585.   }
  5586.   
  5587.  
  5588.   
  5589.   /* before we send the response back to the initiator, pull some of */
  5590.   /* the socket parms from the globals */
  5591.   tcp_conn_rr_response->send_buf_size = lss_size;
  5592.   tcp_conn_rr_response->recv_buf_size = lsr_size;
  5593.   tcp_conn_rr_response->no_delay = loc_nodelay;
  5594.   tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
  5595.   tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
  5596.  
  5597.   send_response();
  5598.   
  5599.   addrlen = sizeof(peeraddr_in);
  5600.   
  5601.   /* Now it's time to start receiving data on the connection. We will */
  5602.   /* first grab the apropriate counters and then start grabbing. */
  5603.   
  5604.   cpu_start(tcp_conn_rr_request->measure_cpu);
  5605.   
  5606.   /* The loop will exit when the sender does a shutdown, which will */
  5607.   /* return a length of zero   */
  5608.   
  5609.   if (tcp_conn_rr_request->test_length > 0) {
  5610.     times_up = 0;
  5611.     trans_remaining = 0;
  5612.     start_timer(tcp_conn_rr_request->test_length + PAD_TIME);
  5613.   }
  5614.   else {
  5615.     times_up = 1;
  5616.     trans_remaining = tcp_conn_rr_request->test_length * -1;
  5617.   }
  5618.   
  5619.   trans_received = 0;
  5620.  
  5621.   while ((!times_up) || (trans_remaining > 0)) {
  5622.  
  5623.     /* accept a connection from the remote */
  5624.     if ((s_data=accept(s_listen,
  5625.                (struct sockaddr *)&peeraddr_in,
  5626.                &addrlen)) == -1) {
  5627.       if (errno == EINTR) {
  5628.     /* the timer popped */
  5629.     timed_out = 1;
  5630.     break;
  5631.       }
  5632.       fprintf(where,"recv_tcp_conn_rr: accept: errno = %d\n",errno);
  5633.       fflush(where);
  5634.       close(s_listen);
  5635.       
  5636.       exit(1);
  5637.     }
  5638.  
  5639. #ifdef KLUDGE_SOCKET_OPTIONS
  5640.     /* this is for those systems which *INCORRECTLY* fail to pass */
  5641.     /* attributes across an accept() call. Including this goes against */
  5642.     /* my better judgement :( raj 11/95 */
  5643.     
  5644.     kludge_socket_options(s_data);
  5645.  
  5646. #endif /* KLUDGE_SOCKET_OPTIONS */
  5647.   
  5648. #ifdef WIN32
  5649.   /* this is used so the timer thread can close the socket out from */
  5650.   /* under us, which to date is the easiest/cleanest/least */
  5651.   /* Windows-specific way I can find to force the winsock calls to */
  5652.   /* return WSAEINTR with the test is over. anything that will run on */
  5653.   /* 95 and NT and is closer to what netperf expects from Unix signals */
  5654.   /* and such would be appreciated raj 1/96 */
  5655.   win_kludge_socket = s_data;
  5656. #endif /* WIN32 */
  5657.  
  5658.     if (debug) {
  5659.       fprintf(where,"recv_tcp_conn_rr: accepted data connection.\n");
  5660.       fflush(where);
  5661.     }
  5662.   
  5663.     temp_message_ptr    = recv_message_ptr;
  5664.     request_bytes_remaining    = tcp_conn_rr_request->request_size;
  5665.     
  5666.     /* receive the request from the other side */
  5667.     while(request_bytes_remaining > 0) {
  5668.       if((request_bytes_recvd=recv(s_data,
  5669.                    temp_message_ptr,
  5670.                    request_bytes_remaining,
  5671.                    0)) < 0) {
  5672. #ifdef WIN32
  5673.     if ( request_bytes_recvd == SOCKET_ERROR &&
  5674.          WSAGetLastError() == WSAEINTR ) {
  5675. #else
  5676.     if (errno == EINTR) {
  5677. #endif /* WIN32 */
  5678.       /* the timer popped */
  5679.       timed_out = 1;
  5680.       break;
  5681.     }
  5682.     netperf_response.content.serv_errno = errno;
  5683.     send_response();
  5684.     exit(1);
  5685.       }
  5686.       else {
  5687.     request_bytes_remaining -= request_bytes_recvd;
  5688.     temp_message_ptr  += request_bytes_recvd;
  5689.       }
  5690.     }
  5691.     
  5692.     if (timed_out) {
  5693.       /* we hit the end of the test based on time - lets */
  5694.       /* bail out of here now... */
  5695.       fprintf(where,"yo5\n");
  5696.       fflush(where);                        
  5697.       break;
  5698.     }
  5699.     
  5700.     /* Now, send the response to the remote */
  5701.     if((bytes_sent=send(s_data,
  5702.             send_message_ptr,
  5703.             tcp_conn_rr_request->response_size,
  5704.             0)) == -1) {
  5705. #ifdef WIN32
  5706.       if (bytes_sent == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  5707. #else
  5708.       if (errno == EINTR) {
  5709. #endif /* WIN32 */
  5710.     /* the test timer has popped */
  5711.     timed_out = 1;
  5712.     fprintf(where,"yo6\n");
  5713.     fflush(where);                        
  5714.     break;
  5715.       }
  5716.       netperf_response.content.serv_errno = 99;
  5717.       send_response();
  5718.       exit(1);
  5719.     }
  5720.     
  5721.     trans_received++;
  5722.     if (trans_remaining) {
  5723.       trans_remaining--;
  5724.     }
  5725.     
  5726.     if (debug) {
  5727.       fprintf(where,
  5728.           "recv_tcp_conn_rr: Transaction %d complete\n",
  5729.           trans_received);
  5730.       fflush(where);
  5731.     }
  5732.  
  5733.     /* close the connection. the server will likely do a graceful */
  5734.     /* close of the connection, insuring that all data has arrived at */
  5735.     /* the client. for this it will call shutdown(), and then recv() and */
  5736.     /* then close(). I'm reasonably confident that this is the */
  5737.     /* appropriate sequence of calls - I would like to hear of */
  5738.     /* examples in web servers to the contrary. raj 10/95*/
  5739.     close(s_data);
  5740.  
  5741.   }
  5742.   
  5743.   
  5744.   /* The loop now exits due to timeout or transaction count being */
  5745.   /* reached */
  5746.   
  5747.   cpu_stop(tcp_conn_rr_request->measure_cpu,&elapsed_time);
  5748.   
  5749.   if (timed_out) {
  5750.     /* we ended the test by time, which was at least 2 seconds */
  5751.     /* longer than we wanted to run. so, we want to subtract */
  5752.     /* PAD_TIME from the elapsed_time. */
  5753.     elapsed_time -= PAD_TIME;
  5754.   }
  5755.   /* send the results to the sender            */
  5756.   
  5757.   if (debug) {
  5758.     fprintf(where,
  5759.         "recv_tcp_conn_rr: got %d transactions\n",
  5760.         trans_received);
  5761.     fflush(where);
  5762.   }
  5763.   
  5764.   tcp_conn_rr_results->bytes_received    = (trans_received * 
  5765.                        (tcp_conn_rr_request->request_size + 
  5766.                         tcp_conn_rr_request->response_size));
  5767.   tcp_conn_rr_results->trans_received    = trans_received;
  5768.   tcp_conn_rr_results->elapsed_time    = elapsed_time;
  5769.   if (tcp_conn_rr_request->measure_cpu) {
  5770.     tcp_conn_rr_results->cpu_util    = calc_cpu_util(elapsed_time);
  5771.   }
  5772.   
  5773.   if (debug) {
  5774.     fprintf(where,
  5775.         "recv_tcp_conn_rr: test complete, sending results.\n");
  5776.     fflush(where);
  5777.   }
  5778.   
  5779.   send_response();
  5780.   
  5781. }
  5782.  
  5783.  
  5784. #ifdef DO_1644
  5785.  
  5786.  /* this test is intended to test the performance of establishing a */
  5787.  /* connection, exchanging a reqeuest/response pair, and repeating. it */
  5788.  /* is expected that this would be a good starting-point for */
  5789.  /* comparision of T/TCP with classic TCP for transactional workloads. */
  5790.  /* it will also look (can look) much like the communication pattern */
  5791.  /* of http for www access. */
  5792.  
  5793. int 
  5794. send_tcp_tran_rr(remote_host)
  5795.      char    remote_host[];
  5796. {
  5797.   
  5798.   char *tput_title = "\
  5799. Local /Remote\n\
  5800. Socket Size   Request  Resp.   Elapsed  Trans.\n\
  5801. Send   Recv   Size     Size    Time     Rate         \n\
  5802. bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
  5803.   
  5804.   char *tput_fmt_0 =
  5805.     "%7.2f\n";
  5806.   
  5807.   char *tput_fmt_1_line_1 = "\
  5808. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
  5809.   char *tput_fmt_1_line_2 = "\
  5810. %-6d %-6d\n";
  5811.   
  5812.   char *cpu_title = "\
  5813. Local /Remote\n\
  5814. Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
  5815. Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
  5816. bytes  bytes  bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
  5817.   
  5818.   char *cpu_fmt_0 =
  5819.     "%6.3f\n";
  5820.   
  5821.   char *cpu_fmt_1_line_1 = "\
  5822. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
  5823.   
  5824.   char *cpu_fmt_1_line_2 = "\
  5825. %-6d %-6d\n";
  5826.   
  5827.   char *ksink_fmt = "\n\
  5828. Alignment      Offset\n\
  5829. Local  Remote  Local  Remote\n\
  5830. Send   Recv    Send   Recv\n\
  5831. %5d  %5d   %5d  %5d\n";
  5832.   
  5833.   
  5834.   int             one = 1;
  5835.   int            timed_out = 0;
  5836.   float            elapsed_time;
  5837.   
  5838.   int    len;
  5839.   struct ring_elt *send_ring;
  5840.   struct ring_elt *recv_ring;
  5841.   char    *temp_message_ptr;
  5842.   int    nummessages;
  5843.   int    send_socket;
  5844.   int    trans_remaining;
  5845.   double    bytes_xferd;
  5846.   int    sock_opt_len = sizeof(int);
  5847.   int    rsp_bytes_left;
  5848.   int    rsp_bytes_recvd;
  5849.   
  5850.   float    local_cpu_utilization;
  5851.   float    local_service_demand;
  5852.   float    remote_cpu_utilization;
  5853.   float    remote_service_demand;
  5854.   double    thruput;
  5855.   
  5856.   struct    hostent            *hp;
  5857.   struct    sockaddr_in    server;
  5858.   struct        sockaddr_in     *myaddr;
  5859.   unsigned      int             addr;
  5860.   int                           myport;
  5861.  
  5862.   struct    tcp_tran_rr_request_struct    *tcp_tran_rr_request;
  5863.   struct    tcp_tran_rr_response_struct    *tcp_tran_rr_response;
  5864.   struct    tcp_tran_rr_results_struct    *tcp_tran_rr_result;
  5865.   
  5866.   tcp_tran_rr_request = 
  5867.     (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
  5868.   tcp_tran_rr_response = 
  5869.     (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
  5870.   tcp_tran_rr_result =
  5871.     (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
  5872.   
  5873.   
  5874. #ifdef HISTOGRAM
  5875.   time_hist = HIST_new();
  5876. #endif /* HISTOGRAM */
  5877.  
  5878.   /* since we are now disconnected from the code that established the */
  5879.   /* control socket, and since we want to be able to use different */
  5880.   /* protocols and such, we are passed the name of the remote host and */
  5881.   /* must turn that into the test specific addressing information. */
  5882.   
  5883.   myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
  5884.  
  5885.   bzero((char *)&server,
  5886.     sizeof(server));
  5887.   bzero((char *)myaddr,
  5888.     sizeof(struct sockaddr_in));
  5889.   myaddr->sin_family = AF_INET;
  5890.  
  5891.  /* it would seem that while HP-UX will allow an IP address (as a */
  5892.  /* string) in a call to gethostbyname, other, less enlightened */
  5893.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  5894.   if ((hp = gethostbyname(remote_host)) == NULL) {
  5895.     if ((addr = inet_addr(remote_host)) == -1) {
  5896.       fprintf(where,
  5897.           "send_tcp_trr: could not resolve the name %s\n",
  5898.           remote_host);
  5899.       fflush(where);
  5900.       exit(1);
  5901.     }
  5902.     server.sin_addr.s_addr = addr;
  5903.     server.sin_family = AF_INET;
  5904.   }
  5905.   else {
  5906.     bcopy(hp->h_addr,
  5907.       (char *)&server.sin_addr,
  5908.       hp->h_length);
  5909.     server.sin_family = hp->h_addrtype;
  5910.   }
  5911.   
  5912.   
  5913.   if ( print_headers ) {
  5914.     fprintf(where,"TCP Transactional/Request/Response TEST");
  5915.     fprintf(where," to %s", remote_host);
  5916.     if (iteration_max > 1) {
  5917.       fprintf(where,
  5918.           " : +/-%3.1f%% @ %2d%% conf.",
  5919.           interval/0.02,
  5920.           confidence_level);
  5921.       }
  5922.     if (loc_nodelay || rem_nodelay) {
  5923.       fprintf(where," : nodelay");
  5924.     }
  5925.     if (loc_sndavoid || 
  5926.     loc_rcvavoid ||
  5927.     rem_sndavoid ||
  5928.     rem_rcvavoid) {
  5929.       fprintf(where," : copy avoidance");
  5930.     }
  5931. #ifdef HISTOGRAM
  5932.     fprintf(where," : histogram");
  5933. #endif /* HISTOGRAM */
  5934. #ifdef INTERVALS
  5935.     fprintf(where," : interval");
  5936. #endif /* INTERVALS */
  5937. #ifdef DIRTY 
  5938.     fprintf(where," : dirty data");
  5939. #endif /* DIRTY */
  5940.     fprintf(where,"\n");
  5941.   }
  5942.   
  5943.   /* initialize a few counters */
  5944.   
  5945.   nummessages    =    0;
  5946.   bytes_xferd    =    0.0;
  5947.   times_up     =     0;
  5948.   
  5949.   /* set-up the data buffers with the requested alignment and offset */
  5950.   if (send_width == 0) send_width = 1;
  5951.   if (recv_width == 0) recv_width = 1;
  5952.  
  5953.   send_ring = allocate_buffer_ring(send_width,
  5954.                    req_size,
  5955.                    local_send_align,
  5956.                    local_send_offset);
  5957.  
  5958.   recv_ring = allocate_buffer_ring(recv_width,
  5959.                    rsp_size,
  5960.                    local_recv_align,
  5961.                    local_recv_offset);
  5962.  
  5963.  
  5964.   if (debug) {
  5965.     fprintf(where,"send_tcp_tran_rr: send_socket obtained...\n");
  5966.   }
  5967.   
  5968.   /* If the user has requested cpu utilization measurements, we must */
  5969.   /* calibrate the cpu(s). We will perform this task within the tests */
  5970.   /* themselves. If the user has specified the cpu rate, then */
  5971.   /* calibrate_local_cpu will return rather quickly as it will have */
  5972.   /* nothing to do. If local_cpu_rate is zero, then we will go through */
  5973.   /* all the "normal" calibration stuff and return the rate back.*/
  5974.   
  5975.   if (local_cpu_usage) {
  5976.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  5977.   }
  5978.   
  5979.   /* Tell the remote end to do a listen. The server alters the socket */
  5980.   /* paramters on the other side at this point, hence the reason for */
  5981.   /* all the values being passed in the setup message. If the user did */
  5982.   /* not specify any of the parameters, they will be passed as 0, which */
  5983.   /* will indicate to the remote that no changes beyond the system's */
  5984.   /* default should be used. Alignment is the exception, it will */
  5985.   /* default to 8, which will be no alignment alterations. */
  5986.   
  5987.   netperf_request.content.request_type            =    DO_TCP_TRR;
  5988.   tcp_tran_rr_request->recv_buf_size    =    rsr_size;
  5989.   tcp_tran_rr_request->send_buf_size    =    rss_size;
  5990.   tcp_tran_rr_request->recv_alignment    =    remote_recv_align;
  5991.   tcp_tran_rr_request->recv_offset    =    remote_recv_offset;
  5992.   tcp_tran_rr_request->send_alignment    =    remote_send_align;
  5993.   tcp_tran_rr_request->send_offset    =    remote_send_offset;
  5994.   tcp_tran_rr_request->request_size    =    req_size;
  5995.   tcp_tran_rr_request->response_size    =    rsp_size;
  5996.   tcp_tran_rr_request->no_delay            =    rem_nodelay;
  5997.   tcp_tran_rr_request->measure_cpu    =    remote_cpu_usage;
  5998.   tcp_tran_rr_request->cpu_rate            =    remote_cpu_rate;
  5999.   tcp_tran_rr_request->so_rcvavoid    =    rem_rcvavoid;
  6000.   tcp_tran_rr_request->so_sndavoid    =    rem_sndavoid;
  6001.   if (test_time) {
  6002.     tcp_tran_rr_request->test_length    =    test_time;
  6003.   }
  6004.   else {
  6005.     tcp_tran_rr_request->test_length    =    test_trans * -1;
  6006.   }
  6007.   
  6008.   if (debug > 1) {
  6009.     fprintf(where,"netperf: send_tcp_tran_rr: requesting TCP_TRR test\n");
  6010.   }
  6011.   
  6012.   send_request();
  6013.   
  6014.   /* The response from the remote will contain all of the relevant     */
  6015.   /* socket parameters for this test type. We will put them back into     */
  6016.   /* the variables here so they can be displayed if desired.  The    */
  6017.   /* remote will have calibrated CPU if necessary, and will have done    */
  6018.   /* all the needed set-up we will have calibrated the cpu locally    */
  6019.   /* before sending the request, and will grab the counter value right    */
  6020.   /* after the connect returns. The remote will grab the counter right    */
  6021.   /* after the accept call. This saves the hassle of extra messages    */
  6022.   /* being sent for the TCP tests.                    */
  6023.   
  6024.   recv_response();
  6025.   
  6026.   if (!netperf_response.content.serv_errno) {
  6027.     rsr_size    =    tcp_tran_rr_response->recv_buf_size;
  6028.     rss_size    =    tcp_tran_rr_response->send_buf_size;
  6029.     rem_nodelay    =    tcp_tran_rr_response->no_delay;
  6030.     remote_cpu_usage=    tcp_tran_rr_response->measure_cpu;
  6031.     remote_cpu_rate =     tcp_tran_rr_response->cpu_rate;
  6032.     /* make sure that port numbers are in network order */
  6033.     server.sin_port    =    tcp_tran_rr_response->data_port_number;
  6034.     server.sin_port =    htons(server.sin_port);
  6035.     if (debug) {
  6036.       fprintf(where,"remote listen done.\n");
  6037.       fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
  6038.       fflush(where);
  6039.     }
  6040.   }
  6041.   else {
  6042.     errno = netperf_response.content.serv_errno;
  6043.     fprintf(where,
  6044.         "netperf: remote error %d",
  6045.         netperf_response.content.serv_errno);
  6046.     perror("");
  6047.     fflush(where);
  6048.     exit(1);
  6049.   }
  6050.  
  6051.   /* pick a nice random spot between client_port_min and */
  6052.   /* client_port_max for our initial port number. if they are the */
  6053.   /* same, then just set to _min */
  6054.   if (client_port_max - client_port_min) {
  6055.     srand(getpid());
  6056.     myport = client_port_min + 
  6057.       (rand() % (client_port_max - client_port_min));
  6058.   }
  6059.   else {
  6060.     myport = client_port_min;
  6061.   }
  6062.  
  6063.   /* there will be a ++ before the first call to bind, so subtract one */
  6064.   myport--;
  6065.   myaddr->sin_port = htons((unsigned short)myport);
  6066.   
  6067.   /* Set-up the test end conditions. For a request/response test, they */
  6068.   /* can be either time or transaction based. */
  6069.   
  6070.   if (test_time) {
  6071.     /* The user wanted to end the test after a period of time. */
  6072.     times_up = 0;
  6073.     trans_remaining = 0;
  6074.     start_timer(test_time);
  6075.   }
  6076.   else {
  6077.     /* The tester wanted to send a number of bytes. */
  6078.     trans_remaining = test_bytes;
  6079.     times_up = 1;
  6080.   }
  6081.   
  6082.   /* The cpu_start routine will grab the current time and possibly */
  6083.   /* value of the idle counter for later use in measuring cpu */
  6084.   /* utilization and/or service demand and thruput. */
  6085.   
  6086.   cpu_start(local_cpu_usage);
  6087.   
  6088.   /* We use an "OR" to control test execution. When the test is */
  6089.   /* controlled by time, the byte count check will always return false. */
  6090.   /* When the test is controlled by byte count, the time test will */
  6091.   /* always return false. When the test is finished, the whole */
  6092.   /* expression will go false and we will stop sending data. I think I */
  6093.   /* just arbitrarily decrement trans_remaining for the timed test, but */
  6094.   /* will not do that just yet... One other question is whether or not */
  6095.   /* the send buffer and the receive buffer should be the same buffer. */
  6096.  
  6097.   while ((!times_up) || (trans_remaining > 0)) {
  6098.  
  6099. #ifdef HISTOGRAM
  6100.     /* timestamp just before our call to create the socket, and then */
  6101.     /* again just after the receive raj 3/95 */
  6102.     gettimeofday(&time_one,NULL);
  6103. #endif /* HISTOGRAM */
  6104.  
  6105.     /* set up the data socket - is this really necessary or can I just */
  6106.     /* re-use the same socket and move this cal out of the while loop. */
  6107.     /* it does introcudea *boatload* of system calls. I guess that it */
  6108.     /* all depends on "reality of programming." keeping it this way is */
  6109.     /* a bit more conservative I imagine - raj 3/95 */
  6110.     send_socket = create_data_socket(AF_INET, 
  6111.                      SOCK_STREAM);
  6112.   
  6113.     if (send_socket < 0) {
  6114.       perror("netperf: send_tcp_tran_rr: tcp stream data socket");
  6115.       exit(1);
  6116.     }
  6117.  
  6118.     /* we set SO_REUSEADDR on the premis that no unreserved port */
  6119.     /* number on the local system is going to be already connected to */
  6120.     /* the remote netserver's port number. One thing that I might */
  6121.     /* try later is to have the remote actually allocate a couple of */
  6122.     /* port numbers and cycle through those as well. depends on if we */
  6123.     /* can get through all the unreserved port numbers in less than */
  6124.     /* the length of the TIME_WAIT state raj 8/94 */
  6125.     one = 1;
  6126.     if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
  6127.           (char *)&one, sock_opt_len) < 0) {
  6128.       perror("netperf: send_tcp_tran_rr: so_reuseaddr");
  6129.       exit(1);
  6130.     }
  6131.  
  6132. newport:
  6133.     /* pick a new port number */
  6134.     myport = ntohs(myaddr->sin_port);
  6135.     myport++;
  6136.  
  6137.     /* we do not want to use the port number that the server is */
  6138.     /* sitting at - this would cause us to fail in a loopback test. we */
  6139.     /* could just rely on the failure of the bind to get us past this, */
  6140.     /* but I'm guessing that in this one case at least, it is much */
  6141.     /* faster, given that we *know* that port number is already in use */
  6142.     /* (or rather would be in a loopback test) */
  6143.  
  6144.     if (myport == ntohs(server.sin_port)) myport++;
  6145.  
  6146.     /* wrap the port number when we get to 65535. NOTE, some broken */
  6147.     /* TCP's might treat the port number as a signed 16 bit quantity. */
  6148.     /* we aren't interested in testing such broken implementations :) */
  6149.     /* raj 8/94  */
  6150.     if (myport >= client_port_max) {
  6151.       myport = client_port_min;
  6152.     }
  6153.     myaddr->sin_port = htons(myport);
  6154.  
  6155.     if (debug) {
  6156.       if ((nummessages % 100) == 0) {
  6157.     printf("port %d\n",myport);
  6158.       }
  6159.     }
  6160.  
  6161.     /* we want to bind our socket to a particular port number. */
  6162.     if (bind(send_socket,
  6163.          (struct sockaddr *)myaddr,
  6164.          sizeof(struct sockaddr_in)) < 0) {
  6165.       /* if the bind failed, someone else must have that port number */
  6166.       /* - perhaps in the listen state. since we can't use it, skip to */
  6167.       /* the next port number. we may have to do this again later, but */
  6168.       /* that's just too bad :) */
  6169.       if (debug > 1) {
  6170.     fprintf(where,
  6171.         "send_tcp_tran_rr: tried to bind to port %d errno %d\n",
  6172.         ntohs(myaddr->sin_port),
  6173.         errno);
  6174.     fflush(where);
  6175.       }
  6176.     /* yes, goto's are supposed to be evil, but they do have their */
  6177.     /* uses from time to time. the real world doesn't always have */
  6178.     /* to code to ge tthe A in CS 101 :) raj 3/95 */
  6179.     goto newport;
  6180.     }
  6181.  
  6182.     /* Connect up to the remote port on the data socket. Since this is */
  6183.     /* a test for RFC_1644-style transactional TCP, we can use the */
  6184.     /* sendto() call instead of calling connect and then send() */
  6185.  
  6186.     /* send the request */
  6187.     if((len=sendto(send_socket,
  6188.            send_ring->buffer_ptr,
  6189.            req_size,
  6190.            MSG_EOF, 
  6191.            (struct sockaddr *)&server,
  6192.            sizeof(server))) != req_size) {
  6193. #ifdef WIN32
  6194.       if (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  6195. #else
  6196.       if (errno == EINTR) {
  6197. #endif /* WIN32 */
  6198.     /* we hit the end of a */
  6199.     /* timed test. */
  6200.     timed_out = 1;
  6201.     break;
  6202.       }
  6203.       perror("send_tcp_tran_rr: data send error");
  6204.       exit(1);
  6205.     }
  6206.     send_ring = send_ring->next;
  6207.  
  6208.     /* receive the response */
  6209.     rsp_bytes_left = rsp_size;
  6210.     temp_message_ptr  = recv_ring->buffer_ptr;
  6211.     while(rsp_bytes_left > 0) {
  6212.       if((rsp_bytes_recvd=recv(send_socket,
  6213.                    temp_message_ptr,
  6214.                    rsp_bytes_left,
  6215.                    0)) < 0) {
  6216. #ifdef WIN32
  6217.     if (rsp_bytes_recvd == SOCKET_ERROR &&
  6218.         WSAGetLastError() == WSAEINTR ) {
  6219. #else
  6220.     if (errno == EINTR) {
  6221. #endif /* WIN32 */
  6222.       /* We hit the end of a timed test. */
  6223.       timed_out = 1;
  6224.       break;
  6225.     }
  6226.     perror("send_tcp_tran_rr: data recv error");
  6227.     exit(1);
  6228.       }
  6229.       rsp_bytes_left -= rsp_bytes_recvd;
  6230.       temp_message_ptr  += rsp_bytes_recvd;
  6231.     }    
  6232.     recv_ring = recv_ring->next;
  6233.  
  6234.     if (timed_out) {
  6235.       /* we may have been in a nested while loop - we need */
  6236.       /* another call to break. */
  6237.       break;
  6238.     }
  6239.  
  6240.     close(send_socket);
  6241.  
  6242. #ifdef HISTOGRAM
  6243.     gettimeofday(&time_two,NULL);
  6244.     HIST_add(time_hist,delta_micro(&time_one,&time_two));
  6245. #endif /* HISTOGRAM */
  6246.  
  6247.     nummessages++;          
  6248.     if (trans_remaining) {
  6249.       trans_remaining--;
  6250.     }
  6251.     
  6252.     if (debug > 3) {
  6253.       fprintf(where,
  6254.           "Transaction %d completed on local port %d\n",
  6255.           nummessages,
  6256.           ntohs(myaddr->sin_port));
  6257.       fflush(where);
  6258.     }
  6259.  
  6260.  
  6261.   }
  6262.   
  6263.   /* this call will always give us the elapsed time for the test, and */
  6264.   /* will also store-away the necessaries for cpu utilization */
  6265.  
  6266.   cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being measured? */
  6267.   /* how long did we really run? */
  6268.   
  6269.   /* Get the statistics from the remote end. The remote will have */
  6270.   /* calculated service demand and all those interesting things. If it */
  6271.   /* wasn't supposed to care, it will return obvious values. */
  6272.   
  6273.   recv_response();
  6274.   if (!netperf_response.content.serv_errno) {
  6275.     if (debug)
  6276.       fprintf(where,"remote results obtained\n");
  6277.   }
  6278.   else {
  6279.     errno = netperf_response.content.serv_errno;
  6280.     fprintf(where,
  6281.         "netperf: remote error %d",
  6282.         netperf_response.content.serv_errno);
  6283.     perror("");
  6284.     fflush(where);
  6285.     exit(1);
  6286.   }
  6287.   
  6288.   /* We now calculate what our thruput was for the test. In the future, */
  6289.   /* we may want to include a calculation of the thruput measured by */
  6290.   /* the remote, but it should be the case that for a TCP stream test, */
  6291.   /* that the two numbers should be *very* close... We calculate */
  6292.   /* bytes_sent regardless of the way the test length was controlled. */
  6293.   /* If it was time, we needed to, and if it was by bytes, the user may */
  6294.   /* have specified a number of bytes that wasn't a multiple of the */
  6295.   /* send_size, so we really didn't send what he asked for ;-) We use */
  6296.   /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
  6297.   /* 1024. A future enhancement *might* be to choose from a couple of */
  6298.   /* unit selections. */ 
  6299.   
  6300.   bytes_xferd    = (req_size * nummessages) + (rsp_size * nummessages);
  6301.   thruput    = (double) calc_thruput(bytes_xferd);
  6302.   
  6303.   if (local_cpu_usage || remote_cpu_usage) {
  6304.     /* We must now do a little math for service demand and cpu */
  6305.     /* utilization for the system(s) */
  6306.     /* Of course, some of the information might be bogus because */
  6307.     /* there was no idle counter in the kernel(s). We need to make */
  6308.     /* a note of this for the user's benefit...*/
  6309.     if (local_cpu_usage) {
  6310.       if (local_cpu_rate == 0.0) {
  6311.     fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
  6312.     fprintf(where,"Local CPU usage numbers based on process information only!\n");
  6313.     fflush(where);
  6314.       }
  6315.       local_cpu_utilization = calc_cpu_util(0.0);
  6316.       /* since calc_service demand is doing ms/Kunit we will */
  6317.       /* multiply the number of transaction by 1024 to get */
  6318.       /* "good" numbers */
  6319.       local_service_demand  = calc_service_demand((double) nummessages*1024,
  6320.                           0.0,
  6321.                           0.0,
  6322.                           0);
  6323.     }
  6324.     else {
  6325.       local_cpu_utilization    = (float) -1.0;
  6326.       local_service_demand    = (float) -1.0;
  6327.     }
  6328.     
  6329.     if (remote_cpu_usage) {
  6330.       if (remote_cpu_rate == 0.0) {
  6331.     fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
  6332.     fprintf(where,"Remote CPU usage numbers based on process information only!\n");
  6333.     fflush(where);
  6334.       }
  6335.       remote_cpu_utilization = tcp_tran_rr_result->cpu_util;
  6336.       /* since calc_service demand is doing ms/Kunit we will */
  6337.       /* multiply the number of transaction by 1024 to get */
  6338.       /* "good" numbers */
  6339.       remote_service_demand = calc_service_demand((double) nummessages*1024,
  6340.                           0.0,
  6341.                           remote_cpu_utilization,
  6342.                           tcp_tran_rr_result->num_cpus);
  6343.     }
  6344.     else {
  6345.       remote_cpu_utilization = (float) -1.0;
  6346.       remote_service_demand  = (float) -1.0;
  6347.     }
  6348.     
  6349.     /* We are now ready to print all the information. If the user */
  6350.     /* has specified zero-level verbosity, we will just print the */
  6351.     /* local service demand, or the remote service demand. If the */
  6352.     /* user has requested verbosity level 1, he will get the basic */
  6353.     /* "streamperf" numbers. If the user has specified a verbosity */
  6354.     /* of greater than 1, we will display a veritable plethora of */
  6355.     /* background information from outside of this block as it it */
  6356.     /* not cpu_measurement specific...  */
  6357.     
  6358.     switch (verbosity) {
  6359.     case 0:
  6360.       if (local_cpu_usage) {
  6361.     fprintf(where,
  6362.         cpu_fmt_0,
  6363.         local_service_demand);
  6364.       }
  6365.       else {
  6366.     fprintf(where,
  6367.         cpu_fmt_0,
  6368.         remote_service_demand);
  6369.       }
  6370.       break;
  6371.     case 1:
  6372.     case 2:
  6373.  
  6374.       if (print_headers) {
  6375.     fprintf(where,
  6376.         cpu_title,
  6377.         local_cpu_method,
  6378.         remote_cpu_method);
  6379.       }
  6380.       
  6381.       fprintf(where,
  6382.           cpu_fmt_1_line_1,        /* the format string */
  6383.           lss_size,        /* local sendbuf size */
  6384.           lsr_size,
  6385.           req_size,        /* how large were the requests */
  6386.           rsp_size,        /* guess */
  6387.           elapsed_time,        /* how long was the test */
  6388.           nummessages/elapsed_time,
  6389.           local_cpu_utilization,    /* local cpu */
  6390.           remote_cpu_utilization,    /* remote cpu */
  6391.           local_service_demand,    /* local service demand */
  6392.           remote_service_demand);    /* remote service demand */
  6393.       fprintf(where,
  6394.           cpu_fmt_1_line_2,
  6395.           rss_size,
  6396.           rsr_size);
  6397.       break;
  6398.     }
  6399.   }
  6400.   else {
  6401.     /* The tester did not wish to measure service demand. */
  6402.     switch (verbosity) {
  6403.     case 0:
  6404.       fprintf(where,
  6405.           tput_fmt_0,
  6406.           nummessages/elapsed_time);
  6407.       break;
  6408.     case 1:
  6409.     case 2:
  6410.       if (print_headers) {
  6411.     fprintf(where,tput_title,format_units());
  6412.       }
  6413.  
  6414.       fprintf(where,
  6415.           tput_fmt_1_line_1,    /* the format string */
  6416.           lss_size,
  6417.           lsr_size,
  6418.           req_size,        /* how large were the requests */
  6419.           rsp_size,        /* how large were the responses */
  6420.           elapsed_time,         /* how long did it take */
  6421.           nummessages/elapsed_time);
  6422.       fprintf(where,
  6423.           tput_fmt_1_line_2,
  6424.           rss_size,         /* remote recvbuf size */
  6425.           rsr_size);
  6426.       
  6427.       break;
  6428.     }
  6429.   }
  6430.   
  6431.   /* it would be a good thing to include information about some of the */
  6432.   /* other parameters that may have been set for this test, but at the */
  6433.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  6434.   /* just put this comment here to help remind me that it is something */
  6435.   /* that should be done at a later time. */
  6436.   
  6437.   if (verbosity > 1) {
  6438.     /* The user wanted to know it all, so we will give it to him. */
  6439.     /* This information will include as much as we can find about */
  6440.     /* TCP statistics, the alignments of the sends and receives */
  6441.     /* and all that sort of rot... */
  6442.     
  6443.     fprintf(where,
  6444.         ksink_fmt,
  6445.         local_send_align,
  6446.         remote_recv_offset,
  6447.         local_send_offset,
  6448.         remote_recv_offset);
  6449.  
  6450. #ifdef HISTOGRAM
  6451.     fprintf(where,"\nHistogram of request/response times\n");
  6452.     fflush(where);
  6453.     HIST_report(time_hist);
  6454. #endif /* HISTOGRAM */
  6455.  
  6456.   }
  6457.   
  6458. }
  6459.  
  6460.  
  6461. int 
  6462. recv_tcp_tran_rr()
  6463. {
  6464.   
  6465.   char message[MAXMESSAGESIZE+MAXALIGNMENT+MAXOFFSET];
  6466.   struct    sockaddr_in        myaddr_in,
  6467.   peeraddr_in;
  6468.   int    s_listen,s_data;
  6469.   int     addrlen;
  6470.   int   NoPush = 1;
  6471.  
  6472.   char    *recv_message_ptr;
  6473.   char    *send_message_ptr;
  6474.   char    *temp_message_ptr;
  6475.   int    trans_received;
  6476.   int    trans_remaining;
  6477.   int    bytes_sent;
  6478.   int    request_bytes_recvd;
  6479.   int    request_bytes_remaining;
  6480.   int    timed_out = 0;
  6481.   float    elapsed_time;
  6482.   
  6483.   struct    tcp_tran_rr_request_struct    *tcp_tran_rr_request;
  6484.   struct    tcp_tran_rr_response_struct    *tcp_tran_rr_response;
  6485.   struct    tcp_tran_rr_results_struct    *tcp_tran_rr_results;
  6486.   
  6487.   tcp_tran_rr_request = 
  6488.     (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
  6489.   tcp_tran_rr_response = 
  6490.     (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
  6491.   tcp_tran_rr_results = 
  6492.     (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
  6493.   
  6494.   if (debug) {
  6495.     fprintf(where,"netserver: recv_tcp_tran_rr: entered...\n");
  6496.     fflush(where);
  6497.   }
  6498.   
  6499.   /* We want to set-up the listen socket with all the desired */
  6500.   /* parameters and then let the initiator know that all is ready. If */
  6501.   /* socket size defaults are to be used, then the initiator will have */
  6502.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  6503.   /* send-back what they are. If that information cannot be determined, */
  6504.   /* then we send-back -1's for the sizes. If things go wrong for any */
  6505.   /* reason, we will drop back ten yards and punt. */
  6506.   
  6507.   /* If anything goes wrong, we want the remote to know about it. It */
  6508.   /* would be best if the error that the remote reports to the user is */
  6509.   /* the actual error we encountered, rather than some bogus unexpected */
  6510.   /* response type message. */
  6511.   
  6512.   if (debug) {
  6513.     fprintf(where,"recv_tcp_tran_rr: setting the response type...\n");
  6514.     fflush(where);
  6515.   }
  6516.   
  6517.   netperf_response.content.response_type = TCP_TRR_RESPONSE;
  6518.   
  6519.   if (debug) {
  6520.     fprintf(where,"recv_tcp_tran_rr: the response type is set...\n");
  6521.     fflush(where);
  6522.   }
  6523.   
  6524.   /* We now alter the message_ptr variables to be at the desired */
  6525.   /* alignments with the desired offsets. */
  6526.   
  6527.   if (debug) {
  6528.     fprintf(where,
  6529.         "recv_tcp_tran_rr: requested recv alignment of %d offset %d\n",
  6530.         tcp_tran_rr_request->recv_alignment,
  6531.         tcp_tran_rr_request->recv_offset);
  6532.     fprintf(where,
  6533.         "recv_tcp_tran_rr: requested send alignment of %d offset %d\n",
  6534.         tcp_tran_rr_request->send_alignment,
  6535.         tcp_tran_rr_request->send_offset);
  6536.     fflush(where);
  6537.   }
  6538.   recv_message_ptr = (char *)(( (long)message + 
  6539.             (long) tcp_tran_rr_request->recv_alignment -1) & 
  6540.             ~((long) tcp_tran_rr_request->recv_alignment - 1));
  6541.   recv_message_ptr = recv_message_ptr + tcp_tran_rr_request->recv_offset;
  6542.   
  6543.   send_message_ptr = (char *)(( (long)message + 
  6544.             (long) tcp_tran_rr_request->send_alignment -1) & 
  6545.             ~((long) tcp_tran_rr_request->send_alignment - 1));
  6546.   send_message_ptr = send_message_ptr + tcp_tran_rr_request->send_offset;
  6547.   
  6548.   if (debug) {
  6549.     fprintf(where,"recv_tcp_tran_rr: receive alignment and offset set...\n");
  6550.     fflush(where);
  6551.   }
  6552.   
  6553.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  6554.   /* can put in OUR values !-) At some point, we may want to nail this */
  6555.   /* socket to a particular network-level address, but for now, */
  6556.   /* INADDR_ANY should be just fine. */
  6557.   
  6558.   bzero((char *)&myaddr_in,
  6559.     sizeof(myaddr_in));
  6560.   myaddr_in.sin_family      = AF_INET;
  6561.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  6562.   myaddr_in.sin_port        = 0;
  6563.   
  6564.   /* Grab a socket to listen on, and then listen on it. */
  6565.   
  6566.   if (debug) {
  6567.     fprintf(where,"recv_tcp_tran_rr: grabbing a socket...\n");
  6568.     fflush(where);
  6569.   }
  6570.  
  6571.   /* create_data_socket expects to find some things in the global */
  6572.   /* variables, so set the globals based on the values in the request. */
  6573.   /* once the socket has been created, we will set the response values */
  6574.   /* based on the updated value of those globals. raj 7/94 */
  6575.   lss_size = tcp_tran_rr_request->send_buf_size;
  6576.   lsr_size = tcp_tran_rr_request->recv_buf_size;
  6577.   loc_nodelay = tcp_tran_rr_request->no_delay;
  6578.   loc_rcvavoid = tcp_tran_rr_request->so_rcvavoid;
  6579.   loc_sndavoid = tcp_tran_rr_request->so_sndavoid;
  6580.   
  6581.   s_listen = create_data_socket(AF_INET,
  6582.                 SOCK_STREAM);
  6583.   
  6584.   if (s_listen < 0) {
  6585.     netperf_response.content.serv_errno = errno;
  6586.     send_response();
  6587.     if (debug) {
  6588.       fprintf(where,"could not create data socket\n");
  6589.       fflush(where);
  6590.     }
  6591.     exit(1);
  6592.   }
  6593.  
  6594.   /* Let's get an address assigned to this socket so we can tell the */
  6595.   /* initiator how to reach the data socket. There may be a desire to */
  6596.   /* nail this socket to a specific IP address in a multi-homed, */
  6597.   /* multi-connection situation, but for now, we'll ignore the issue */
  6598.   /* and concentrate on single connection testing. */
  6599.   
  6600.   if (bind(s_listen,
  6601.        (struct sockaddr *)&myaddr_in,
  6602.        sizeof(myaddr_in)) == -1) {
  6603.     netperf_response.content.serv_errno = errno;
  6604.     close(s_listen);
  6605.     send_response();
  6606.     if (debug) {
  6607.       fprintf(where,"could not bind\n");
  6608.       fflush(where);
  6609.     }
  6610.     exit(1);
  6611.   }
  6612.  
  6613.   /* we want to disable the implicit PUSH on all sends. at some point, */
  6614.   /* this might want to be a parm to the test raj 3/95 */
  6615.   if (setsockopt(s_listen,
  6616.          IPPROTO_TCP,
  6617.          TCP_NOPUSH, 
  6618.          &NoPush,
  6619.          sizeof(int))) {
  6620.     fprintf(where,
  6621.         "recv_tcp_tran_rr: could not set TCP_NOPUSH errno %d\n",
  6622.         errno);
  6623.     fflush(where);
  6624.     netperf_response.content.serv_errno = errno;
  6625.     close(s_listen);
  6626.     send_response();
  6627.   }
  6628.  
  6629.   /* Now, let's set-up the socket to listen for connections */
  6630.   if (listen(s_listen, 5) == -1) {
  6631.     netperf_response.content.serv_errno = errno;
  6632.     close(s_listen);
  6633.     send_response();
  6634.     if (debug) {
  6635.       fprintf(where,"could not listen\n");
  6636.       fflush(where);
  6637.     }
  6638.     exit(1);
  6639.   }
  6640.   
  6641.   /* now get the port number assigned by the system  */
  6642.   addrlen = sizeof(myaddr_in);
  6643.   if (getsockname(s_listen,
  6644.           (struct sockaddr *)&myaddr_in,
  6645.           &addrlen) == -1){
  6646.     netperf_response.content.serv_errno = errno;
  6647.     close(s_listen);
  6648.     send_response();
  6649.     if (debug) {
  6650.       fprintf(where,"could not geetsockname\n");
  6651.       fflush(where);
  6652.     }
  6653.     exit(1);
  6654.   }
  6655.   
  6656.   /* Now myaddr_in contains the port and the internet address this is */
  6657.   /* returned to the sender also implicitly telling the sender that the */
  6658.   /* socket buffer sizing has been done. */
  6659.   
  6660.   tcp_tran_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  6661.   if (debug) {
  6662.     fprintf(where,"telling the remote to call me at %d\n",
  6663.         tcp_tran_rr_response->data_port_number);
  6664.     fflush(where);
  6665.   }
  6666.   netperf_response.content.serv_errno   = 0;
  6667.   
  6668.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  6669.   /* then we must call the calibrate routine, which will return the max */
  6670.   /* rate back to the initiator. If the CPU was not to be measured, or */
  6671.   /* something went wrong with the calibration, we will return a 0.0 to */
  6672.   /* the initiator. */
  6673.   
  6674.   tcp_tran_rr_response->cpu_rate = 0.0;     /* assume no cpu */
  6675.   if (tcp_tran_rr_request->measure_cpu) {
  6676.     tcp_tran_rr_response->measure_cpu = 1;
  6677.     tcp_tran_rr_response->cpu_rate = 
  6678.       calibrate_local_cpu(tcp_tran_rr_request->cpu_rate);
  6679.   }
  6680.   
  6681.  
  6682.   
  6683.   /* before we send the response back to the initiator, pull some of */
  6684.   /* the socket parms from the globals */
  6685.   tcp_tran_rr_response->send_buf_size = lss_size;
  6686.   tcp_tran_rr_response->recv_buf_size = lsr_size;
  6687.   tcp_tran_rr_response->no_delay = loc_nodelay;
  6688.   tcp_tran_rr_response->so_rcvavoid = loc_rcvavoid;
  6689.   tcp_tran_rr_response->so_sndavoid = loc_sndavoid;
  6690.  
  6691.   send_response();
  6692.   
  6693.   addrlen = sizeof(peeraddr_in);
  6694.   
  6695.   /* Now it's time to start receiving data on the connection. We will */
  6696.   /* first grab the apropriate counters and then start grabbing. */
  6697.   
  6698.   cpu_start(tcp_tran_rr_request->measure_cpu);
  6699.   
  6700.   /* The loop will exit when the sender does a shutdown, which will */
  6701.   /* return a length of zero   */
  6702.   
  6703.   if (tcp_tran_rr_request->test_length > 0) {
  6704.     times_up = 0;
  6705.     trans_remaining = 0;
  6706.     start_timer(tcp_tran_rr_request->test_length + PAD_TIME);
  6707.   }
  6708.   else {
  6709.     times_up = 1;
  6710.     trans_remaining = tcp_tran_rr_request->test_length * -1;
  6711.   }
  6712.   
  6713.   trans_received = 0;
  6714.  
  6715.   while ((!times_up) || (trans_remaining > 0)) {
  6716.  
  6717.     /* accept a connection from the remote */
  6718.     if ((s_data=accept(s_listen,
  6719.                (struct sockaddr *)&peeraddr_in,
  6720.                &addrlen)) == -1) {
  6721.       if (errno == EINTR) {
  6722.     /* the timer popped */
  6723.     timed_out = 1;
  6724.     break;
  6725.       }
  6726.       fprintf(where,"recv_tcp_tran_rr: accept: errno = %d\n",errno);
  6727.       fflush(where);
  6728.       close(s_listen);
  6729.       
  6730.       exit(1);
  6731.     }
  6732.   
  6733.     if (debug) {
  6734.       fprintf(where,"recv_tcp_tran_rr: accepted data connection.\n");
  6735.       fflush(where);
  6736.     }
  6737.  
  6738. #ifdef KLUDGE_SOCKET_OPTIONS
  6739.   /* this is for those systems which *INCORRECTLY* fail to pass */
  6740.   /* attributes across an accept() call. Including this goes against */
  6741.   /* my better judgement :( raj 11/95 */
  6742.  
  6743.   kludge_socket_options(s_data);
  6744.  
  6745. #endif /* KLUDGE_SOCKET_OPTIONS */
  6746.   
  6747.     temp_message_ptr    = recv_message_ptr;
  6748.     request_bytes_remaining    = tcp_tran_rr_request->request_size;
  6749.     
  6750.     /* receive the request from the other side. we can just receive */
  6751.     /* until we get zero bytes, but that would be a slight structure */
  6752.     /* change in the code, with minimal perfomance effects. If */
  6753.     /* however, I has variable-length messages, I would want to do */
  6754.     /* this to avoid needing "double reads" - one for the message */
  6755.     /* length, and one for the rest of the message raj 3/95 */
  6756.     while(request_bytes_remaining > 0) {
  6757.       if((request_bytes_recvd=recv(s_data,
  6758.                    temp_message_ptr,
  6759.                    request_bytes_remaining,
  6760.                    0)) < 0) {
  6761. #ifdef WIN32
  6762.     if ( request_bytes_recvd == SOCKET_ERROR &&
  6763.          WSAGetLastError() == WSAEINTR ) {
  6764. #else
  6765.     if (errno == EINTR) {
  6766. #endif /* WIN32 */
  6767.       /* the timer popped */
  6768.       timed_out = 1;
  6769.       break;
  6770.     }
  6771.     netperf_response.content.serv_errno = errno;
  6772.     send_response();
  6773.     exit(1);
  6774.       }
  6775.       else {
  6776.     request_bytes_remaining -= request_bytes_recvd;
  6777.     temp_message_ptr  += request_bytes_recvd;
  6778.       }
  6779.     }
  6780.     
  6781.     if (timed_out) {
  6782.       /* we hit the end of the test based on time - lets */
  6783.       /* bail out of here now... */
  6784.       fprintf(where,"yo5\n");
  6785.       fflush(where);                        
  6786.       break;
  6787.     }
  6788.     
  6789.     /* Now, send the response to the remote we can use sendto here to */
  6790.     /* help remind people that this is an rfc 1644 style of test */
  6791.     if((bytes_sent=sendto(s_data,
  6792.               send_message_ptr,
  6793.               tcp_tran_rr_request->response_size,
  6794.               MSG_EOF,
  6795.               &peeraddr_in,
  6796.               sizeof(struct sockaddr_in))) == -1) {
  6797. #ifdef WIN32
  6798.       if ( bytes_sent == SOCKET_ERROR &&
  6799.       WSAGetLastError() == WSAEINTR ) {
  6800. #else
  6801.       if (errno == EINTR) {
  6802. #endif /* WIN32 */
  6803.     /* the test timer has popped */
  6804.     timed_out = 1;
  6805.     fprintf(where,"yo6\n");
  6806.     fflush(where);                        
  6807.     break;
  6808.       }
  6809.       netperf_response.content.serv_errno = 99;
  6810.       send_response();
  6811.       exit(1);
  6812.     }
  6813.     
  6814.     trans_received++;
  6815.     if (trans_remaining) {
  6816.       trans_remaining--;
  6817.     }
  6818.     
  6819.     if (debug) {
  6820.       fprintf(where,
  6821.           "recv_tcp_tran_rr: Transaction %d complete\n",
  6822.           trans_received);
  6823.       fflush(where);
  6824.     }
  6825.  
  6826.     /* close the connection. since we have disable PUSH on sends, the */
  6827.     /* FIN should be tacked-onto our last send instead of being */
  6828.     /* standalone */
  6829.     close(s_data);
  6830.  
  6831.   }
  6832.   
  6833.   
  6834.   /* The loop now exits due to timeout or transaction count being */
  6835.   /* reached */
  6836.   
  6837.   cpu_stop(tcp_tran_rr_request->measure_cpu,&elapsed_time);
  6838.   
  6839.   if (timed_out) {
  6840.     /* we ended the test by time, which was at least 2 seconds */
  6841.     /* longer than we wanted to run. so, we want to subtract */
  6842.     /* PAD_TIME from the elapsed_time. */
  6843.     elapsed_time -= PAD_TIME;
  6844.   }
  6845.   /* send the results to the sender            */
  6846.   
  6847.   if (debug) {
  6848.     fprintf(where,
  6849.         "recv_tcp_tran_rr: got %d transactions\n",
  6850.         trans_received);
  6851.     fflush(where);
  6852.   }
  6853.   
  6854.   tcp_tran_rr_results->bytes_received    = (trans_received * 
  6855.                        (tcp_tran_rr_request->request_size + 
  6856.                         tcp_tran_rr_request->response_size));
  6857.   tcp_tran_rr_results->trans_received    = trans_received;
  6858.   tcp_tran_rr_results->elapsed_time    = elapsed_time;
  6859.   if (tcp_tran_rr_request->measure_cpu) {
  6860.     tcp_tran_rr_results->cpu_util    = calc_cpu_util(elapsed_time);
  6861.   }
  6862.   
  6863.   if (debug) {
  6864.     fprintf(where,
  6865.         "recv_tcp_tran_rr: test complete, sending results.\n");
  6866.     fflush(where);
  6867.   }
  6868.   
  6869.   send_response();
  6870.   
  6871. }
  6872. #endif /* DO_1644 */
  6873.  
  6874. #ifdef DO_NBRR
  6875.  /* this routine implements the sending (netperf) side of the TCP_RR */
  6876.  /* test using POSIX-style non-blocking sockets. */
  6877.  
  6878. int 
  6879. send_tcp_nbrr(remote_host)
  6880.      char    remote_host[];
  6881. {
  6882.   
  6883.   char *tput_title = "\
  6884. Local /Remote\n\
  6885. Socket Size   Request  Resp.   Elapsed  Trans.\n\
  6886. Send   Recv   Size     Size    Time     Rate         \n\
  6887. bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
  6888.   
  6889.   char *tput_fmt_0 =
  6890.     "%7.2f\n";
  6891.   
  6892.   char *tput_fmt_1_line_1 = "\
  6893. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
  6894.   char *tput_fmt_1_line_2 = "\
  6895. %-6d %-6d\n";
  6896.   
  6897.   char *cpu_title = "\
  6898. Local /Remote\n\
  6899. Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
  6900. Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
  6901. bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
  6902.   
  6903.   char *cpu_fmt_0 =
  6904.     "%6.3f %c\n";
  6905.   
  6906.   char *cpu_fmt_1_line_1 = "\
  6907. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f\n";
  6908.   
  6909.   char *cpu_fmt_1_line_2 = "\
  6910. %-6d %-6d\n";
  6911.   
  6912.   char *ksink_fmt = "\
  6913. Alignment      Offset\n\
  6914. Local  Remote  Local  Remote\n\
  6915. Send   Recv    Send   Recv\n\
  6916. %5d  %5d   %5d  %5d";
  6917.   
  6918.   
  6919.   int            timed_out = 0;
  6920.   float            elapsed_time;
  6921.   
  6922.   int    len;
  6923.   char    *temp_message_ptr;
  6924.   int    nummessages;
  6925.   int    send_socket;
  6926.   int    trans_remaining;
  6927.   double    bytes_xferd;
  6928.  
  6929.   struct ring_elt *send_ring;
  6930.   struct ring_elt *recv_ring;
  6931.   
  6932.   int    rsp_bytes_left;
  6933.   int    rsp_bytes_recvd;
  6934.   
  6935.   float    local_cpu_utilization;
  6936.   float    local_service_demand;
  6937.   float    remote_cpu_utilization;
  6938.   float    remote_service_demand;
  6939.   double    thruput;
  6940.   
  6941.   struct    hostent            *hp;
  6942.   struct    sockaddr_in    server;
  6943.   unsigned      int             addr;
  6944.   
  6945.   struct    tcp_rr_request_struct    *tcp_rr_request;
  6946.   struct    tcp_rr_response_struct    *tcp_rr_response;
  6947.   struct    tcp_rr_results_struct    *tcp_rr_result;
  6948.   
  6949. #ifdef INTERVALS
  6950.   int    interval_count;
  6951.   sigset_t signal_set;
  6952. #endif /* INTERVALS */
  6953.  
  6954.   tcp_rr_request = 
  6955.     (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
  6956.   tcp_rr_response=
  6957.     (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
  6958.   tcp_rr_result    =
  6959.     (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
  6960.   
  6961. #ifdef HISTOGRAM
  6962.   time_hist = HIST_new();
  6963. #endif /* HISTOGRAM */
  6964.  
  6965.   /* since we are now disconnected from the code that established the */
  6966.   /* control socket, and since we want to be able to use different */
  6967.   /* protocols and such, we are passed the name of the remote host and */
  6968.   /* must turn that into the test specific addressing information. */
  6969.  
  6970.   bzero((char *)&server,
  6971.     sizeof(server));
  6972.   
  6973.  /* it would seem that while HP-UX will allow an IP address (as a */
  6974.  /* string) in a call to gethostbyname, other, less enlightened */
  6975.  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
  6976.   if ((hp = gethostbyname(remote_host)) == NULL) {
  6977.     if ((addr = inet_addr(remote_host)) == -1) {
  6978.       fprintf(where,
  6979.           "send_tcp_nbrr: could not resolve the name %s\n",
  6980.           remote_host);
  6981.       fflush(where);
  6982.       exit(1);
  6983.     }
  6984.     server.sin_addr.s_addr = addr;
  6985.     server.sin_family = AF_INET;
  6986.   }
  6987.   else {
  6988.     bcopy(hp->h_addr,
  6989.       (char *)&server.sin_addr,
  6990.       hp->h_length);
  6991.     server.sin_family = hp->h_addrtype;
  6992.   }
  6993.   
  6994.   
  6995.   if ( print_headers ) {
  6996.     fprintf(where,"TCP Non-Blocking REQUEST/RESPONSE TEST");
  6997.     fprintf(where," to %s", remote_host);
  6998.     if (iteration_max > 1) {
  6999.       fprintf(where,
  7000.           " : +/-%3.1f%% @ %2d%% conf.",
  7001.           interval/0.02,
  7002.           confidence_level);
  7003.       }
  7004.     if (loc_nodelay || rem_nodelay) {
  7005.       fprintf(where," : nodelay");
  7006.     }
  7007.     if (loc_sndavoid || 
  7008.     loc_rcvavoid ||
  7009.     rem_sndavoid ||
  7010.     rem_rcvavoid) {
  7011.       fprintf(where," : copy avoidance");
  7012.     }
  7013. #ifdef HISTOGRAM
  7014.     fprintf(where," : histogram");
  7015. #endif /* HISTOGRAM */
  7016. #ifdef INTERVALS
  7017.     fprintf(where," : interval");
  7018. #endif /* INTERVALS */
  7019. #ifdef DIRTY 
  7020.     fprintf(where," : dirty data");
  7021. #endif /* DIRTY */
  7022.     fprintf(where,"\n");
  7023.   }
  7024.   
  7025.   /* initialize a few counters */
  7026.   
  7027.   send_ring = NULL;
  7028.   recv_ring = NULL;
  7029.   confidence_iteration = 1;
  7030.   init_stat();
  7031.  
  7032.   /* we have a great-big while loop which controls the number of times */
  7033.   /* we run a particular test. this is for the calculation of a */
  7034.   /* confidence interval (I really should have stayed awake during */
  7035.   /* probstats :). If the user did not request confidence measurement */
  7036.   /* (no confidence is the default) then we will only go though the */
  7037.   /* loop once. the confidence stuff originates from the folks at IBM */
  7038.  
  7039.   while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
  7040.      (confidence_iteration <= iteration_min)) {
  7041.  
  7042.     /* initialize a few counters. we have to remember that we might be */
  7043.     /* going through the loop more than once. */
  7044.  
  7045.     nummessages     = 0;
  7046.     bytes_xferd     = 0.0;
  7047.     times_up        = 0;
  7048.     timed_out       = 0;
  7049.     trans_remaining = 0;
  7050.  
  7051.     /* set-up the data buffers with the requested alignment and offset. */
  7052.     /* since this is a request/response test, default the send_width and */
  7053.     /* recv_width to 1 and not two raj 7/94 */
  7054.  
  7055.     if (send_width == 0) send_width = 1;
  7056.     if (recv_width == 0) recv_width = 1;
  7057.   
  7058.     if (send_ring == NULL) {
  7059.       send_ring = allocate_buffer_ring(send_width,
  7060.                        req_size,
  7061.                        local_send_align,
  7062.                        local_send_offset);
  7063.     }
  7064.  
  7065.     if (recv_ring == NULL) {
  7066.       recv_ring = allocate_buffer_ring(recv_width,
  7067.                        rsp_size,
  7068.                        local_recv_align,
  7069.                        local_recv_offset);
  7070.     }
  7071.     
  7072.     /*set up the data socket                        */
  7073.     send_socket = create_data_socket(AF_INET, 
  7074.                      SOCK_STREAM);
  7075.   
  7076.     if (send_socket < 0){
  7077.       perror("netperf: send_tcp_nbrr: tcp stream data socket");
  7078.       exit(1);
  7079.     }
  7080.     
  7081.     if (debug) {
  7082.       fprintf(where,"send_tcp_nbrr: send_socket obtained...\n");
  7083.     }
  7084.   
  7085.     /* If the user has requested cpu utilization measurements, we must */
  7086.     /* calibrate the cpu(s). We will perform this task within the tests */
  7087.     /* themselves. If the user has specified the cpu rate, then */
  7088.     /* calibrate_local_cpu will return rather quickly as it will have */
  7089.     /* nothing to do. If local_cpu_rate is zero, then we will go through */
  7090.     /* all the "normal" calibration stuff and return the rate back.*/
  7091.     
  7092.     if (local_cpu_usage) {
  7093.       local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  7094.     }
  7095.     
  7096.     /* Tell the remote end to do a listen. The server alters the socket */
  7097.     /* paramters on the other side at this point, hence the reason for */
  7098.     /* all the values being passed in the setup message. If the user did */
  7099.     /* not specify any of the parameters, they will be passed as 0, which */
  7100.     /* will indicate to the remote that no changes beyond the system's */
  7101.     /* default should be used. Alignment is the exception, it will */
  7102.     /* default to 8, which will be no alignment alterations. */
  7103.     
  7104.     netperf_request.content.request_type    =    DO_TCP_NBRR;
  7105.     tcp_rr_request->recv_buf_size    =    rsr_size;
  7106.     tcp_rr_request->send_buf_size    =    rss_size;
  7107.     tcp_rr_request->recv_alignment      =    remote_recv_align;
  7108.     tcp_rr_request->recv_offset            =    remote_recv_offset;
  7109.     tcp_rr_request->send_alignment      =    remote_send_align;
  7110.     tcp_rr_request->send_offset            =    remote_send_offset;
  7111.     tcp_rr_request->request_size    =    req_size;
  7112.     tcp_rr_request->response_size    =    rsp_size;
  7113.     tcp_rr_request->no_delay            =    rem_nodelay;
  7114.     tcp_rr_request->measure_cpu            =    remote_cpu_usage;
  7115.     tcp_rr_request->cpu_rate            =    remote_cpu_rate;
  7116.     tcp_rr_request->so_rcvavoid            =    rem_rcvavoid;
  7117.     tcp_rr_request->so_sndavoid            =    rem_sndavoid;
  7118.     if (test_time) {
  7119.       tcp_rr_request->test_length    =    test_time;
  7120.     }
  7121.     else {
  7122.       tcp_rr_request->test_length    =    test_trans * -1;
  7123.     }
  7124.     
  7125.     if (debug > 1) {
  7126.       fprintf(where,"netperf: send_tcp_nbrr: requesting TCP rr test\n");
  7127.     }
  7128.     
  7129.     send_request();
  7130.     
  7131.     /* The response from the remote will contain all of the relevant     */
  7132.     /* socket parameters for this test type. We will put them back into */
  7133.     /* the variables here so they can be displayed if desired.  The    */
  7134.     /* remote will have calibrated CPU if necessary, and will have done    */
  7135.     /* all the needed set-up we will have calibrated the cpu locally    */
  7136.     /* before sending the request, and will grab the counter value right*/
  7137.     /* after the connect returns. The remote will grab the counter right*/
  7138.     /* after the accept call. This saves the hassle of extra messages    */
  7139.     /* being sent for the TCP tests.                    */
  7140.   
  7141.     recv_response();
  7142.   
  7143.     if (!netperf_response.content.serv_errno) {
  7144.       if (debug)
  7145.     fprintf(where,"remote listen done.\n");
  7146.       rsr_size          = tcp_rr_response->recv_buf_size;
  7147.       rss_size          = tcp_rr_response->send_buf_size;
  7148.       rem_nodelay       = tcp_rr_response->no_delay;
  7149.       remote_cpu_usage  = tcp_rr_response->measure_cpu;
  7150.       remote_cpu_rate   = tcp_rr_response->cpu_rate;
  7151.       /* make sure that port numbers are in network order */
  7152.       server.sin_port   = tcp_rr_response->data_port_number;
  7153.       server.sin_port   = htons(server.sin_port);
  7154.     }
  7155.     else {
  7156.       errno = netperf_response.content.serv_errno;
  7157.       fprintf(where,
  7158.           "netperf: remote error %d",
  7159.           netperf_response.content.serv_errno);
  7160.       perror("");
  7161.       fflush(where);
  7162.       exit(1);
  7163.     }
  7164.     
  7165.     /*Connect up to the remote port on the data socket  */
  7166.     if (connect(send_socket, 
  7167.         (struct sockaddr *)&server,
  7168.         sizeof(server)) <0){
  7169.       perror("netperf: data socket connect failed");
  7170.       
  7171.       exit(1);
  7172.     }
  7173.     
  7174.     /* now that we are connected, mark the socket as non-blocking */
  7175.     if (fcntl(send_socket, F_SETFL, O_NONBLOCK) == -1) {
  7176.       perror("netperf: fcntl");
  7177.       exit(1);
  7178.     }
  7179.  
  7180.     /* Data Socket set-up is finished. If there were problems, either the */
  7181.     /* connect would have failed, or the previous response would have */
  7182.     /* indicated a problem. I failed to see the value of the extra */
  7183.     /* message after the accept on the remote. If it failed, we'll see it */
  7184.     /* here. If it didn't, we might as well start pumping data. */
  7185.     
  7186.     /* Set-up the test end conditions. For a request/response test, they */
  7187.     /* can be either time or transaction based. */
  7188.     
  7189.     if (test_time) {
  7190.       /* The user wanted to end the test after a period of time. */
  7191.       times_up = 0;
  7192.       trans_remaining = 0;
  7193.       start_timer(test_time);
  7194.     }
  7195.     else {
  7196.       /* The tester wanted to send a number of bytes. */
  7197.       trans_remaining = test_bytes;
  7198.       times_up = 1;
  7199.     }
  7200.     
  7201.     /* The cpu_start routine will grab the current time and possibly */
  7202.     /* value of the idle counter for later use in measuring cpu */
  7203.     /* utilization and/or service demand and thruput. */
  7204.     
  7205.     cpu_start(local_cpu_usage);
  7206.  
  7207. #ifdef INTERVALS
  7208.     if ((interval_burst) || (demo_mode)) {
  7209.       /* zero means that we never pause, so we never should need the */
  7210.       /* interval timer, unless we are in demo_mode */
  7211.       start_itimer(interval_wate);
  7212.     }
  7213.     interval_count = interval_burst;
  7214.     /* get the signal set for the call to sigsuspend */
  7215.     if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
  7216.       fprintf(where,
  7217.           "send_tcp_nbrr: unable to get sigmask errno %d\n",
  7218.           errno);
  7219.       fflush(where);
  7220.       exit(1);
  7221.     }
  7222. #endif /* INTERVALS */
  7223.     
  7224.     /* We use an "OR" to control test execution. When the test is */
  7225.     /* controlled by time, the byte count check will always return false. */
  7226.     /* When the test is controlled by byte count, the time test will */
  7227.     /* always return false. When the test is finished, the whole */
  7228.     /* expression will go false and we will stop sending data. I think I */
  7229.     /* just arbitrarily decrement trans_remaining for the timed test, but */
  7230.     /* will not do that just yet... One other question is whether or not */
  7231.     /* the send buffer and the receive buffer should be the same buffer. */
  7232.  
  7233.     while ((!times_up) || (trans_remaining > 0)) {
  7234.       /* send the request. we assume that if we use a blocking socket, */
  7235.       /* the request will be sent at one shot. */
  7236.       
  7237. #ifdef HISTOGRAM
  7238.       /* timestamp just before our call to send, and then again just */
  7239.       /* after the receive raj 8/94 */
  7240.       gettimeofday(&time_one,NULL);
  7241. #endif /* HISTOGRAM */
  7242.  
  7243.       /* even though this is a non-blocking socket, we will assume for */
  7244.       /* the time being that we will be able to send an entire request */
  7245.       /* without getting an EAGAIN */
  7246.       if((len=send(send_socket,
  7247.            send_ring->buffer_ptr,
  7248.            req_size,
  7249.            0)) != req_size) {
  7250.     if ((errno == EINTR) || (errno == 0)) {
  7251.       /* we hit the end of a */
  7252.       /* timed test. */
  7253.       timed_out = 1;
  7254.       break;
  7255.     }
  7256.     perror("send_tcp_nbrr: data send error");
  7257.     exit(1);
  7258.       }
  7259.       send_ring = send_ring->next;
  7260.       
  7261.       /* receive the response. since we are using non-blocking I/O, we */
  7262.       /* will "spin" on the recvs */
  7263.       rsp_bytes_left = rsp_size;
  7264.       temp_message_ptr  = recv_ring->buffer_ptr;
  7265.       while(rsp_bytes_left > 0) {
  7266.     if((rsp_bytes_recvd=recv(send_socket,
  7267.                  temp_message_ptr,
  7268.                  rsp_bytes_left,
  7269.                  0)) < 0) {
  7270. #ifdef WIN32
  7271.     if (rsp_bytes_recvd == SOCKET_ERROR &&
  7272.          WSAGetLastError() == WSAEINTR ) {
  7273. #else
  7274.     if (errno == EINTR) {
  7275. #endif /* WIN32 */
  7276.         /* We hit the end of a timed test. */
  7277.         timed_out = 1;
  7278.         break;
  7279.       }
  7280.       else if (errno == EAGAIN) {
  7281.         errno = 0;
  7282.         continue;
  7283.       }
  7284.       else {
  7285.         perror("send_tcp_nbrr: data recv error");
  7286.         exit(1);
  7287.       }
  7288.     }
  7289.     rsp_bytes_left -= rsp_bytes_recvd;
  7290.     temp_message_ptr  += rsp_bytes_recvd;
  7291.       }    
  7292.       recv_ring = recv_ring->next;
  7293.       
  7294.       if (timed_out) {
  7295.     /* we may have been in a nested while loop - we need */
  7296.     /* another call to break. */
  7297.     break;
  7298.       }
  7299.       
  7300. #ifdef HISTOGRAM
  7301.       gettimeofday(&time_two,NULL);
  7302.       HIST_add(time_hist,delta_micro(&time_one,&time_two));
  7303. #endif /* HISTOGRAM */
  7304. #ifdef INTERVALS      
  7305.       if (demo_mode) {
  7306.     units_this_tick += 1;
  7307.       }
  7308.       /* in this case, the interval count is the count-down couter */
  7309.       /* to decide to sleep for a little bit */
  7310.       if ((interval_burst) && (--interval_count == 0)) {
  7311.     /* call sigsuspend and wait for the interval timer to get us */
  7312.     /* out */
  7313.     if (debug) {
  7314.       fprintf(where,"about to suspend\n");
  7315.       fflush(where);
  7316.     }
  7317.     if (sigsuspend(&signal_set) == EFAULT) {
  7318.       fprintf(where,
  7319.           "send_udp_rr: fault with signal set!\n");
  7320.       fflush(where);
  7321.       exit(1);
  7322.     }
  7323.     interval_count = interval_burst;
  7324.       }
  7325. #endif /* INTERVALS */
  7326.       
  7327.       nummessages++;          
  7328.       if (trans_remaining) {
  7329.     trans_remaining--;
  7330.       }
  7331.       
  7332.       if (debug > 3) {
  7333.     if ((nummessages % 100) == 0) {
  7334.       fprintf(where,
  7335.           "Transaction %d completed\n",
  7336.           nummessages);
  7337.       fflush(where);
  7338.     }
  7339.       }
  7340.     }
  7341.  
  7342.     /* At this point we used to call shutdown on the data socket to be */
  7343.     /* sure all the data was delivered, but this was not germane in a */
  7344.     /* request/response test, and it was causing the tests to "hang" when */
  7345.     /* they were being controlled by time. So, I have replaced this */
  7346.     /* shutdown call with a call to close that can be found later in the */
  7347.     /* procedure. */
  7348.     
  7349.     /* this call will always give us the elapsed time for the test, and */
  7350.     /* will also store-away the necessaries for cpu utilization */
  7351.     
  7352.     cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
  7353.                         /* measured? how long */
  7354.                         /* did we really run? */
  7355.     
  7356.     /* Get the statistics from the remote end. The remote will have */
  7357.     /* calculated service demand and all those interesting things. If it */
  7358.     /* wasn't supposed to care, it will return obvious values. */
  7359.     
  7360.     recv_response();
  7361.     if (!netperf_response.content.serv_errno) {
  7362.       if (debug)
  7363.     fprintf(where,"remote results obtained\n");
  7364.     }
  7365.     else {
  7366.       errno = netperf_response.content.serv_errno;
  7367.       fprintf(where,
  7368.           "netperf: remote error %d",
  7369.           netperf_response.content.serv_errno);
  7370.       perror("");
  7371.       fflush(where);
  7372.       
  7373.       exit(1);
  7374.     }
  7375.     
  7376.     /* We now calculate what our thruput was for the test. */
  7377.   
  7378.     bytes_xferd    = (req_size * nummessages) + (rsp_size * nummessages);
  7379.     thruput    = nummessages/elapsed_time;
  7380.   
  7381.     if (local_cpu_usage || remote_cpu_usage) {
  7382.       /* We must now do a little math for service demand and cpu */
  7383.       /* utilization for the system(s) */
  7384.       /* Of course, some of the information might be bogus because */
  7385.       /* there was no idle counter in the kernel(s). We need to make */
  7386.       /* a note of this for the user's benefit...*/
  7387.       if (local_cpu_usage) {
  7388.     local_cpu_utilization = calc_cpu_util(0.0);
  7389.     /* since calc_service demand is doing ms/Kunit we will */
  7390.     /* multiply the number of transaction by 1024 to get */
  7391.     /* "good" numbers */
  7392.     local_service_demand  = calc_service_demand((double) nummessages*1024,
  7393.                             0.0,
  7394.                             0.0,
  7395.                             0);
  7396.       }
  7397.       else {
  7398.     local_cpu_utilization    = (float) -1.0;
  7399.     local_service_demand    = (float) -1.0;
  7400.       }
  7401.       
  7402.       if (remote_cpu_usage) {
  7403.     remote_cpu_utilization = tcp_rr_result->cpu_util;
  7404.     /* since calc_service demand is doing ms/Kunit we will */
  7405.     /* multiply the number of transaction by 1024 to get */
  7406.     /* "good" numbers */
  7407.     remote_service_demand = calc_service_demand((double) nummessages*1024,
  7408.                             0.0,
  7409.                             remote_cpu_utilization,
  7410.                             tcp_rr_result->num_cpus);
  7411.       }
  7412.       else {
  7413.     remote_cpu_utilization = (float) -1.0;
  7414.     remote_service_demand  = (float) -1.0;
  7415.       }
  7416.       
  7417.     }
  7418.     else {
  7419.       /* we were not measuring cpu, for the confidence stuff, we */
  7420.       /* should make it -1.0 */
  7421.       local_cpu_utilization    = (float) -1.0;
  7422.       local_service_demand    = (float) -1.0;
  7423.       remote_cpu_utilization = (float) -1.0;
  7424.       remote_service_demand  = (float) -1.0;
  7425.     }
  7426.  
  7427.     /* at this point, we want to calculate the confidence information. */
  7428.     /* if debugging is on, calculate_confidence will print-out the */
  7429.     /* parameters we pass it */
  7430.     
  7431.     calculate_confidence(confidence_iteration,
  7432.              elapsed_time,
  7433.              thruput,
  7434.              local_cpu_utilization,
  7435.              remote_cpu_utilization,
  7436.              local_service_demand,
  7437.              remote_service_demand);
  7438.     
  7439.     
  7440.     confidence_iteration++;
  7441.  
  7442.     /* we are now done with the socket, so close it */
  7443.     close(send_socket);
  7444.  
  7445.   }
  7446.  
  7447.   retrieve_confident_values(&elapsed_time,
  7448.                 &thruput,
  7449.                 &local_cpu_utilization,
  7450.                 &remote_cpu_utilization,
  7451.                 &local_service_demand,
  7452.                 &remote_service_demand);
  7453.  
  7454.   /* We are now ready to print all the information. If the user */
  7455.   /* has specified zero-level verbosity, we will just print the */
  7456.   /* local service demand, or the remote service demand. If the */
  7457.   /* user has requested verbosity level 1, he will get the basic */
  7458.   /* "streamperf" numbers. If the user has specified a verbosity */
  7459.   /* of greater than 1, we will display a veritable plethora of */
  7460.   /* background information from outside of this block as it it */
  7461.   /* not cpu_measurement specific...  */
  7462.  
  7463.   if (confidence < 0) {
  7464.     /* we did not hit confidence, but were we asked to look for it? */
  7465.     if (iteration_max > 1) {
  7466.       display_confidence();
  7467.     }
  7468.   }
  7469.  
  7470.   if (local_cpu_usage || remote_cpu_usage) {
  7471.     local_cpu_method = format_cpu_method(cpu_method);
  7472.     remote_cpu_method = format_cpu_method(tcp_rr_result->cpu_method);
  7473.     
  7474.     switch (verbosity) {
  7475.     case 0:
  7476.       if (local_cpu_usage) {
  7477.     fprintf(where,
  7478.         cpu_fmt_0,
  7479.         local_service_demand,
  7480.         local_cpu_method);
  7481.       }
  7482.       else {
  7483.     fprintf(where,
  7484.         cpu_fmt_0,
  7485.         remote_service_demand,
  7486.         remote_cpu_method);
  7487.       }
  7488.       break;
  7489.     case 1:
  7490.     case 2:
  7491.       if (print_headers) {
  7492.     fprintf(where,
  7493.         cpu_title,
  7494.         local_cpu_method,
  7495.         remote_cpu_method);
  7496.       }
  7497.  
  7498.       fprintf(where,
  7499.           cpu_fmt_1_line_1,        /* the format string */
  7500.           lss_size,        /* local sendbuf size */
  7501.           lsr_size,
  7502.           req_size,        /* how large were the requests */
  7503.           rsp_size,        /* guess */
  7504.           elapsed_time,        /* how long was the test */
  7505.           thruput,
  7506.           local_cpu_utilization,    /* local cpu */
  7507.           remote_cpu_utilization,    /* remote cpu */
  7508.           local_service_demand,    /* local service demand */
  7509.           remote_service_demand);    /* remote service demand */
  7510.       fprintf(where,
  7511.           cpu_fmt_1_line_2,
  7512.           rss_size,
  7513.           rsr_size);
  7514.       break;
  7515.     }
  7516.   }
  7517.   else {
  7518.     /* The tester did not wish to measure service demand. */
  7519.     
  7520.     switch (verbosity) {
  7521.     case 0:
  7522.       fprintf(where,
  7523.           tput_fmt_0,
  7524.           thruput);
  7525.       break;
  7526.     case 1:
  7527.     case 2:
  7528.       if (print_headers) {
  7529.     fprintf(where,tput_title,format_units());
  7530.       }
  7531.  
  7532.       fprintf(where,
  7533.           tput_fmt_1_line_1,    /* the format string */
  7534.           lss_size,
  7535.           lsr_size,
  7536.           req_size,        /* how large were the requests */
  7537.           rsp_size,        /* how large were the responses */
  7538.           elapsed_time,         /* how long did it take */
  7539.           thruput);
  7540.       fprintf(where,
  7541.           tput_fmt_1_line_2,
  7542.           rss_size,         /* remote recvbuf size */
  7543.           rsr_size);
  7544.       
  7545.       break;
  7546.     }
  7547.   }
  7548.   
  7549.   /* it would be a good thing to include information about some of the */
  7550.   /* other parameters that may have been set for this test, but at the */
  7551.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  7552.   /* just put this comment here to help remind me that it is something */
  7553.   /* that should be done at a later time. */
  7554.   
  7555.   /* how to handle the verbose information in the presence of */
  7556.   /* confidence intervals is yet to be determined... raj 11/94 */
  7557.   if (verbosity > 1) {
  7558.     /* The user wanted to know it all, so we will give it to him. */
  7559.     /* This information will include as much as we can find about */
  7560.     /* TCP statistics, the alignments of the sends and receives */
  7561.     /* and all that sort of rot... */
  7562.     
  7563.     fprintf(where,
  7564.         ksink_fmt,
  7565.         local_send_align,
  7566.         remote_recv_offset,
  7567.         local_send_offset,
  7568.         remote_recv_offset);
  7569.  
  7570. #ifdef HISTOGRAM
  7571.     fprintf(where,"\nHistogram of request/response times\n");
  7572.     fflush(where);
  7573.     HIST_report(time_hist);
  7574. #endif /* HISTOGRAM */
  7575.  
  7576.   }
  7577.   
  7578. }
  7579.  
  7580.  /* this routine implements the receive (netserver) side of a TCP_RR */
  7581.  /* test */
  7582. int 
  7583. recv_tcp_nbrr()
  7584. {
  7585.   
  7586.   struct ring_elt *send_ring;
  7587.   struct ring_elt *recv_ring;
  7588.  
  7589.   struct    sockaddr_in        myaddr_in,
  7590.   peeraddr_in;
  7591.   int    s_listen,s_data;
  7592.   int     addrlen;
  7593.   char    *temp_message_ptr;
  7594.   int    trans_received;
  7595.   int    trans_remaining;
  7596.   int    bytes_sent;
  7597.   int    request_bytes_recvd;
  7598.   int    request_bytes_remaining;
  7599.   int    timed_out = 0;
  7600.   float    elapsed_time;
  7601.   
  7602.   struct    tcp_rr_request_struct    *tcp_rr_request;
  7603.   struct    tcp_rr_response_struct    *tcp_rr_response;
  7604.   struct    tcp_rr_results_struct    *tcp_rr_results;
  7605.   
  7606.   tcp_rr_request = 
  7607.     (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
  7608.   tcp_rr_response =
  7609.     (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
  7610.   tcp_rr_results =
  7611.     (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
  7612.   
  7613.   if (debug) {
  7614.     fprintf(where,"netserver: recv_tcp_nbrr: entered...\n");
  7615.     fflush(where);
  7616.   }
  7617.   
  7618.   /* We want to set-up the listen socket with all the desired */
  7619.   /* parameters and then let the initiator know that all is ready. If */
  7620.   /* socket size defaults are to be used, then the initiator will have */
  7621.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  7622.   /* send-back what they are. If that information cannot be determined, */
  7623.   /* then we send-back -1's for the sizes. If things go wrong for any */
  7624.   /* reason, we will drop back ten yards and punt. */
  7625.   
  7626.   /* If anything goes wrong, we want the remote to know about it. It */
  7627.   /* would be best if the error that the remote reports to the user is */
  7628.   /* the actual error we encountered, rather than some bogus unexpected */
  7629.   /* response type message. */
  7630.   
  7631.   if (debug) {
  7632.     fprintf(where,"recv_tcp_nbrr: setting the response type...\n");
  7633.     fflush(where);
  7634.   }
  7635.   
  7636.   netperf_response.content.response_type = TCP_RR_RESPONSE;
  7637.   
  7638.   if (debug) {
  7639.     fprintf(where,"recv_tcp_nbrr: the response type is set...\n");
  7640.     fflush(where);
  7641.   }
  7642.   
  7643.   /* allocate the recv and send rings with the requested alignments */
  7644.   /* and offsets. raj 7/94 */
  7645.   if (debug) {
  7646.     fprintf(where,"recv_tcp_nbrr: requested recv alignment of %d offset %d\n",
  7647.         tcp_rr_request->recv_alignment,
  7648.         tcp_rr_request->recv_offset);
  7649.     fprintf(where,"recv_tcp_nbrr: requested send alignment of %d offset %d\n",
  7650.         tcp_rr_request->send_alignment,
  7651.         tcp_rr_request->send_offset);
  7652.     fflush(where);
  7653.   }
  7654.  
  7655.   /* at some point, these need to come to us from the remote system */
  7656.   if (send_width == 0) send_width = 1;
  7657.   if (recv_width == 0) recv_width = 1;
  7658.  
  7659.   send_ring = allocate_buffer_ring(send_width,
  7660.                    tcp_rr_request->response_size,
  7661.                    tcp_rr_request->send_alignment,
  7662.                    tcp_rr_request->send_offset);
  7663.  
  7664.   recv_ring = allocate_buffer_ring(recv_width,
  7665.                    tcp_rr_request->request_size,
  7666.                    tcp_rr_request->recv_alignment,
  7667.                    tcp_rr_request->recv_offset);
  7668.  
  7669.   
  7670.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  7671.   /* can put in OUR values !-) At some point, we may want to nail this */
  7672.   /* socket to a particular network-level address, but for now, */
  7673.   /* INADDR_ANY should be just fine. */
  7674.   
  7675.   bzero((char *)&myaddr_in,
  7676.     sizeof(myaddr_in));
  7677.   myaddr_in.sin_family      = AF_INET;
  7678.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  7679.   myaddr_in.sin_port        = 0;
  7680.   
  7681.   /* Grab a socket to listen on, and then listen on it. */
  7682.   
  7683.   if (debug) {
  7684.     fprintf(where,"recv_tcp_nbrr: grabbing a socket...\n");
  7685.     fflush(where);
  7686.   }
  7687.  
  7688.   /* create_data_socket expects to find some things in the global */
  7689.   /* variables, so set the globals based on the values in the request. */
  7690.   /* once the socket has been created, we will set the response values */
  7691.   /* based on the updated value of those globals. raj 7/94 */
  7692.   lss_size = tcp_rr_request->send_buf_size;
  7693.   lsr_size = tcp_rr_request->recv_buf_size;
  7694.   loc_nodelay = tcp_rr_request->no_delay;
  7695.   loc_rcvavoid = tcp_rr_request->so_rcvavoid;
  7696.   loc_sndavoid = tcp_rr_request->so_sndavoid;
  7697.   
  7698.   s_listen = create_data_socket(AF_INET,
  7699.                 SOCK_STREAM);
  7700.   
  7701.   if (s_listen < 0) {
  7702.     netperf_response.content.serv_errno = errno;
  7703.     send_response();
  7704.     
  7705.     exit(1);
  7706.   }
  7707.   
  7708.   /* Let's get an address assigned to this socket so we can tell the */
  7709.   /* initiator how to reach the data socket. There may be a desire to */
  7710.   /* nail this socket to a specific IP address in a multi-homed, */
  7711.   /* multi-connection situation, but for now, we'll ignore the issue */
  7712.   /* and concentrate on single connection testing. */
  7713.   
  7714.   if (bind(s_listen,
  7715.        (struct sockaddr *)&myaddr_in,
  7716.        sizeof(myaddr_in)) == -1) {
  7717.     netperf_response.content.serv_errno = errno;
  7718.     close(s_listen);
  7719.     send_response();
  7720.     
  7721.     exit(1);
  7722.   }
  7723.   
  7724.   /* Now, let's set-up the socket to listen for connections */
  7725.   if (listen(s_listen, 5) == -1) {
  7726.     netperf_response.content.serv_errno = errno;
  7727.     close(s_listen);
  7728.     send_response();
  7729.     
  7730.     exit(1);
  7731.   }
  7732.   
  7733.   
  7734.   /* now get the port number assigned by the system  */
  7735.   addrlen = sizeof(myaddr_in);
  7736.   if (getsockname(s_listen,
  7737.           (struct sockaddr *)&myaddr_in, &addrlen) == -1){
  7738.     netperf_response.content.serv_errno = errno;
  7739.     close(s_listen);
  7740.     send_response();
  7741.     
  7742.     exit(1);
  7743.   }
  7744.   
  7745.   /* Now myaddr_in contains the port and the internet address this is */
  7746.   /* returned to the sender also implicitly telling the sender that the */
  7747.   /* socket buffer sizing has been done. */
  7748.   
  7749.   tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
  7750.   netperf_response.content.serv_errno   = 0;
  7751.   
  7752.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  7753.   /* then we must call the calibrate routine, which will return the max */
  7754.   /* rate back to the initiator. If the CPU was not to be measured, or */
  7755.   /* something went wrong with the calibration, we will return a 0.0 to */
  7756.   /* the initiator. */
  7757.   
  7758.   tcp_rr_response->cpu_rate = 0.0;     /* assume no cpu */
  7759.   tcp_rr_response->measure_cpu = 0;
  7760.  
  7761.   if (tcp_rr_request->measure_cpu) {
  7762.     tcp_rr_response->measure_cpu = 1;
  7763.     tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
  7764.   }
  7765.   
  7766.   
  7767.   /* before we send the response back to the initiator, pull some of */
  7768.   /* the socket parms from the globals */
  7769.   tcp_rr_response->send_buf_size = lss_size;
  7770.   tcp_rr_response->recv_buf_size = lsr_size;
  7771.   tcp_rr_response->no_delay = loc_nodelay;
  7772.   tcp_rr_response->so_rcvavoid = loc_rcvavoid;
  7773.   tcp_rr_response->so_sndavoid = loc_sndavoid;
  7774.   tcp_rr_response->test_length = tcp_rr_request->test_length;
  7775.   send_response();
  7776.   
  7777.   addrlen = sizeof(peeraddr_in);
  7778.   
  7779.   if ((s_data = accept(s_listen,
  7780.                (struct sockaddr *)&peeraddr_in,
  7781.                &addrlen)) ==  -1) {
  7782.     /* Let's just punt. The remote will be given some information */
  7783.     close(s_listen);
  7784.     exit(1);
  7785.   }
  7786.   
  7787.   if (debug) {
  7788.     fprintf(where,"recv_tcp_nbrr: accept completes on the data connection.\n");
  7789.     fflush(where);
  7790.   }
  7791.  
  7792. #ifdef KLUDGE_SOCKET_OPTIONS
  7793.   /* this is for those systems which *INCORRECTLY* fail to pass */
  7794.   /* attributes across an accept() call. Including this goes against */
  7795.   /* my better judgement :( raj 11/95 */
  7796.  
  7797.   kludge_socket_options(s_data);
  7798.  
  7799. #endif /* KLUDGE_SOCKET_OPTIONS */
  7800.     
  7801.   /* now that we are connected, mark the socket as non-blocking */
  7802.   if (fcntl(s_data, F_SETFL, O_NONBLOCK) == -1) {
  7803.     close(s_data);
  7804.     exit(1);
  7805.   }
  7806.  
  7807.   
  7808.   /* Now it's time to start receiving data on the connection. We will */
  7809.   /* first grab the apropriate counters and then start grabbing. */
  7810.   
  7811.   cpu_start(tcp_rr_request->measure_cpu);
  7812.   
  7813.   /* The loop will exit when the sender does a shutdown, which will */
  7814.   /* return a length of zero   */
  7815.   
  7816.   if (tcp_rr_request->test_length > 0) {
  7817.     times_up = 0;
  7818.     trans_remaining = 0;
  7819.     start_timer(tcp_rr_request->test_length + PAD_TIME);
  7820.   }
  7821.   else {
  7822.     times_up = 1;
  7823.     trans_remaining = tcp_rr_request->test_length * -1;
  7824.   }
  7825.  
  7826.   trans_received = 0;
  7827.   
  7828.   while ((!times_up) || (trans_remaining > 0)) {
  7829.     temp_message_ptr = recv_ring->buffer_ptr;
  7830.     request_bytes_remaining    = tcp_rr_request->request_size;
  7831.     while(request_bytes_remaining > 0) {
  7832.       if((request_bytes_recvd=recv(s_data,
  7833.                    temp_message_ptr,
  7834.                    request_bytes_remaining,
  7835.                    0)) < 0) {
  7836. #ifdef WIN32
  7837.     if ( request_bytes_recvd == SOCKET_ERROR &&
  7838.          WSAGetLastError() == WSAEINTR ) {
  7839. #else
  7840.     if (errno == EINTR) {
  7841. #endif /* WIN32 */
  7842.       /* the timer popped */
  7843.       timed_out = 1;
  7844.       break;
  7845.     }
  7846.     else if (errno == EAGAIN) {
  7847.       errno = 0;
  7848.       if (times_up) {
  7849.         timed_out = 1;
  7850.         break;
  7851.       }
  7852.       continue;
  7853.     }
  7854.     else {
  7855.       netperf_response.content.serv_errno = errno;
  7856.       send_response();
  7857.       exit(1);
  7858.     }
  7859.       }
  7860.       else {
  7861.     request_bytes_remaining -= request_bytes_recvd;
  7862.     temp_message_ptr  += request_bytes_recvd;
  7863.       }
  7864.     }
  7865.  
  7866.     recv_ring = recv_ring->next;
  7867.  
  7868.     if (timed_out) {
  7869.       /* we hit the end of the test based on time - lets */
  7870.       /* bail out of here now... */
  7871.       fprintf(where,"yo5\n");
  7872.       fflush(where);                        
  7873.       break;
  7874.     }
  7875.     
  7876.     /* Now, send the response to the remote */
  7877.     if((bytes_sent=send(s_data,
  7878.             send_ring->buffer_ptr,
  7879.             tcp_rr_request->response_size,
  7880.             0)) == -1) {
  7881. #ifdef WIN32
  7882.       if (bytes_sent == SOCKET_ERROR && WSAGetLastError() == WSAEINTR ){
  7883. #else
  7884.       if (errno == EINTR) {
  7885. #endif /* WIN32 */
  7886.     /* the test timer has popped */
  7887.     timed_out = 1;
  7888.     fprintf(where,"yo6\n");
  7889.     fflush(where);                        
  7890.     break;
  7891.       }
  7892.       netperf_response.content.serv_errno = 992;
  7893.       send_response();
  7894.       exit(1);
  7895.     }
  7896.     
  7897.     send_ring = send_ring->next;
  7898.  
  7899.     trans_received++;
  7900.     if (trans_remaining) {
  7901.       trans_remaining--;
  7902.     }
  7903.   }
  7904.   
  7905.   
  7906.   /* The loop now exits due to timeout or transaction count being */
  7907.   /* reached */
  7908.   
  7909.   cpu_stop(tcp_rr_request->measure_cpu,&elapsed_time);
  7910.   
  7911.   stop_timer();
  7912.  
  7913.   if (timed_out) {
  7914.     /* we ended the test by time, which was at least 2 seconds */
  7915.     /* longer than we wanted to run. so, we want to subtract */
  7916.     /* PAD_TIME from the elapsed_time. */
  7917.     elapsed_time -= PAD_TIME;
  7918.   }
  7919.  
  7920.   /* send the results to the sender            */
  7921.   
  7922.   if (debug) {
  7923.     fprintf(where,
  7924.         "recv_tcp_nbrr: got %d transactions\n",
  7925.         trans_received);
  7926.     fflush(where);
  7927.   }
  7928.   
  7929.   tcp_rr_results->bytes_received = (trans_received * 
  7930.                     (tcp_rr_request->request_size + 
  7931.                      tcp_rr_request->response_size));
  7932.   tcp_rr_results->trans_received = trans_received;
  7933.   tcp_rr_results->elapsed_time   = elapsed_time;
  7934.   tcp_rr_results->cpu_method     = cpu_method;
  7935.   tcp_rr_results->num_cpus       = lib_num_loc_cpus;
  7936.   if (tcp_rr_request->measure_cpu) {
  7937.     tcp_rr_results->cpu_util    = calc_cpu_util(elapsed_time);
  7938.   }
  7939.   
  7940.   if (debug) {
  7941.     fprintf(where,
  7942.         "recv_tcp_nbrr: test complete, sending results.\n");
  7943.     fflush(where);
  7944.   }
  7945.   
  7946.   /* we are done with the socket, free it */
  7947.   close(s_data);
  7948.  
  7949.   send_response();
  7950.   
  7951. }
  7952.  
  7953. #endif /* DO_NBRR */
  7954.  
  7955.  
  7956. void
  7957. print_sockets_usage()
  7958. {
  7959.  
  7960.   printf("%s",sockets_usage);
  7961.   exit(1);
  7962.  
  7963. }
  7964. void
  7965. scan_sockets_args(argc, argv)
  7966.      int    argc;
  7967.      char    *argv[];
  7968.  
  7969. {
  7970. #define SOCKETS_ARGS "Dhm:M:p:r:s:S:Vw:W:z"
  7971.   extern char    *optarg;      /* pointer to option string    */
  7972.   
  7973.   int        c;
  7974.   
  7975.   char    
  7976.     arg1[BUFSIZ],  /* argument holders        */
  7977.     arg2[BUFSIZ];
  7978.   
  7979.   /* Go through all the command line arguments and break them */
  7980.   /* out. For those options that take two parms, specifying only */
  7981.   /* the first will set both to that value. Specifying only the */
  7982.   /* second will leave the first untouched. To change only the */
  7983.   /* first, use the form "first," (see the routine break_args.. */
  7984.   
  7985.   while ((c= getopt(argc, argv, SOCKETS_ARGS)) != EOF) {
  7986.     switch (c) {
  7987.     case '?':    
  7988.     case 'h':
  7989.       print_sockets_usage();
  7990.       exit(1);
  7991.     case 'D':
  7992.       /* set the TCP nodelay flag */
  7993.       loc_nodelay = 1;
  7994.       rem_nodelay = 1;
  7995.       break;
  7996.     case 's':
  7997.       /* set local socket sizes */
  7998.       break_args(optarg,arg1,arg2);
  7999.       if (arg1[0])
  8000.     lss_size = convert(arg1);
  8001.       if (arg2[0])
  8002.     lsr_size = convert(arg2);
  8003.       break;
  8004.     case 'S':
  8005.       /* set remote socket sizes */
  8006.       break_args(optarg,arg1,arg2);
  8007.       if (arg1[0])
  8008.     rss_size = convert(arg1);
  8009.       if (arg2[0])
  8010.     rsr_size = convert(arg2);
  8011.       break;
  8012.     case 'r':
  8013.       /* set the request/response sizes */
  8014.       break_args(optarg,arg1,arg2);
  8015.       if (arg1[0])
  8016.     req_size = convert(arg1);
  8017.       if (arg2[0])    
  8018.     rsp_size = convert(arg2);
  8019.       break;
  8020.     case 'm':
  8021.       /* set the send size */
  8022.       send_size = convert(optarg);
  8023.       break;
  8024.     case 'M':
  8025.       /* set the recv size */
  8026.       recv_size = convert(optarg);
  8027.       break;
  8028.     case 'p':
  8029.       /* set the min and max port numbers for the TCP_CRR and TCP_TRR */
  8030.       /* tests. */
  8031.       break_args(optarg,arg1,arg2);
  8032.       if (arg1[0])
  8033.     client_port_min = atoi(arg1);
  8034.       if (arg2[0])    
  8035.     client_port_max = atoi(arg2);
  8036.       break;
  8037.     case 't':
  8038.       /* set the test name */
  8039.       strcpy(test_name,optarg);
  8040.       break;
  8041.     case 'W':
  8042.       /* set the "width" of the user space data */
  8043.       /* buffer. This will be the number of */
  8044.       /* send_size buffers malloc'd in the */
  8045.       /* *_STREAM test. It may be enhanced to set */
  8046.       /* both send and receive "widths" but for now */
  8047.       /* it is just the sending *_STREAM. */
  8048.       send_width = convert(optarg);
  8049.       break;
  8050.     case 'V' :
  8051.       /* we want to do copy avoidance and will set */
  8052.       /* it for everything, everywhere, if we really */
  8053.       /* can. of course, we don't know anything */
  8054.       /* about the remote... */
  8055. #ifdef SO_SND_COPYAVOID
  8056.       loc_sndavoid = 1;
  8057. #else
  8058.       loc_sndavoid = 0;
  8059.       printf("Local send copy avoidance not available.\n");
  8060. #endif
  8061. #ifdef SO_RCV_COPYAVOID
  8062.       loc_rcvavoid = 1;
  8063. #else
  8064.       loc_rcvavoid = 0;
  8065.       printf("Local recv copy avoidance not available.\n");
  8066. #endif
  8067.       rem_sndavoid = 1;
  8068.       rem_rcvavoid = 1;
  8069.       break;
  8070.     };
  8071.   }
  8072. }
  8073.