nettest_dlpi.c
Upload User: kvgkvg
Upload Date: 2015-05-07
Package Size: 1129k
Code Size: 122k
Development Platform:

C/C++

  1. /****************************************************************/
  2. /* */
  3. /* nettest_dlpi.c */
  4. /* */
  5. /* the actual test routines... */
  6. /* */
  7. /* send_dlpi_co_stream() perform a CO DLPI stream test */
  8. /* recv_dlpi_co_stream() */
  9. /* send_dlpi_co_rr() perform a CO DLPI req/res */
  10. /* recv_dlpi_co_rr() */
  11. /* send_dlpi_cl_stream() perform a CL DLPI stream test */
  12. /* recv_dlpi_cl_stream() */
  13. /* send_dlpi_cl_rr() perform a CL DLPI req/res */
  14. /* recv_dlpi_cl_rr() */
  15. /* */
  16. /****************************************************************/
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #ifdef WANT_DLPI
  21. char nettest_dlpi_id[]="
  22. @(#)nettest_dlpi.c (c) Copyright 1993,1995,2004 Hewlett-Packard Co. Version 2.4.3";
  23. #include <sys/types.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <malloc.h>
  31. #include <sys/stream.h>
  32. #include <sys/stropts.h>
  33. #include <sys/poll.h>
  34. #ifdef __osf__
  35. #include <sys/dlpihdr.h>
  36. #else /* __osf__ */
  37. #include <sys/dlpi.h>
  38. #ifdef __hpux__
  39. #include <sys/dlpi_ext.h>
  40. #endif /* __hpux__ */
  41. #endif /* __osf__ */
  42. #include "netlib.h"
  43. #include "netsh.h"
  44. #include "nettest_dlpi.h"
  45. /* these are some variables global to all the DLPI tests. declare */
  46. /* them static to make them global only to this file */
  47. static int 
  48.   rsw_size, /* remote send window size */
  49.   rrw_size, /* remote recv window size */
  50.   lsw_size, /* local  send window size  */
  51.   lrw_size, /* local  recv window size  */
  52.   req_size = 100, /* request size                    */
  53.   rsp_size = 200, /* response size */
  54.   send_size, /* how big are individual sends */
  55.   recv_size; /* how big are individual receives */
  56. int
  57.   loc_ppa = 4,          /* the ppa for the local interface, */
  58.   /* as shown as the NM Id in lanscan */
  59.   rem_ppa = 4,          /* the ppa for the remote interface */
  60.   dlpi_sap = 84;        /* which 802.2 SAP should we use?   */
  61. char loc_dlpi_device[32] = "/dev/dlpi";
  62. char rem_dlpi_device[32] = "/dev/dlpi";
  63. char dlpi_usage[] = "n
  64. Usage: netperf [global options] -- [test options] n
  65. n
  66. CO/CL DLPI Test Options:n
  67.     -D dev[,dev]      Set the local/remote DLPI device file namen
  68.     -h                Display this textn
  69.     -M bytes          Set the recv size (DLCO_STREAM, DLCL_STREAM)n
  70.     -m bytes          Set the send size (DLCO_STREAM, DLCL_STREAM)n
  71.     -p loc[,rem]      Set the local/remote PPA for the testn
  72.     -R bytes          Set response size (DLCO_RR, DLCL_RR)n
  73.     -r bytes          Set request size (DLCO_RR, DLCL_RR)n
  74.     -s sap            Set the 802.2 sap for the testn
  75.     -W send[,recv]    Set remote send/recv window sizesn
  76.     -w send[,recv]    Set local send/recv window sizesn
  77. n
  78. For those options taking two parms, at least one must be specified;n
  79. specifying one value without a comma will set both parms to thatn
  80. value, specifying a value with a leading comma will set just the secondn
  81. parm, a value with a trailing comma will set just the first. To setn
  82. each parm to unique values, specify both and separate them with an
  83. comma.n"; 
  84. /* This routine implements the CO unidirectional data transfer test */
  85. /* (a.k.a. stream) for the sockets interface. It receives its */
  86. /* parameters via global variables from the shell and writes its */
  87. /* output to the standard output. */
  88. void 
  89. send_dlpi_co_stream()
  90. {
  91.   
  92.   char *tput_title = "
  93. Recv   Send    Send                          n
  94. Window Window  Message  Elapsed              n
  95. Size   Size    Size     Time     Throughput  n
  96. frames frames  bytes    secs.    %s/sec  nn";
  97.   
  98.   char *tput_fmt_0 =
  99.     "%7.2fn";
  100.   
  101.   char *tput_fmt_1 =
  102.     "%5d  %5d  %6d    %-6.2f   %7.2f   n";
  103.   
  104.   char *cpu_title = "
  105. Recv   Send    Send                          Utilization    Service Demandn
  106. Window Window  Message  Elapsed              Send   Recv    Send    Recvn
  107. Size   Size    Size     Time     Throughput  local  remote  local   remoten
  108. frames frames  bytes    secs.    %-8.8s/s  %%      %%       us/KB   us/KBnn";
  109.   
  110.   char *cpu_fmt_0 =
  111.     "%6.3fn";
  112.   
  113.   char *cpu_fmt_1 =
  114.     "%5d  %5d  %6d    %-6.2f     %7.2f   %-6.2f %-6.2f  %-6.3f  %-6.3fn";
  115.   
  116.   char *ksink_fmt = "n
  117. Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvsn
  118. Local  Remote  Local  Remote  Xfered   Per                 Pern
  119. Send   Recv    Send   Recv             Send (avg)          Recv (avg)n
  120. %5d   %5d  %5d   %5d %6.4g  %6.2f     %6d %6.2f   %6dn";
  121.   
  122.   
  123.   float elapsed_time;
  124.   
  125. #ifdef WANT_INTERVALS
  126.   int interval_count;
  127. #endif /* WANT_INTERVALS */
  128.   
  129.   /* what we want is to have a buffer space that is at least one */
  130.   /* send-size greater than our send window. this will insure that we */
  131.   /* are never trying to re-use a buffer that may still be in the hands */
  132.   /* of the transport. This buffer will be malloc'd after we have found */
  133.   /* the size of the local senc socket buffer. We will want to deal */
  134.   /* with alignment and offset concerns as well. */
  135.   
  136.   struct ring_elt *send_ring;
  137.   char *message;
  138.   char *message_ptr;
  139.   struct strbuf send_message;
  140.   char  dlsap[BUFSIZ];
  141.   int   dlsap_len;
  142.   int *message_int_ptr;
  143.   int message_offset;
  144.   int malloc_size;
  145.   
  146.   int len;
  147.   int nummessages;
  148.   int send_descriptor;
  149.   int bytes_remaining;
  150.   /* with links like fddi, one can send > 32 bits worth of bytes */
  151.   /* during a test... ;-) */
  152.   double bytes_sent;
  153.   
  154. #ifdef DIRTY
  155.   int i;
  156. #endif /* DIRTY */
  157.   
  158.   float local_cpu_utilization;
  159.   float local_service_demand;
  160.   float remote_cpu_utilization;
  161.   float remote_service_demand;
  162.   double thruput;
  163.   
  164.   struct dlpi_co_stream_request_struct *dlpi_co_stream_request;
  165.   struct dlpi_co_stream_response_struct *dlpi_co_stream_response;
  166.   struct dlpi_co_stream_results_struct *dlpi_co_stream_result;
  167.   
  168.   dlpi_co_stream_request = 
  169.     (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
  170.   dlpi_co_stream_response =
  171.     (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
  172.   dlpi_co_stream_result         = 
  173.     (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
  174.   
  175.   if ( print_headers ) {
  176.     fprintf(where,"DLPI CO STREAM TESTn");
  177.     if (local_cpu_usage || remote_cpu_usage)
  178.       fprintf(where,cpu_title,format_units());
  179.     else
  180.       fprintf(where,tput_title,format_units());
  181.   }
  182.   
  183.   /* initialize a few counters */
  184.   
  185.   nummessages = 0;
  186.   bytes_sent = 0.0;
  187.   times_up  =  0;
  188.   
  189.   /*set up the data descriptor                        */
  190.   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);  
  191.   if (send_descriptor < 0){
  192.     perror("netperf: send_dlpi_co_stream: dlpi stream data descriptor");
  193.     exit(1);
  194.   }
  195.   
  196.   /* bind the puppy and get the assigned dlsap */
  197.   dlsap_len = BUFSIZ;
  198.   if (dl_bind(send_descriptor, 
  199.               dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
  200.     fprintf(where,"send_dlpi_co_rr: bind failuren");
  201.     fflush(where);
  202.     exit(1);
  203.   }
  204.   
  205.   if (debug) {
  206.     fprintf(where,"send_dlpi_co_stream: send_descriptor obtained...n");
  207.   }
  208.   
  209. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  210.   if (lsw_size > 0) {
  211.     if (debug > 1) {
  212.       fprintf(where,"netperf: send_dlpi_co_stream: window send size altered from system default...n");
  213.       fprintf(where,"                          send: %dn",lsw_size);
  214.     }
  215.   }
  216.   if (lrw_size > 0) {
  217.     if (debug > 1) {
  218.       fprintf(where,
  219.       "netperf: send_dlpi_co_stream: window recv size altered from system default...n");
  220.       fprintf(where,"                          recv: %dn",lrw_size);
  221.     }
  222.   }
  223.   
  224.   
  225.   /* Now, we will find-out what the size actually became, and report */
  226.   /* that back to the user. If the call fails, we will just report a -1 */
  227.   /* back to the initiator for the recv buffer size. */
  228.   
  229.   
  230.   if (debug) {
  231.     fprintf(where,
  232.     "netperf: send_dlpi_co_stream: window sizes determined...n");
  233.     fprintf(where,"         send: %d recv: %dn",lsw_size,lrw_size);
  234.     ffluch(where);
  235.   }
  236.   
  237. #else /* DL_HP_SET_LOCAL_WIN_REQ */
  238.   
  239.   lsw_size = -1;
  240.   lrw_size = -1;
  241.   
  242. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  243.   
  244.   /* we should pick a default send_size, it should not be larger than */
  245.   /* the min of the two interface MTU's, and should perhaps default to */
  246.   /* the Interface MTU, but for now, we will default it to 1024... if */
  247.   /* someone wants to change this, the should change the corresponding */
  248.   /* lines in the recv_dlpi_co_stream routine */
  249.   
  250.   if (send_size == 0) {
  251.     send_size = 1024;
  252.   }
  253.   
  254.   /* set-up the data buffer with the requested alignment and offset. */
  255.   /* After we have calculated the proper starting address, we want to */
  256.   /* put that back into the message variable so we go back to the */
  257.   /* proper place. note that this means that only the first send is */
  258.   /* guaranteed to be at the alignment specified by the -a parameter. I */
  259.   /* think that this is a little more "real-world" than what was found */
  260.   /* in previous versions. note also that we have allocated a quantity */
  261.   /* of memory that is at least one send-size greater than our socket */
  262.   /* buffer size. We want to be sure that there are at least two */
  263.   /* buffers allocated - this can be a bit of a problem when the */
  264.   /* send_size is bigger than the socket size, so we must check... the */
  265.   /* user may have wanted to explicitly set the "width" of our send */
  266.   /* buffers, we should respect that wish... */
  267.   if (send_width == 0) {
  268.     send_width = (lsw_size/send_size) + 1;
  269.     if (send_width == 1) send_width++;
  270.   }
  271.   
  272.   send_ring = allocate_buffer_ring(send_width,
  273.    send_size,
  274.    local_send_align,
  275.    local_send_offset);
  276.   
  277.   send_message.maxlen = send_size;
  278.   send_message.len = send_size;
  279.   send_message.buf = send_ring->buffer_ptr;
  280.   
  281.   /* If the user has requested cpu utilization measurements, we must */
  282.   /* calibrate the cpu(s). We will perform this task within the tests */
  283.   /* themselves. If the user has specified the cpu rate, then */
  284.   /* calibrate_local_cpu will return rather quickly as it will have */
  285.   /* nothing to do. If local_cpu_rate is zero, then we will go through */
  286.   /* all the "normal" calibration stuff and return the rate back.*/
  287.   
  288.   if (local_cpu_usage) {
  289.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  290.   }
  291.   
  292.   /* Tell the remote end to do a listen. The server alters the socket */
  293.   /* paramters on the other side at this point, hence the reason for */
  294.   /* all the values being passed in the setup message. If the user did */
  295.   /* not specify any of the parameters, they will be passed as 0, which */
  296.   /* will indicate to the remote that no changes beyond the system's */
  297.   /* default should be used. */
  298.   
  299.   netperf_request.content.request_type  = DO_DLPI_CO_STREAM;
  300.   dlpi_co_stream_request->send_win_size = rsw_size;
  301.   dlpi_co_stream_request->recv_win_size = rrw_size;
  302.   dlpi_co_stream_request->receive_size  = recv_size;
  303.   dlpi_co_stream_request->recv_alignment= remote_recv_align;
  304.   dlpi_co_stream_request->recv_offset  = remote_recv_offset;
  305.   dlpi_co_stream_request->measure_cpu  = remote_cpu_usage;
  306.   dlpi_co_stream_request->cpu_rate  = remote_cpu_rate;
  307.   dlpi_co_stream_request->ppa           =      rem_ppa;
  308.   dlpi_co_stream_request->sap           =      dlpi_sap;
  309.   dlpi_co_stream_request->dev_name_len  =      strlen(rem_dlpi_device);
  310.   strcpy(dlpi_co_stream_request->dlpi_device,
  311.  rem_dlpi_device);
  312.   
  313. #ifdef __alpha
  314.   
  315.   /* ok - even on a DEC box, strings are strings. I didn't really want */
  316.   /* to ntohl the words of a string. since I don't want to teach the */
  317.   /* send_ and recv_ _request and _response routines about the types, */
  318.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  319.   /* solution would be to use XDR, but I am still leary of being able */
  320.   /* to find XDR libs on all platforms I want running netperf. raj */
  321.   {
  322.     int *charword;
  323.     int *initword;
  324.     int *lastword;
  325.     
  326.     initword = (int *) dlpi_co_stream_request->dlpi_device;
  327.     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
  328.     
  329.     for (charword = initword;
  330.  charword < lastword;
  331.  charword++) {
  332.       
  333.       *charword = ntohl(*charword);
  334.     }
  335.   }
  336. #endif /* __alpha */
  337.   
  338.   if (test_time) {
  339.     dlpi_co_stream_request->test_length = test_time;
  340.   }
  341.   else {
  342.     dlpi_co_stream_request->test_length = test_bytes;
  343.   }
  344. #ifdef DIRTY
  345.   dlpi_co_stream_request->dirty_count       =       rem_dirty_count;
  346.   dlpi_co_stream_request->clean_count       =       rem_clean_count;
  347. #endif /* DIRTY */
  348.   
  349.   
  350.   if (debug > 1) {
  351.     fprintf(where,
  352.     "netperf: send_dlpi_co_stream: requesting DLPI CO stream testn");
  353.   }
  354.   
  355.   send_request();
  356.   
  357.   /* The response from the remote will contain all of the relevant  */
  358.   /* parameters for this test type. We will put them back into  */
  359.   /* the variables here so they can be displayed if desired.  The */
  360.   /* remote will have calibrated CPU if necessary, and will have done */
  361.   /* all the needed set-up we will have calibrated the cpu locally */
  362.   /* before sending the request, and will grab the counter value right */
  363.   /* after the connect returns. The remote will grab the counter right */
  364.   /* after the accept call. This saves the hassle of extra messages */
  365.   /* being sent for the TCP tests. */
  366.   
  367.   recv_response();
  368.   
  369.   if (!netperf_response.content.serv_errno) {
  370.     if (debug)
  371.       fprintf(where,"remote listen done.n");
  372.     rrw_size = dlpi_co_stream_response->recv_win_size;
  373.     rsw_size = dlpi_co_stream_response->send_win_size;
  374.     remote_cpu_usage= dlpi_co_stream_response->measure_cpu;
  375.     remote_cpu_rate =  dlpi_co_stream_response->cpu_rate;
  376.   }
  377.   else {
  378.     Set_errno(netperf_response.content.serv_errno);
  379.     perror("netperf: remote error");
  380.     exit(1);
  381.   }
  382.   
  383.   /* Connect up to the remote port on the data descriptor */
  384.   if(dl_connect(send_descriptor,
  385. dlpi_co_stream_response->station_addr,
  386. dlpi_co_stream_response->station_addr_len) != 0) {
  387.     fprintf(where,"recv_dlpi_co_stream: connect failuren");
  388.     fflush(where);
  389.     exit(1);
  390.   }
  391.   
  392.   /* Data Socket set-up is finished. If there were problems, either the */
  393.   /* connect would have failed, or the previous response would have */
  394.   /* indicated a problem. I failed to see the value of the extra */
  395.   /* message after the accept on the remote. If it failed, we'll see it */
  396.   /* here. If it didn't, we might as well start pumping data. */
  397.   
  398.   /* Set-up the test end conditions. For a stream test, they can be */
  399.   /* either time or byte-count based. */
  400.   
  401.   if (test_time) {
  402.     /* The user wanted to end the test after a period of time. */
  403.     times_up = 0;
  404.     bytes_remaining = 0;
  405.     start_timer(test_time);
  406.   }
  407.   else {
  408.     /* The tester wanted to send a number of bytes. */
  409.     bytes_remaining = test_bytes;
  410.     times_up = 1;
  411.   }
  412.   
  413.   /* The cpu_start routine will grab the current time and possibly */
  414.   /* value of the idle counter for later use in measuring cpu */
  415.   /* utilization and/or service demand and thruput. */
  416.   
  417.   cpu_start(local_cpu_usage);
  418.   
  419.   /* We use an "OR" to control test execution. When the test is */
  420.   /* controlled by time, the byte count check will always return false. */
  421.   /* When the test is controlled by byte count, the time test will */
  422.   /* always return false. When the test is finished, the whole */
  423.   /* expression will go false and we will stop sending data. */
  424.   
  425. #ifdef DIRTY
  426.   /* initialize the random number generator for putting dirty stuff */
  427.   /* into the send buffer. raj */
  428.   srand((int) getpid());
  429. #endif /* DIRTY */
  430.   
  431.   while ((!times_up) || (bytes_remaining > 0)) {
  432.     
  433. #ifdef DIRTY
  434.     /* we want to dirty some number of consecutive integers in the buffer */
  435.     /* we are about to send. we may also want to bring some number of */
  436.     /* them cleanly into the cache. The clean ones will follow any dirty */
  437.     /* ones into the cache. */
  438.     message_int_ptr = (int *)message_ptr;
  439.     for (i = 0; i < loc_dirty_count; i++) {
  440.       *message_int_ptr = rand();
  441.       message_int_ptr++;
  442.     }
  443.     for (i = 0; i < loc_clean_count; i++) {
  444.       loc_dirty_count = *message_int_ptr;
  445.       message_int_ptr++;
  446.     }
  447. #endif /* DIRTY */
  448.     
  449.     if((putmsg(send_descriptor,
  450.        0,
  451.        &send_message,
  452.        0)) != 0) {
  453.       if (errno == EINTR)
  454. break;
  455.       perror("netperf: data send error");
  456.       exit(1);
  457.     }
  458.     send_ring = send_ring->next;
  459.     send_message.buf = send_ring->buffer_ptr;
  460. #ifdef WANT_INTERVALS
  461.     for (interval_count = 0;
  462.  interval_count < interval_wate;
  463.  interval_count++);
  464. #endif /* WANT_INTERVALS */
  465.     
  466.     if (debug > 4) {
  467.       fprintf(where,"netperf: send_clpi_co_stream: putmsg called ");
  468.       fprintf(where,"len is %dn",send_message.len);
  469.       fflush(where);
  470.     }
  471.     
  472.     nummessages++;          
  473.     if (bytes_remaining) {
  474.       bytes_remaining -= send_size;
  475.     }
  476.   }
  477.   
  478.   /* The test is over. Flush the buffers to the remote end. We do a */
  479.   /* graceful release to insure that all data has been taken by the */
  480.   /* remote. this needs a little work - there is no three-way */
  481.   /* handshake with type two as there is with TCP, so there really */
  482.   /* should be a message exchange here. however, we will finesse it by */
  483.   /* saying that the tests shoudl run for a while. */ 
  484.   
  485.   if (debug) {
  486.     fprintf(where,"sending test end signal n");
  487.     fflush(where);
  488.   }
  489.   
  490.   send_message.len = (send_size - 1);
  491.   if (send_message.len == 0) send_message.len = 2;
  492.   
  493.   if((putmsg(send_descriptor,
  494.      0,
  495.      &send_message,
  496.      0)) != 0) {
  497.     perror("netperf: data send error");
  498.     exit(1);
  499.   }
  500.   
  501.   /* this call will always give us the elapsed time for the test, and */
  502.   /* will also store-away the necessaries for cpu utilization */
  503.   
  504.   cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
  505.   /* how long did we really run? */
  506.   
  507.   /* Get the statistics from the remote end. The remote will have */
  508.   /* calculated service demand and all those interesting things. If it */
  509.   /* wasn't supposed to care, it will return obvious values. */
  510.   
  511.   recv_response();
  512.   if (!netperf_response.content.serv_errno) {
  513.     if (debug)
  514.       fprintf(where,"remote results obtainedn");
  515.   }
  516.   else {
  517.     Set_errno(netperf_response.content.serv_errno);
  518.     perror("netperf: remote error");
  519.     
  520.     exit(1);
  521.   }
  522.   
  523.   /* We now calculate what our thruput was for the test. In the future, */
  524.   /* we may want to include a calculation of the thruput measured by */
  525.   /* the remote, but it should be the case that for a TCP stream test, */
  526.   /* that the two numbers should be *very* close... We calculate */
  527.   /* bytes_sent regardless of the way the test length was controlled. */
  528.   /* If it was time, we needed to, and if it was by bytes, the user may */
  529.   /* have specified a number of bytes that wasn't a multiple of the */
  530.   /* send_size, so we really didn't send what he asked for ;-) */
  531.   
  532.   bytes_sent = ((double) send_size * (double) nummessages) + (double) len;
  533.   thruput = calc_thruput(bytes_sent);
  534.   
  535.   if (local_cpu_usage || remote_cpu_usage) {
  536.     /* We must now do a little math for service demand and cpu */
  537.     /* utilization for the system(s) */
  538.     /* Of course, some of the information might be bogus because */
  539.     /* there was no idle counter in the kernel(s). We need to make */
  540.     /* a note of this for the user's benefit...*/
  541.     if (local_cpu_usage) {
  542.       if (local_cpu_rate == 0.0) {
  543. fprintf(where,
  544. "WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!n");
  545. fprintf(where,
  546. "Local CPU usage numbers based on process information only!n");
  547. fflush(where);
  548.       }
  549.       local_cpu_utilization = calc_cpu_util(0.0);
  550.       local_service_demand = calc_service_demand(bytes_sent,
  551.       0.0,
  552.       0.0,
  553.       0);
  554.     }
  555.     else {
  556.       local_cpu_utilization = -1.0;
  557.       local_service_demand = -1.0;
  558.     }
  559.     
  560.     if (remote_cpu_usage) {
  561.       if (remote_cpu_rate == 0.0) {
  562. fprintf(where,
  563. "DANGER   DANGER  DANGER   DANGER   DANGER  DANGER   DANGER!n");
  564. fprintf(where,
  565. "Remote CPU usage numbers based on process information only!n");
  566. fflush(where);
  567.       }
  568.       remote_cpu_utilization = dlpi_co_stream_result->cpu_util;
  569.       remote_service_demand = calc_service_demand(bytes_sent,
  570.       0.0,
  571.       remote_cpu_utilization,
  572.       dlpi_co_stream_result->num_cpus);
  573.     }
  574.     else {
  575.       remote_cpu_utilization = -1.0;
  576.       remote_service_demand  = -1.0;
  577.     }
  578.     
  579.     /* We are now ready to print all the information. If the user */
  580.     /* has specified zero-level verbosity, we will just print the */
  581.     /* local service demand, or the remote service demand. If the */
  582.     /* user has requested verbosity level 1, he will get the basic */
  583.     /* "streamperf" numbers. If the user has specified a verbosity */
  584.     /* of greater than 1, we will display a veritable plethora of */
  585.     /* background information from outside of this block as it it */
  586.     /* not cpu_measurement specific...  */
  587.     
  588.     switch (verbosity) {
  589.     case 0:
  590.       if (local_cpu_usage) {
  591. fprintf(where,
  592. cpu_fmt_0,
  593. local_service_demand);
  594.       }
  595.       else {
  596. fprintf(where,
  597. cpu_fmt_0,
  598. remote_service_demand);
  599.       }
  600.       break;
  601.     case 1:
  602.     case 2:
  603.       fprintf(where,
  604.       cpu_fmt_1, /* the format string */
  605.       rrw_size, /* remote recvbuf size */
  606.       lsw_size, /* local sendbuf size */
  607.       send_size, /* how large were the sends */
  608.       elapsed_time, /* how long was the test */
  609.       thruput,  /* what was the xfer rate */
  610.       local_cpu_utilization, /* local cpu */
  611.       remote_cpu_utilization, /* remote cpu */
  612.       local_service_demand, /* local service demand */
  613.       remote_service_demand); /* remote service demand */
  614.       break;
  615.     }
  616.   }
  617.   else {
  618.     /* The tester did not wish to measure service demand. */
  619.     switch (verbosity) {
  620.     case 0:
  621.       fprintf(where,
  622.       tput_fmt_0,
  623.       thruput);
  624.       break;
  625.     case 1:
  626.     case 2:
  627.       fprintf(where,
  628.       tput_fmt_1, /* the format string */
  629.       rrw_size,  /* remote recvbuf size */
  630.       lsw_size,  /* local sendbuf size */
  631.       send_size, /* how large were the sends */
  632.       elapsed_time,  /* how long did it take */
  633.       thruput);/* how fast did it go */
  634.       break;
  635.     }
  636.   }
  637.   
  638.   /* it would be a good thing to include information about some of the */
  639.   /* other parameters that may have been set for this test, but at the */
  640.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  641.   /* just put this comment here to help remind me that it is something */
  642.   /* that should be done at a later time. */
  643.   
  644.   if (verbosity > 1) {
  645.     /* The user wanted to know it all, so we will give it to him. */
  646.     /* This information will include as much as we can find about */
  647.     /* TCP statistics, the alignments of the sends and receives */
  648.     /* and all that sort of rot... */
  649.     
  650.     fprintf(where,
  651.     ksink_fmt,
  652.     "Bytes",
  653.     "Bytes",
  654.     "Bytes",
  655.     local_send_align,
  656.     remote_recv_align,
  657.     local_send_offset,
  658.     remote_recv_offset,
  659.     bytes_sent,
  660.     bytes_sent / (double)nummessages,
  661.     nummessages,
  662.     bytes_sent / (double)dlpi_co_stream_result->recv_calls,
  663.     dlpi_co_stream_result->recv_calls);
  664.   }
  665.   
  666. }
  667. /* This is the server-side routine for the tcp stream test. It is */
  668. /* implemented as one routine. I could break things-out somewhat, but */
  669. /* didn't feel it was necessary. */
  670. int 
  671.   recv_dlpi_co_stream()
  672. {
  673.   
  674.   int data_descriptor;
  675.   int flags = 0;
  676.   int measure_cpu;
  677.   int bytes_received;
  678.   int receive_calls;
  679.   float elapsed_time;
  680.   
  681.   struct ring_elt *recv_ring;
  682.   char *message_ptr;
  683.   char *message;
  684.   int   *message_int_ptr;
  685.   struct strbuf recv_message;
  686.   int   dirty_count;
  687.   int   clean_count;
  688.   int   i;
  689.   
  690.   struct dlpi_co_stream_request_struct *dlpi_co_stream_request;
  691.   struct dlpi_co_stream_response_struct *dlpi_co_stream_response;
  692.   struct dlpi_co_stream_results_struct *dlpi_co_stream_results;
  693.   
  694.   dlpi_co_stream_request = (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
  695.   dlpi_co_stream_response = (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
  696.   dlpi_co_stream_results = (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
  697.   
  698.   if (debug) {
  699.     fprintf(where,"netserver: recv_dlpi_co_stream: entered...n");
  700.     fflush(where);
  701.   }
  702.   
  703.   /* We want to set-up the listen socket with all the desired */
  704.   /* parameters and then let the initiator know that all is ready. If */
  705.   /* socket size defaults are to be used, then the initiator will have */
  706.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  707.   /* send-back what they are. If that information cannot be determined, */
  708.   /* then we send-back -1's for the sizes. If things go wrong for any */
  709.   /* reason, we will drop back ten yards and punt. */
  710.   
  711.   /* If anything goes wrong, we want the remote to know about it. It */
  712.   /* would be best if the error that the remote reports to the user is */
  713.   /* the actual error we encountered, rather than some bogus unexpected */
  714.   /* response type message. */
  715.   
  716.   netperf_response.content.response_type = DLPI_CO_STREAM_RESPONSE;
  717.   
  718.   /* We now alter the message_ptr variable to be at the desired */
  719.   /* alignment with the desired offset. */
  720.   
  721.   if (debug > 1) {
  722.     fprintf(where,"recv_dlpi_co_stream: requested alignment of %dn",
  723.     dlpi_co_stream_request->recv_alignment);
  724.     fflush(where);
  725.   }
  726.   
  727.   
  728.   /* Grab a descriptor to listen on, and then listen on it. */
  729.   
  730.   if (debug > 1) {
  731.     fprintf(where,"recv_dlpi_co_stream: grabbing a descriptor...n");
  732.     fflush(where);
  733.   }
  734.   
  735.   
  736.   
  737. #ifdef __alpha
  738.   
  739.   /* ok - even on a DEC box, strings are strings. I din't really want */
  740.   /* to ntohl the words of a string. since I don't want to teach the */
  741.   /* send_ and recv_ _request and _response routines about the types, */
  742.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  743.   /* solution would be to use XDR, but I am still leary of being able */
  744.   /* to find XDR libs on all platforms I want running netperf. raj */
  745.   {
  746.     int *charword;
  747.     int *initword;
  748.     int *lastword;
  749.     
  750.     initword = (int *) dlpi_co_stream_request->dlpi_device;
  751.     lastword = initword + ((dlpi_co_stream_request->dev_name_len + 3) / 4);
  752.     
  753.     for (charword = initword;
  754.  charword < lastword;
  755.  charword++) {
  756.       
  757.       *charword = htonl(*charword);
  758.     }
  759.   }
  760. #endif /* __alpha */
  761.   
  762.   data_descriptor = dl_open(dlpi_co_stream_request->dlpi_device,
  763.     dlpi_co_stream_request->ppa);
  764.   if (data_descriptor < 0) {
  765.     netperf_response.content.serv_errno = errno;
  766.     send_response();
  767.     exit(1);
  768.   }
  769.   
  770.   /* Let's get an address assigned to this descriptor so we can tell the */
  771.   /* initiator how to reach the data descriptor. There may be a desire to */
  772.   /* nail this descriptor to a specific address in a multi-homed, */
  773.   /* multi-connection situation, but for now, we'll ignore the issue */
  774.   /* and concentrate on single connection testing. */
  775.   
  776.   /* bind the sap and retrieve the dlsap assigned by the system  */
  777.   dlpi_co_stream_response->station_addr_len = 14; /* arbitrary */
  778.   if (dl_bind(data_descriptor,
  779.       dlpi_co_stream_request->sap,
  780.       DL_CODLS,
  781.       (char *)dlpi_co_stream_response->station_addr,
  782.       &dlpi_co_stream_response->station_addr_len) != 0) {
  783.     fprintf(where,"recv_dlpi_co_stream: bind failuren");
  784.     fflush(where);
  785.     exit(1);
  786.   }
  787.   
  788.   /* The initiator may have wished-us to modify the socket buffer */
  789.   /* sizes. We should give it a shot. If he didn't ask us to change the */
  790.   /* sizes, we should let him know what sizes were in use at this end. */
  791.   /* If none of this code is compiled-in, then we will tell the */
  792.   /* initiator that we were unable to play with the socket buffer by */
  793.   /* setting the size in the response to -1. */
  794.   
  795. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  796.   
  797.   if (dlpi_co_stream_request->recv_win_size) {
  798.   }
  799.   /* Now, we will find-out what the size actually became, and report */
  800.   /* that back to the user. If the call fails, we will just report a -1 */
  801.   /* back to the initiator for the recv buffer size. */
  802.   
  803. #else /* the system won't let us play with the buffers */
  804.   
  805.   dlpi_co_stream_response->recv_win_size = -1;
  806.   
  807. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  808.   
  809.   /* what sort of sizes did we end-up with? */
  810.   /* this bit of code whould default to the Interface MTU */
  811.   if (dlpi_co_stream_request->receive_size == 0) {
  812.     recv_size = 1024;
  813.   }
  814.   else {
  815.     recv_size = dlpi_co_stream_request->receive_size;
  816.   }
  817.   
  818.   /* tell the other fellow what our receive size became */
  819.   dlpi_co_stream_response->receive_size = recv_size;
  820.   
  821.   /* just a little prep work for when we may have to behave like the */
  822.   /* sending side... */
  823.   message = (char *)malloc(recv_size * 2);
  824.   if (message == NULL) {
  825.     printf("malloc(%d) failed!n", recv_size * 2);
  826.     exit(1);
  827.   }
  828.   message_ptr = ALIGN_BUFFER(message, dlpi_co_stream_request->recv_alignment, dlpi_co_stream_request->recv_offset);
  829.   recv_message.maxlen = recv_size;
  830.   recv_message.len = 0;
  831.   recv_message.buf = message_ptr;
  832.   
  833.   if (debug > 1) {
  834.     fprintf(where,
  835.     "recv_dlpi_co_stream: receive alignment and offset set...n");
  836.     fflush(where);
  837.   }
  838.   
  839.   netperf_response.content.serv_errno   = 0;
  840.   
  841.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  842.   /* then we must call the calibrate routine, which will return the max */
  843.   /* rate back to the initiator. If the CPU was not to be measured, or */
  844.   /* something went wrong with the calibration, we will return a -1 to */
  845.   /* the initiator. */
  846.   
  847.   dlpi_co_stream_response->cpu_rate = 0.0;  /* assume no cpu */
  848.   if (dlpi_co_stream_request->measure_cpu) {
  849.     dlpi_co_stream_response->measure_cpu = 1;
  850.     dlpi_co_stream_response->cpu_rate = 
  851.       calibrate_local_cpu(dlpi_co_stream_request->cpu_rate);
  852.   }
  853.   
  854.   send_response();
  855.   
  856.   /* accept a connection on this file descriptor. at some point, */
  857.   /* dl_accept will "do the right thing" with the last two parms, but */
  858.   /* for now it ignores them, so we will pass zeros. */
  859.   
  860.   if(dl_accept(data_descriptor, 0, 0) != 0) {
  861.     fprintf(where,
  862.     "recv_dlpi_co_stream: error in accept, errno %dn",
  863.     errno);
  864.     fflush(where);
  865.     netperf_response.content.serv_errno = errno;
  866.     send_response();
  867.     exit(1);
  868.   }
  869.   
  870.   if (debug) {
  871.     fprintf(where,"netserver:recv_dlpi_co_stream: connection acceptedn");
  872.     fflush(where);
  873.   }
  874.   
  875.   /* Now it's time to start receiving data on the connection. We will */
  876.   /* first grab the apropriate counters and then start grabbing. */
  877.   
  878.   cpu_start(dlpi_co_stream_request->measure_cpu);
  879.   
  880. #ifdef DIRTY
  881.   /* we want to dirty some number of consecutive integers in the buffer */
  882.   /* we are about to recv. we may also want to bring some number of */
  883.   /* them cleanly into the cache. The clean ones will follow any dirty */
  884.   /* ones into the cache. */
  885.   
  886.   dirty_count = dlpi_co_stream_request->dirty_count;
  887.   clean_count = dlpi_co_stream_request->clean_count;
  888.   message_int_ptr = (int *)message_ptr;
  889.   for (i = 0; i < dirty_count; i++) {
  890.     *message_int_ptr = rand();
  891.     message_int_ptr++;
  892.   }
  893.   for (i = 0; i < clean_count; i++) {
  894.     dirty_count = *message_int_ptr;
  895.     message_int_ptr++;
  896.   }
  897. #endif /* DIRTY */
  898.   
  899.   recv_message.len = recv_size; 
  900.   while (recv_message.len == recv_size) {
  901.     if (getmsg(data_descriptor, 
  902.        0,
  903.        &recv_message, 
  904.        &flags) != 0) {
  905.       netperf_response.content.serv_errno = errno;
  906.       send_response();
  907.       exit(1);
  908.     }
  909.     bytes_received += recv_message.len;
  910.     receive_calls++;
  911.     
  912.     if (debug) {
  913.       fprintf(where,
  914.       "netserver:recv_dlpi_co_stream: getmsg accepted %d bytesn",
  915.       recv_message.len);
  916.       fflush(where);
  917.     }
  918.     
  919.     
  920. #ifdef DIRTY
  921.     message_int_ptr = (int *)message_ptr;
  922.     for (i = 0; i < dirty_count; i++) {
  923.       *message_int_ptr = rand();
  924.       message_int_ptr++;
  925.     }
  926.     for (i = 0; i < clean_count; i++) {
  927.       dirty_count = *message_int_ptr;
  928.       message_int_ptr++;
  929.     }
  930. #endif /* DIRTY */
  931.     
  932.   }
  933.   
  934.   /* The loop now exits due to zero bytes received. */
  935.   /* should perform a disconnect to signal the sender that */
  936.   /* we have received all the data sent. */
  937.   
  938.   if (close(data_descriptor) == -1) {
  939.     netperf_response.content.serv_errno = errno;
  940.     send_response();
  941.     exit(1);
  942.   }
  943.   
  944.   cpu_stop(dlpi_co_stream_request->measure_cpu,&elapsed_time);
  945.   
  946.   /* send the results to the sender */
  947.   
  948.   if (debug) {
  949.     fprintf(where,
  950.     "recv_dlpi_co_stream: got %d bytesn",
  951.     bytes_received);
  952.     fprintf(where,
  953.     "recv_dlpi_co_stream: got %d recvsn",
  954.     receive_calls);
  955.     fflush(where);
  956.   }
  957.   
  958.   dlpi_co_stream_results->bytes_received = bytes_received;
  959.   dlpi_co_stream_results->elapsed_time = elapsed_time;
  960.   dlpi_co_stream_results->recv_calls = receive_calls;
  961.   
  962.   if (dlpi_co_stream_request->measure_cpu) {
  963.     dlpi_co_stream_results->cpu_util = calc_cpu_util(0.0);
  964.   };
  965.   
  966.   if (debug > 1) {
  967.     fprintf(where,
  968.     "recv_dlpi_co_stream: test complete, sending results.n");
  969.     fflush(where);
  970.   }
  971.   
  972.   send_response();
  973. }
  974. /*********************************/
  975. int send_dlpi_co_rr(char remote_host[])
  976. {
  977.   
  978.   char *tput_title = "
  979.  Local /Remoten
  980.  Window Size   Request  Resp.   Elapsed  Trans.n
  981.  Send   Recv   Size     Size    Time     Rate         n
  982.  frames frames bytes    bytes   secs.    per sec   nn";
  983.   
  984.   char *tput_fmt_0 =
  985.     "%7.2fn";
  986.   
  987.   char *tput_fmt_1_line_1 = "
  988.  %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   n";
  989.   char *tput_fmt_1_line_2 = "
  990.  %-6d %-6dn";
  991.   
  992.   char *cpu_title = "
  993.  Local /Remoten
  994.  Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.demn
  995.  Send   Recv   Size    Size   Time    Rate     local  remote local   remoten
  996.  frames frames bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Trnn";
  997.   
  998.   char *cpu_fmt_0 =
  999.     "%6.3fn";
  1000.   
  1001.   char *cpu_fmt_1_line_1 = "
  1002.  %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3fn";
  1003.   
  1004.   char *cpu_fmt_1_line_2 = "
  1005.  %-6d %-6dn";
  1006.   
  1007.   char *ksink_fmt = "
  1008.  Alignment      Offsetn
  1009.  Local  Remote  Local  Remoten
  1010.  Send   Recv    Send   Recvn
  1011.  %5d  %5d   %5d  %5dn";
  1012.   
  1013.   
  1014.   int timed_out = 0;
  1015.   float elapsed_time;
  1016.   int     dlsap_len;
  1017.   char      dlsap[BUFSIZ];
  1018.   
  1019.   int   flags = 0;
  1020.   char *send_message_ptr;
  1021.   char *recv_message_ptr;
  1022.   char *temp_message_ptr;
  1023.   struct strbuf send_message;
  1024.   struct strbuf recv_message;
  1025.   
  1026.   int nummessages;
  1027.   int send_descriptor;
  1028.   int trans_remaining;
  1029.   double bytes_xferd;
  1030.   
  1031.   int rsp_bytes_left;
  1032.   
  1033.   /* we assume that station adresses fit within two ints */
  1034.   unsigned int   remote_address[1];
  1035.   
  1036.   float local_cpu_utilization;
  1037.   float local_service_demand;
  1038.   float remote_cpu_utilization;
  1039.   float remote_service_demand;
  1040.   double thruput;
  1041.   
  1042.   struct dlpi_co_rr_request_struct *dlpi_co_rr_request;
  1043.   struct dlpi_co_rr_response_struct *dlpi_co_rr_response;
  1044.   struct dlpi_co_rr_results_struct *dlpi_co_rr_result;
  1045.   
  1046.   dlpi_co_rr_request = 
  1047.     (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
  1048.   dlpi_co_rr_response = 
  1049.     (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
  1050.   dlpi_co_rr_result = 
  1051.     (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
  1052.   
  1053.   /* since we are now disconnected from the code that established the */
  1054.   /* control socket, and since we want to be able to use different */
  1055.   /* protocols and such, we are passed the name of the remote host and */
  1056.   /* must turn that into the test specific addressing information. */
  1057.   
  1058.   if ( print_headers ) {
  1059.     fprintf(where,"DLPI CO REQUEST/RESPONSE TESTn");
  1060.     if (local_cpu_usage || remote_cpu_usage)
  1061.       fprintf(where,cpu_title,format_units());
  1062.     else
  1063.       fprintf(where,tput_title,format_units());
  1064.   }
  1065.   
  1066.   /* initialize a few counters */
  1067.   
  1068.   nummessages = 0;
  1069.   bytes_xferd = 0.0;
  1070.   times_up  =  0;
  1071.   
  1072.   /* set-up the data buffers with the requested alignment and offset */
  1073.   temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
  1074.   if (temp_message_ptr == NULL) {
  1075.     printf("malloc(%d) failed!n", req_size+MAXALIGNMENT+MAXOFFSET);
  1076.     exit(1);
  1077.   }
  1078.   send_message_ptr = (char *)(( (long) temp_message_ptr + 
  1079.        (long) local_send_align - 1) &
  1080.       ~((long) local_send_align - 1));
  1081.   send_message_ptr = send_message_ptr + local_send_offset;
  1082.   send_message.maxlen = req_size+MAXALIGNMENT+MAXOFFSET;
  1083.   send_message.len    = req_size;
  1084.   send_message.buf    = send_message_ptr;
  1085.   
  1086.   temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
  1087.   if (temp_message_ptr == NULL) {
  1088.     printf("malloc(%d) failed!n", rsp_size+MAXALIGNMENT+MAXOFFSET);
  1089.     exit(1);
  1090.   }
  1091.   recv_message_ptr = (char *)(( (long) temp_message_ptr + 
  1092.        (long) local_recv_align - 1) &
  1093.       ~((long) local_recv_align - 1));
  1094.   recv_message_ptr = recv_message_ptr + local_recv_offset;
  1095.   recv_message.maxlen = rsp_size+MAXALIGNMENT+MAXOFFSET;
  1096.   recv_message.len    = 0;
  1097.   recv_message.buf    = send_message_ptr;
  1098.   
  1099.   /*set up the data socket                        */
  1100.   
  1101.   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
  1102.   if (send_descriptor < 0){
  1103.     perror("netperf: send_dlpi_co_rr: tcp stream data descriptor");
  1104.     exit(1);
  1105.   }
  1106.   
  1107.   if (debug) {
  1108.     fprintf(where,"send_dlpi_co_rr: send_descriptor obtained...n");
  1109.   }
  1110.   
  1111.   /* bind the puppy and get the assigned dlsap */
  1112.   
  1113.   dlsap_len = BUFSIZ;
  1114.   if (dl_bind(send_descriptor, 
  1115.       dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
  1116.     fprintf(where,"send_dlpi_co_rr: bind failuren");
  1117.     fflush(where);
  1118.     exit(1);
  1119.   }
  1120.   
  1121.   /* Modify the local socket size. The reason we alter the send buffer */
  1122.   /* size here rather than when the connection is made is to take care */
  1123.   /* of decreases in buffer size. Decreasing the window size after */
  1124.   /* connection establishment is a TCP no-no. Also, by setting the */
  1125.   /* buffer (window) size before the connection is established, we can */
  1126.   /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
  1127.   /* the minimum receive buffer size at each half of the connection. */
  1128.   /* This is why we are altering the receive buffer size on the sending */
  1129.   /* size of a unidirectional transfer. If the user has not requested */
  1130.   /* that the socket buffers be altered, we will try to find-out what */
  1131.   /* their values are. If we cannot touch the socket buffer in any way, */
  1132.   /* we will set the values to -1 to indicate that.  */
  1133.   
  1134. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  1135.   if (lsw_size > 0) {
  1136.     if (debug > 1) {
  1137.       fprintf(where,"netperf: send_dlpi_co_rr: socket send size altered from system default...n");
  1138.       fprintf(where,"                          send: %dn",lsw_size);
  1139.     }
  1140.   }
  1141.   if (lrw_size > 0) {
  1142.     if (debug > 1) {
  1143.       fprintf(where,"netperf: send_dlpi_co_rr: socket recv size altered from system default...n");
  1144.       fprintf(where,"                          recv: %dn",lrw_size);
  1145.     }
  1146.   }
  1147.   
  1148.   
  1149.   /* Now, we will find-out what the size actually became, and report */
  1150.   /* that back to the user. If the call fails, we will just report a -1 */
  1151.   /* back to the initiator for the recv buffer size. */
  1152.   
  1153.   
  1154.   if (debug) {
  1155.     fprintf(where,"netperf: send_dlpi_co_rr: socket sizes determined...n");
  1156.     fprintf(where,"         send: %d recv: %dn",lsw_size,lrw_size);
  1157.   }
  1158.   
  1159. #else /* DL_HP_SET_LOCAL_WIN_REQ */
  1160.   
  1161.   lsw_size = -1;
  1162.   lrw_size = -1;
  1163.   
  1164. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  1165.   
  1166.   /* If the user has requested cpu utilization measurements, we must */
  1167.   /* calibrate the cpu(s). We will perform this task within the tests */
  1168.   /* themselves. If the user has specified the cpu rate, then */
  1169.   /* calibrate_local_cpu will return rather quickly as it will have */
  1170.   /* nothing to do. If local_cpu_rate is zero, then we will go through */
  1171.   /* all the "normal" calibration stuff and return the rate back.*/
  1172.   
  1173.   if (local_cpu_usage) {
  1174.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  1175.   }
  1176.   
  1177.   /* Tell the remote end to do a listen. The server alters the socket */
  1178.   /* paramters on the other side at this point, hence the reason for */
  1179.   /* all the values being passed in the setup message. If the user did */
  1180.   /* not specify any of the parameters, they will be passed as 0, which */
  1181.   /* will indicate to the remote that no changes beyond the system's */
  1182.   /* default should be used. Alignment is the exception, it will */
  1183.   /* default to 8, which will be no alignment alterations. */
  1184.   
  1185.   netperf_request.content.request_type         = DO_DLPI_CO_RR;
  1186.   dlpi_co_rr_request->recv_win_size = rrw_size;
  1187.   dlpi_co_rr_request->send_win_size = rsw_size;
  1188.   dlpi_co_rr_request->recv_alignment = remote_recv_align;
  1189.   dlpi_co_rr_request->recv_offset = remote_recv_offset;
  1190.   dlpi_co_rr_request->send_alignment = remote_send_align;
  1191.   dlpi_co_rr_request->send_offset = remote_send_offset;
  1192.   dlpi_co_rr_request->request_size = req_size;
  1193.   dlpi_co_rr_request->response_size = rsp_size;
  1194.   dlpi_co_rr_request->measure_cpu = remote_cpu_usage;
  1195.   dlpi_co_rr_request->cpu_rate         = remote_cpu_rate;
  1196.   dlpi_co_rr_request->ppa               =       rem_ppa;
  1197.   dlpi_co_rr_request->sap               =       dlpi_sap;
  1198.   dlpi_co_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
  1199.   strcpy(dlpi_co_rr_request->dlpi_device,
  1200.  rem_dlpi_device);
  1201. #ifdef __alpha
  1202.   
  1203.   /* ok - even on a DEC box, strings are strings. I din't really want */
  1204.   /* to ntohl the words of a string. since I don't want to teach the */
  1205.   /* send_ and recv_ _request and _response routines about the types, */
  1206.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  1207.   /* solution would be to use XDR, but I am still leary of being able */
  1208.   /* to find XDR libs on all platforms I want running netperf. raj */
  1209.   {
  1210.     int *charword;
  1211.     int *initword;
  1212.     int *lastword;
  1213.     
  1214.     initword = (int *) dlpi_co_rr_request->dlpi_device;
  1215.     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
  1216.     
  1217.     for (charword = initword;
  1218.  charword < lastword;
  1219.  charword++) {
  1220.       
  1221.       *charword = ntohl(*charword);
  1222.     }
  1223.   }
  1224. #endif /* __alpha */
  1225.   
  1226.   if (test_time) {
  1227.     dlpi_co_rr_request->test_length = test_time;
  1228.   }
  1229.   else {
  1230.     dlpi_co_rr_request->test_length = test_trans * -1;
  1231.   }
  1232.   
  1233.   if (debug > 1) {
  1234.     fprintf(where,"netperf: send_dlpi_co_rr: requesting TCP stream testn");
  1235.   }
  1236.   
  1237.   send_request();
  1238.   
  1239.   /* The response from the remote will contain all of the relevant  */
  1240.   /* socket parameters for this test type. We will put them back into  */
  1241.   /* the variables here so they can be displayed if desired.  The */
  1242.   /* remote will have calibrated CPU if necessary, and will have done */
  1243.   /* all the needed set-up we will have calibrated the cpu locally */
  1244.   /* before sending the request, and will grab the counter value right */
  1245.   /* after the connect returns. The remote will grab the counter right */
  1246.   /* after the accept call. This saves the hassle of extra messages */
  1247.   /* being sent for the TCP tests. */
  1248.   
  1249.   recv_response();
  1250.   
  1251.   if (!netperf_response.content.serv_errno) {
  1252.     if (debug)
  1253.       fprintf(where,"remote listen done.n");
  1254.     rrw_size = dlpi_co_rr_response->recv_win_size;
  1255.     rsw_size = dlpi_co_rr_response->send_win_size;
  1256.     remote_cpu_usage= dlpi_co_rr_response->measure_cpu;
  1257.     remote_cpu_rate =  dlpi_co_rr_response->cpu_rate;
  1258.     
  1259.   }
  1260.   else {
  1261.     Set_errno(netperf_response.content.serv_errno);
  1262.     perror("netperf: remote error");
  1263.     
  1264.     exit(1);
  1265.   }
  1266.   
  1267.   /*Connect up to the remote port on the data descriptor  */
  1268.   
  1269.   if(dl_connect(send_descriptor,
  1270. dlpi_co_rr_response->station_addr,
  1271. dlpi_co_rr_response->station_addr_len) != 0) {
  1272.     fprintf(where,"send_dlpi_co_rr: connect failuren");
  1273.     fflush(where);
  1274.     exit(1);
  1275.   }
  1276.   
  1277.   /* Data Socket set-up is finished. If there were problems, either the */
  1278.   /* connect would have failed, or the previous response would have */
  1279.   /* indicated a problem. I failed to see the value of the extra */
  1280.   /* message after the accept on the remote. If it failed, we'll see it */
  1281.   /* here. If it didn't, we might as well start pumping data. */
  1282.   
  1283.   /* Set-up the test end conditions. For a request/response test, they */
  1284.   /* can be either time or transaction based. */
  1285.   
  1286.   if (test_time) {
  1287.     /* The user wanted to end the test after a period of time. */
  1288.     times_up = 0;
  1289.     trans_remaining = 0;
  1290.     start_timer(test_time);
  1291.   }
  1292.   else {
  1293.     /* The tester wanted to send a number of bytes. */
  1294.     trans_remaining = test_bytes;
  1295.     times_up = 1;
  1296.   }
  1297.   
  1298.   /* The cpu_start routine will grab the current time and possibly */
  1299.   /* value of the idle counter for later use in measuring cpu */
  1300.   /* utilization and/or service demand and thruput. */
  1301.   
  1302.   cpu_start(local_cpu_usage);
  1303.   
  1304.   /* We use an "OR" to control test execution. When the test is */
  1305.   /* controlled by time, the byte count check will always return false. */
  1306.   /* When the test is controlled by byte count, the time test will */
  1307.   /* always return false. When the test is finished, the whole */
  1308.   /* expression will go false and we will stop sending data. I think I */
  1309.   /* just arbitrarily decrement trans_remaining for the timed test, but */
  1310.   /* will not do that just yet... One other question is whether or not */
  1311.   /* the send buffer and the receive buffer should be the same buffer. */
  1312.   
  1313.   while ((!times_up) || (trans_remaining > 0)) {
  1314.     /* send the request */
  1315.     if((putmsg(send_descriptor,
  1316.        0,
  1317.        &send_message,
  1318.        0)) != 0) {
  1319.       if (errno == EINTR) {
  1320. /* we hit the end of a */
  1321. /* timed test. */
  1322. timed_out = 1;
  1323. break;
  1324.       }
  1325.       perror("send_dlpi_co_rr: putmsg error");
  1326.       exit(1);
  1327.     }
  1328.     
  1329.     if (debug) {
  1330.       fprintf(where,"recv_message.len %dn",recv_message.len);
  1331.       fprintf(where,"send_message.len %dn",send_message.len);
  1332.       fflush(where);
  1333.     }
  1334.     
  1335.     /* receive the response */
  1336.     /* this needs some work with streams buffers if we are going to */
  1337.     /* support requests and responses larger than the MTU of the */
  1338.     /* network, but this can wait until later */
  1339.     rsp_bytes_left = rsp_size;
  1340.     recv_message.len = rsp_size;
  1341.     while(rsp_bytes_left > 0) {
  1342.       if((getmsg(send_descriptor,
  1343.  0,
  1344.  &recv_message,
  1345.  &flags)) < 0) {
  1346. if (errno == EINTR) {
  1347.   /* We hit the end of a timed test. */
  1348.   timed_out = 1;
  1349.   break;
  1350. }
  1351. perror("send_dlpi_co_rr: data recv error");
  1352. exit(1);
  1353.       }
  1354.       rsp_bytes_left -= recv_message.len;
  1355.     }
  1356.     
  1357.     if (timed_out) {
  1358.       /* we may have been in a nested while loop - we need */
  1359.       /* another call to break. */
  1360.       break;
  1361.     }
  1362.     
  1363.     nummessages++;          
  1364.     if (trans_remaining) {
  1365.       trans_remaining--;
  1366.     }
  1367.     
  1368.     if (debug > 3) {
  1369.       fprintf(where,
  1370.       "Transaction %d completedn",
  1371.       nummessages);
  1372.       fflush(where);
  1373.     }
  1374.   }
  1375.   
  1376.   /* At this point we used to call shutdown onthe data socket to be */
  1377.   /* sure all the data was delivered, but this was not germane in a */
  1378.   /* request/response test, and it was causing the tests to "hang" when */
  1379.   /* they were being controlled by time. So, I have replaced this */
  1380.   /* shutdown call with a call to close that can be found later in the */
  1381.   /* procedure. */
  1382.   
  1383.   /* this call will always give us the elapsed time for the test, and */
  1384.   /* will also store-away the necessaries for cpu utilization */
  1385.   
  1386.   cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
  1387.   /* how long did we really run? */
  1388.   
  1389.   /* Get the statistics from the remote end. The remote will have */
  1390.   /* calculated service demand and all those interesting things. If it */
  1391.   /* wasn't supposed to care, it will return obvious values. */
  1392.   
  1393.   recv_response();
  1394.   if (!netperf_response.content.serv_errno) {
  1395.     if (debug)
  1396.       fprintf(where,"remote results obtainedn");
  1397.   }
  1398.   else {
  1399.     Set_errno(netperf_response.content.serv_errno);
  1400.     perror("netperf: remote error");
  1401.     
  1402.     exit(1);
  1403.   }
  1404.   
  1405.   /* We now calculate what our thruput was for the test. In the future, */
  1406.   /* we may want to include a calculation of the thruput measured by */
  1407.   /* the remote, but it should be the case that for a TCP stream test, */
  1408.   /* that the two numbers should be *very* close... We calculate */
  1409.   /* bytes_sent regardless of the way the test length was controlled. */
  1410.   /* If it was time, we needed to, and if it was by bytes, the user may */
  1411.   /* have specified a number of bytes that wasn't a multiple of the */
  1412.   /* send_size, so we really didn't send what he asked for ;-) We use */
  1413.   /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
  1414.   /* 1024. A future enhancement *might* be to choose from a couple of */
  1415.   /* unit selections. */ 
  1416.   
  1417.   bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
  1418.   thruput = calc_thruput(bytes_xferd);
  1419.   
  1420.   if (local_cpu_usage || remote_cpu_usage) {
  1421.     /* We must now do a little math for service demand and cpu */
  1422.     /* utilization for the system(s) */
  1423.     /* Of course, some of the information might be bogus because */
  1424.     /* there was no idle counter in the kernel(s). We need to make */
  1425.     /* a note of this for the user's benefit...*/
  1426.     if (local_cpu_usage) {
  1427.       if (local_cpu_rate == 0.0) {
  1428. fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!n");
  1429. fprintf(where,"Local CPU usage numbers based on process information only!n");
  1430. fflush(where);
  1431.       }
  1432.       local_cpu_utilization = calc_cpu_util(0.0);
  1433.       /* since calc_service demand is doing ms/Kunit we will */
  1434.       /* multiply the number of transaction by 1024 to get */
  1435.       /* "good" numbers */
  1436.       local_service_demand  = calc_service_demand((double) nummessages*1024,
  1437.   0.0,
  1438.   0.0,
  1439.   0);
  1440.     }
  1441.     else {
  1442.       local_cpu_utilization = -1.0;
  1443.       local_service_demand = -1.0;
  1444.     }
  1445.     
  1446.     if (remote_cpu_usage) {
  1447.       if (remote_cpu_rate == 0.0) {
  1448. fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!n");
  1449. fprintf(where,"Remote CPU usage numbers based on process information only!n");
  1450. fflush(where);
  1451.       }
  1452.       remote_cpu_utilization = dlpi_co_rr_result->cpu_util;
  1453.       /* since calc_service demand is doing ms/Kunit we will */
  1454.       /* multiply the number of transaction by 1024 to get */
  1455.       /* "good" numbers */
  1456.       remote_service_demand = calc_service_demand((double) nummessages*1024,
  1457.   0.0,
  1458.   remote_cpu_utilization,
  1459.   dlpi_co_rr_result->num_cpus);
  1460.     }
  1461.     else {
  1462.       remote_cpu_utilization = -1.0;
  1463.       remote_service_demand  = -1.0;
  1464.     }
  1465.     
  1466.     /* We are now ready to print all the information. If the user */
  1467.     /* has specified zero-level verbosity, we will just print the */
  1468.     /* local service demand, or the remote service demand. If the */
  1469.     /* user has requested verbosity level 1, he will get the basic */
  1470.     /* "streamperf" numbers. If the user has specified a verbosity */
  1471.     /* of greater than 1, we will display a veritable plethora of */
  1472.     /* background information from outside of this block as it it */
  1473.     /* not cpu_measurement specific...  */
  1474.     
  1475.     switch (verbosity) {
  1476.     case 0:
  1477.       if (local_cpu_usage) {
  1478. fprintf(where,
  1479. cpu_fmt_0,
  1480. local_service_demand);
  1481.       }
  1482.       else {
  1483. fprintf(where,
  1484. cpu_fmt_0,
  1485. remote_service_demand);
  1486.       }
  1487.       break;
  1488.     case 1:
  1489.       fprintf(where,
  1490.       cpu_fmt_1_line_1, /* the format string */
  1491.       lsw_size, /* local sendbuf size */
  1492.       lrw_size,
  1493.       req_size, /* how large were the requests */
  1494.       rsp_size, /* guess */
  1495.       elapsed_time, /* how long was the test */
  1496.       nummessages/elapsed_time,
  1497.       local_cpu_utilization, /* local cpu */
  1498.       remote_cpu_utilization, /* remote cpu */
  1499.       local_service_demand, /* local service demand */
  1500.       remote_service_demand); /* remote service demand */
  1501.       fprintf(where,
  1502.       cpu_fmt_1_line_2,
  1503.       rsw_size,
  1504.       rrw_size);
  1505.       break;
  1506.     }
  1507.   }
  1508.   else {
  1509.     /* The tester did not wish to measure service demand. */
  1510.     switch (verbosity) {
  1511.     case 0:
  1512.       fprintf(where,
  1513.       tput_fmt_0,
  1514.       nummessages/elapsed_time);
  1515.       break;
  1516.     case 1:
  1517.       fprintf(where,
  1518.       tput_fmt_1_line_1, /* the format string */
  1519.       lsw_size,
  1520.       lrw_size,
  1521.       req_size, /* how large were the requests */
  1522.       rsp_size, /* how large were the responses */
  1523.       elapsed_time,  /* how long did it take */
  1524.       nummessages/elapsed_time);
  1525.       fprintf(where,
  1526.       tput_fmt_1_line_2,
  1527.       rsw_size,  /* remote recvbuf size */
  1528.       rrw_size);
  1529.       
  1530.       break;
  1531.     }
  1532.   }
  1533.   
  1534.   /* it would be a good thing to include information about some of the */
  1535.   /* other parameters that may have been set for this test, but at the */
  1536.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  1537.   /* just put this comment here to help remind me that it is something */
  1538.   /* that should be done at a later time. */
  1539.   
  1540.   if (verbosity > 1) {
  1541.     /* The user wanted to know it all, so we will give it to him. */
  1542.     /* This information will include as much as we can find about */
  1543.     /* TCP statistics, the alignments of the sends and receives */
  1544.     /* and all that sort of rot... */
  1545.     
  1546.     fprintf(where,
  1547.     ksink_fmt);
  1548.   }
  1549.   /* The test is over. Kill the data descriptor */
  1550.   
  1551.   if (close(send_descriptor) == -1) {
  1552.     perror("send_dlpi_co_rr: cannot shutdown tcp stream descriptor");
  1553.   }
  1554.   
  1555. }
  1556. void
  1557.   send_dlpi_cl_stream(char remote_host[])
  1558. {
  1559.   /************************************************************************/
  1560.   /* */
  1561.   /*                UDP Unidirectional Send Test                    */
  1562.   /* */
  1563.   /************************************************************************/
  1564.   char *tput_title =
  1565.     "Window  Message  Elapsed      Messages                n
  1566. Size    Size     Time         Okay Errors   Throughputn
  1567. frames  bytes    secs            #      #   %s/secnn";
  1568.   
  1569.   char *tput_fmt_0 =
  1570.     "%7.2fn";
  1571.   
  1572.   char *tput_fmt_1 =
  1573.     "%5d   %5d    %-7.2f   %7d %6d    %7.2fn
  1574. %5d            %-7.2f   %7d           %7.2fnn";
  1575.   
  1576.   
  1577.   char *cpu_title =
  1578.     "Window  Message  Elapsed      Messages                   CPU     Servicen
  1579. Size    Size     Time         Okay Errors   Throughput   Util    Demandn
  1580. frames  bytes    secs            #      #   %s/sec   %%       us/KBnn";
  1581.   
  1582.   char *cpu_fmt_0 =
  1583.     "%6.2fn";
  1584.   
  1585.   char *cpu_fmt_1 =
  1586.     "%5d   %5d    %-7.2f   %7d %6d    %7.1f      %-6.2f  %-6.3fn
  1587. %5d            %-7.2f   %7d           %7.1f      %-6.2f  %-6.3fnn";
  1588.   
  1589.   int messages_recvd;
  1590.   float elapsed_time,
  1591.   local_cpu_utilization, 
  1592.   remote_cpu_utilization;
  1593.   
  1594.   float local_service_demand, remote_service_demand;
  1595.   double local_thruput, remote_thruput;
  1596.   double bytes_sent;
  1597.   double bytes_recvd;
  1598.   
  1599.   
  1600.   int *message_int_ptr;
  1601.   char *message_ptr;
  1602.   char *message;
  1603.   char  sctl_data[BUFSIZ];
  1604.   struct strbuf send_message;
  1605.   struct strbuf sctl_message;
  1606.   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
  1607.   
  1608.   char dlsap[BUFSIZ];
  1609.   int  dlsap_len;
  1610.   int message_offset;
  1611.   int message_max_offset;
  1612.   int failed_sends;
  1613.   int failed_cows;
  1614.   int  messages_sent;
  1615.   int  data_descriptor;
  1616.   
  1617.   
  1618. #ifdef WANT_INTERVALS
  1619.   int interval_count;
  1620. #endif /* WANT_INTERVALS */
  1621. #ifdef DIRTY
  1622.   int i;
  1623. #endif /* DIRTY */
  1624.   
  1625.   struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request;
  1626.   struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response;
  1627.   struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results;
  1628.   
  1629.   dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
  1630.   dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
  1631.   dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
  1632.   
  1633.   if ( print_headers ) {
  1634.     printf("DLPI CL UNIDIRECTIONAL SEND TESTn");
  1635.     if (local_cpu_usage || remote_cpu_usage)
  1636.       printf(cpu_title,format_units());
  1637.     else
  1638.       printf(tput_title,format_units());
  1639.   }
  1640.   
  1641.   failed_sends = 0;
  1642.   messages_sent = 0;
  1643.   times_up = 0;
  1644.   
  1645.   /*set up the data descriptor */
  1646.   
  1647.   data_descriptor = dl_open(loc_dlpi_device,loc_ppa);
  1648.   if (data_descriptor < 0){
  1649.     perror("send_dlpi_cl_stream: data descriptor");
  1650.     exit(1);
  1651.   }
  1652.   
  1653.   /* bind the puppy and get the assigned dlsap */
  1654.   dlsap_len = BUFSIZ;
  1655.   if (dl_bind(data_descriptor, 
  1656.               dlpi_sap, DL_CLDLS, dlsap, &dlsap_len) != 0) {
  1657.     fprintf(where,"send_dlpi_cl_stream: bind failuren");
  1658.     fflush(where);
  1659.     exit(1);
  1660.   }
  1661.   
  1662.   /* Modify the local socket size (SNDBUF size)    */
  1663.   
  1664. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  1665.   if (lsw_size > 0) {
  1666.     if (debug > 1) {
  1667.       fprintf(where,"netperf: send_dlpi_cl_stream: descriptor send size altered from system default...n");
  1668.       fprintf(where,"                          send: %dn",lsw_size);
  1669.     }
  1670.   }
  1671.   if (lrw_size > 0) {
  1672.     if (debug > 1) {
  1673.       fprintf(where,"netperf: send_dlpi_cl_stream: descriptor recv size altered from system default...n");
  1674.       fprintf(where,"                          recv: %dn",lrw_size);
  1675.     }
  1676.   }
  1677.   
  1678.   
  1679.   /* Now, we will find-out what the size actually became, and report */
  1680.   /* that back to the user. If the call fails, we will just report a -1 */
  1681.   /* back to the initiator for the recv buffer size. */
  1682.   
  1683. #else /* DL_HP_SET_LOCAL_WIN_REQ */
  1684.   
  1685.   lsw_size = -1;
  1686.   lrw_size = -1;
  1687.   
  1688. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  1689.   
  1690.   /* now, we want to see if we need to set the send_size */
  1691.   if (send_size == 0) {
  1692.     send_size = 1024;
  1693.   }
  1694.   
  1695.   
  1696.   /* set-up the data buffer with the requested alignment and offset, */
  1697.   /* most of the numbers here are just a hack to pick something nice */
  1698.   /* and big in an attempt to never try to send a buffer a second time */
  1699.   /* before it leaves the node...unless the user set the width */
  1700.   /* explicitly. */
  1701.   if (send_width == 0) send_width = 32;
  1702.   message = (char *)malloc(send_size * (send_width + 1) + local_send_align + local_send_offset);
  1703.   if (message == NULL) {
  1704.     printf("malloc(%d) failed!n", send_size * (send_width + 1) + local_send_align + local_send_offset);
  1705.     exit(1);
  1706.   }
  1707.   message_ptr = (char *)(( (long) message + 
  1708.   (long) local_send_align - 1) &
  1709.  ~((long) local_send_align - 1));
  1710.   message_ptr = message_ptr + local_send_offset;
  1711.   message = message_ptr;
  1712.   send_message.maxlen = send_size;
  1713.   send_message.len = send_size;
  1714.   send_message.buf = message;
  1715.   
  1716.   sctl_message.maxlen = BUFSIZ;
  1717.   sctl_message.len    = 0;
  1718.   sctl_message.buf    = sctl_data;
  1719.   
  1720.   /* if the user supplied a cpu rate, this call will complete rather */
  1721.   /* quickly, otherwise, the cpu rate will be retured to us for */
  1722.   /* possible display. The Library will keep it's own copy of this data */
  1723.   /* for use elsewhere. We will only display it. (Does that make it */
  1724.   /* "opaque" to us?) */
  1725.   
  1726.   if (local_cpu_usage)
  1727.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  1728.   
  1729.   /* Tell the remote end to set up the data connection. The server */
  1730.   /* sends back the port number and alters the socket parameters there. */
  1731.   /* Of course this is a datagram service so no connection is actually */
  1732.   /* set up, the server just sets up the socket and binds it. */
  1733.   
  1734.   netperf_request.content.request_type                 = DO_DLPI_CL_STREAM;
  1735.   dlpi_cl_stream_request->recv_win_size         = rrw_size;
  1736.   dlpi_cl_stream_request->message_size         = send_size;
  1737.   dlpi_cl_stream_request->recv_alignment = remote_recv_align;
  1738.   dlpi_cl_stream_request->recv_offset = remote_recv_offset;
  1739.   dlpi_cl_stream_request->measure_cpu = remote_cpu_usage;
  1740.   dlpi_cl_stream_request->cpu_rate = remote_cpu_rate;
  1741.   dlpi_cl_stream_request->ppa                   = rem_ppa;
  1742.   dlpi_cl_stream_request->sap                   = dlpi_sap;
  1743.   dlpi_cl_stream_request->dev_name_len          = strlen(rem_dlpi_device);
  1744.   strcpy(dlpi_cl_stream_request->dlpi_device,
  1745.  rem_dlpi_device);
  1746.   
  1747. #ifdef __alpha
  1748.   
  1749.   /* ok - even on a DEC box, strings are strings. I din't really want */
  1750.   /* to ntohl the words of a string. since I don't want to teach the */
  1751.   /* send_ and recv_ _request and _response routines about the types, */
  1752.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  1753.   /* solution would be to use XDR, but I am still leary of being able */
  1754.   /* to find XDR libs on all platforms I want running netperf. raj */
  1755.   {
  1756.     int *charword;
  1757.     int *initword;
  1758.     int *lastword;
  1759.     
  1760.     initword = (int *) dlpi_cl_stream_request->dlpi_device;
  1761.     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
  1762.     
  1763.     for (charword = initword;
  1764.  charword < lastword;
  1765.  charword++) {
  1766.       
  1767.       *charword = ntohl(*charword);
  1768.     }
  1769.   }
  1770. #endif /* __alpha */
  1771.   
  1772.   if (test_time) {
  1773.     dlpi_cl_stream_request->test_length = test_time;
  1774.   }
  1775.   else {
  1776.     dlpi_cl_stream_request->test_length = test_bytes * -1;
  1777.   }
  1778.   
  1779.   
  1780.   send_request();
  1781.   
  1782.   recv_response();
  1783.   
  1784.   if (!netperf_response.content.serv_errno) {
  1785.     if (debug)
  1786.       fprintf(where,"send_dlpi_cl_stream: remote data connection done.n");
  1787.   }
  1788.   else {
  1789.     Set_errno(netperf_response.content.serv_errno);
  1790.     perror("send_dlpi_cl_stream: error on remote");
  1791.     exit(1);
  1792.   }
  1793.   
  1794.   /* place some of the remote's addressing information into the send */
  1795.   /* structure so our sends can be sent to the correct place. Also get */
  1796.   /* some of the returned socket buffer information for user display. */
  1797.   
  1798.   /* set-up the destination addressing control info */
  1799.   data_req->dl_primitive = DL_UNITDATA_REQ;
  1800.   bcopy((char *)(dlpi_cl_stream_response->station_addr),
  1801. ((char *)data_req + sizeof(dl_unitdata_req_t)),
  1802. dlpi_cl_stream_response->station_addr_len);
  1803.   data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
  1804.   data_req->dl_dest_addr_length = dlpi_cl_stream_response->station_addr_len;
  1805.   /* there is a dl_priority structure too, but I am ignoring it for */
  1806.   /* the time being. */
  1807.   /* however... it is best to put some value in there lest some code
  1808.      get grumpy about it - fix from Nicolas Thomas */
  1809.   data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
  1810.   data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
  1811.   sctl_message.len = sizeof(dl_unitdata_req_t) + 
  1812.     data_req->dl_dest_addr_length;
  1813.   
  1814.   rrw_size         = dlpi_cl_stream_response->recv_win_size;
  1815.   rsw_size         = dlpi_cl_stream_response->send_win_size;
  1816.   remote_cpu_rate = dlpi_cl_stream_response->cpu_rate;
  1817.   
  1818.   
  1819.   /* set up the timer to call us after test_time */
  1820.   start_timer(test_time);
  1821.   
  1822.   /* Get the start count for the idle counter and the start time */
  1823.   
  1824.   cpu_start(local_cpu_usage);
  1825.   
  1826. #ifdef WANT_INTERVALS
  1827.   interval_count = interval_burst;
  1828. #endif /* WANT_INTERVALS */
  1829.   
  1830.   /* Send datagrams like there was no tomorrow */
  1831.   while (!times_up) {
  1832. #ifdef DIRTY
  1833.     /* we want to dirty some number of consecutive integers in the buffer */
  1834.     /* we are about to send. we may also want to bring some number of */
  1835.     /* them cleanly into the cache. The clean ones will follow any dirty */
  1836.     /* ones into the cache. */
  1837.     message_int_ptr = (int *)message_ptr;
  1838.     for (i = 0; i < loc_dirty_count; i++) {
  1839.       *message_int_ptr = 4;
  1840.       message_int_ptr++;
  1841.     }
  1842.     for (i = 0; i < loc_clean_count; i++) {
  1843.       loc_dirty_count = *message_int_ptr;
  1844.       message_int_ptr++;
  1845.     }
  1846. #endif /* DIRTY */
  1847.     if (putmsg(data_descriptor,
  1848.        &sctl_message,
  1849.        &send_message,
  1850.        0)  != 0) {
  1851.       if (errno == EINTR) {
  1852. break;
  1853.       }
  1854.       if (errno == ENOBUFS) {
  1855. /* we might not ever hit this with STREAMS, it would probably */
  1856. /* be better to do a getinfo request at the end of the test to */
  1857. /* get all sorts of gory statistics. in the meantime, we will */
  1858. /* keep this code in place. */
  1859. failed_sends++;
  1860. continue;
  1861.       }
  1862.       perror("send_dlpi_cl_stream: data send error");
  1863.       if (debug) {
  1864. fprintf(where,"messages_sent %un",messages_sent);
  1865. fflush(where);
  1866.       }
  1867.       exit(1);
  1868.     }
  1869.     messages_sent++;          
  1870.     
  1871.     /* now we want to move our pointer to the next position in the */
  1872.     /* data buffer...since there was a successful send */
  1873.     
  1874.     
  1875. #ifdef WANT_INTERVALS
  1876.     /* in this case, the interval count is the count-down couter */
  1877.     /* to decide to sleep for a little bit */
  1878.     if ((interval_burst) && (--interval_count == 0)) {
  1879.       /* call the sleep routine for some milliseconds, if our */
  1880.       /* timer popped while we were in there, we want to */
  1881.       /* break out of the loop. */
  1882.       if (msec_sleep(interval_wate)) {
  1883. break;
  1884.       }
  1885.       interval_count = interval_burst;
  1886.     }
  1887.     
  1888. #endif /* WANT_INTERVALS */
  1889.     
  1890.   }
  1891.   
  1892.   /* This is a timed test, so the remote will be returning to us after */
  1893.   /* a time. We should not need to send any "strange" messages to tell */
  1894.   /* the remote that the test is completed, unless we decide to add a */
  1895.   /* number of messages to the test. */
  1896.   
  1897.   /* the test is over, so get stats and stuff */
  1898.   cpu_stop(local_cpu_usage,
  1899.    &elapsed_time);
  1900.   
  1901.   /* Get the statistics from the remote end */
  1902.   recv_response();
  1903.   if (!netperf_response.content.serv_errno) {
  1904.     if (debug)
  1905.       fprintf(where,"send_dlpi_cl_stream: remote results obtainedn");
  1906.   }
  1907.   else {
  1908.     Set_errno(netperf_response.content.serv_errno);
  1909.     perror("send_dlpi_cl_stream: error on remote");
  1910.     exit(1);
  1911.   }
  1912.   
  1913.   bytes_sent = send_size * messages_sent;
  1914.   local_thruput = calc_thruput(bytes_sent);
  1915.   
  1916.   messages_recvd = dlpi_cl_stream_results->messages_recvd;
  1917.   bytes_recvd = send_size * messages_recvd;
  1918.   
  1919.   /* we asume that the remote ran for as long as we did */
  1920.   
  1921.   remote_thruput = calc_thruput(bytes_recvd);
  1922.   
  1923.   /* print the results for this descriptor and message size */
  1924.   
  1925.   if (local_cpu_usage || remote_cpu_usage) {
  1926.     /* We must now do a little math for service demand and cpu */
  1927.     /* utilization for the system(s) We pass zeros for the local */
  1928.     /* cpu utilization and elapsed time to tell the routine to use */
  1929.     /* the libraries own values for those. */
  1930.     if (local_cpu_usage) {
  1931.       if (local_cpu_rate == 0.0) {
  1932. fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!n");
  1933. fprintf(where,"Local CPU usage numbers based on process information only!n");
  1934. fflush(where);
  1935.       }
  1936.       
  1937.       local_cpu_utilization = calc_cpu_util(0.0);
  1938.       local_service_demand = calc_service_demand(bytes_sent,
  1939.       0.0,
  1940.       0.0,
  1941.       0);
  1942.     }
  1943.     else {
  1944.       local_cpu_utilization = -1.0;
  1945.       local_service_demand = -1.0;
  1946.     }
  1947.     
  1948.     /* The local calculations could use variables being kept by */
  1949.     /* the local netlib routines. The remote calcuations need to */
  1950.     /* have a few things passed to them. */
  1951.     if (remote_cpu_usage) {
  1952.       if (remote_cpu_rate == 0.0) {
  1953. fprintf(where,"DANGER   DANGER  DANGER   DANGER  DANGER   DANGER   DANGER!n");
  1954. fprintf(where,"REMOTE CPU usage numbers based on process information only!n");
  1955. fflush(where);
  1956.       }
  1957.       
  1958.       remote_cpu_utilization = dlpi_cl_stream_results->cpu_util;
  1959.       remote_service_demand = calc_service_demand(bytes_recvd,
  1960.       0.0,
  1961.       remote_cpu_utilization,
  1962.       dlpi_cl_stream_results->num_cpus);
  1963.     }
  1964.     else {
  1965.       remote_cpu_utilization = -1.0;
  1966.       remote_service_demand = -1.0;
  1967.     }
  1968.     
  1969.     /* We are now ready to print all the information. If the user */
  1970.     /* has specified zero-level verbosity, we will just print the */
  1971.     /* local service demand, or the remote service demand. If the */
  1972.     /* user has requested verbosity level 1, he will get the basic */
  1973.     /* "streamperf" numbers. If the user has specified a verbosity */
  1974.     /* of greater than 1, we will display a veritable plethora of */
  1975.     /* background information from outside of this block as it it */
  1976.     /* not cpu_measurement specific...  */
  1977.     
  1978.     switch (verbosity) {
  1979.     case 0:
  1980.       if (local_cpu_usage) {
  1981. fprintf(where,
  1982. cpu_fmt_0,
  1983. local_service_demand);
  1984.       }
  1985.       else {
  1986. fprintf(where,
  1987. cpu_fmt_0,
  1988. remote_service_demand);
  1989.       }
  1990.       break;
  1991.     case 1:
  1992.       fprintf(where,
  1993.       cpu_fmt_1, /* the format string */
  1994.       lsw_size, /* local sendbuf size */
  1995.       send_size, /* how large were the sends */
  1996.       elapsed_time, /* how long was the test */
  1997.       messages_sent,
  1998.       failed_sends,
  1999.       local_thruput,  /* what was the xfer rate */
  2000.       local_cpu_utilization, /* local cpu */
  2001.       local_service_demand, /* local service demand */
  2002.       rrw_size,
  2003.       elapsed_time,
  2004.       messages_recvd,
  2005.       remote_thruput,
  2006.       remote_cpu_utilization, /* remote cpu */
  2007.       remote_service_demand); /* remote service demand */
  2008.       break;
  2009.     }
  2010.   }
  2011.   else {
  2012.     /* The tester did not wish to measure service demand. */
  2013.     switch (verbosity) {
  2014.     case 0:
  2015.       fprintf(where,
  2016.       tput_fmt_0,
  2017.       local_thruput);
  2018.       break;
  2019.     case 1:
  2020.       fprintf(where,
  2021.       tput_fmt_1, /* the format string */
  2022.       lsw_size,  /* local sendbuf size */
  2023.       send_size, /* how large were the sends */
  2024.       elapsed_time,  /* how long did it take */
  2025.       messages_sent,
  2026.       failed_sends,
  2027.       local_thruput,
  2028.       rrw_size,  /* remote recvbuf size */
  2029.       elapsed_time,
  2030.       messages_recvd,
  2031.       remote_thruput
  2032.       );
  2033.       break;
  2034.     }
  2035.   }
  2036. }
  2037. int
  2038.   recv_dlpi_cl_stream()
  2039. {
  2040.   
  2041.   char  *message;
  2042.   int data_descriptor;
  2043.   int len;
  2044.   char *message_ptr;
  2045.   char  rctl_data[BUFSIZ];
  2046.   struct strbuf recv_message;
  2047.   struct strbuf rctl_message;
  2048.   int flags = 0;
  2049.   /* these are to make reading some of the DLPI control messages easier */
  2050.   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
  2051.   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
  2052.   
  2053.   int bytes_received = 0;
  2054.   float elapsed_time;
  2055.   
  2056.   int message_size;
  2057.   int messages_recvd = 0;
  2058.   int measure_cpu;
  2059.   
  2060.   struct dlpi_cl_stream_request_struct *dlpi_cl_stream_request;
  2061.   struct dlpi_cl_stream_response_struct *dlpi_cl_stream_response;
  2062.   struct dlpi_cl_stream_results_struct *dlpi_cl_stream_results;
  2063.   
  2064.   dlpi_cl_stream_request = (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
  2065.   dlpi_cl_stream_response = (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
  2066.   dlpi_cl_stream_results = (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
  2067.   
  2068.   if (debug) {
  2069.     fprintf(where,"netserver: recv_dlpi_cl_stream: entered...n");
  2070.     fflush(where);
  2071.   }
  2072.   
  2073.   /* We want to set-up the listen descriptor with all the desired */
  2074.   /* parameters and then let the initiator know that all is ready. If */
  2075.   /* socket size defaults are to be used, then the initiator will have */
  2076.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  2077.   /* send-back what they are. If that information cannot be determined, */
  2078.   /* then we send-back -1's for the sizes. If things go wrong for any */
  2079.   /* reason, we will drop back ten yards and punt. */
  2080.   
  2081.   /* If anything goes wrong, we want the remote to know about it. It */
  2082.   /* would be best if the error that the remote reports to the user is */
  2083.   /* the actual error we encountered, rather than some bogus unexpected */
  2084.   /* response type message. */
  2085.   
  2086.   if (debug > 1) {
  2087.     fprintf(where,"recv_dlpi_cl_stream: setting the response type...n");
  2088.     fflush(where);
  2089.   }
  2090.   
  2091.   netperf_response.content.response_type = DLPI_CL_STREAM_RESPONSE;
  2092.   
  2093.   if (debug > 2) {
  2094.     fprintf(where,"recv_dlpi_cl_stream: the response type is set...n");
  2095.     fflush(where);
  2096.   }
  2097.   /* set-up the data buffer with the requested alignment and offset */
  2098.   message = (char *)malloc(DATABUFFERLEN);
  2099.   if (message == NULL) {
  2100.     printf("malloc(%d) failed!n", DATABUFFERLEN);
  2101.     exit(1);
  2102.   }
  2103.   
  2104.   /* We now alter the message_ptr variable to be at the desired */
  2105.   /* alignment with the desired offset. */
  2106.   
  2107.   if (debug > 1) {
  2108.     fprintf(where,"recv_dlpi_cl_stream: requested alignment of %dn",
  2109.     dlpi_cl_stream_request->recv_alignment);
  2110.     fflush(where);
  2111.   }
  2112.   message_ptr = ALIGN_BUFFER(message, dlpi_cl_stream_request->recv_alignment, dlpi_cl_stream_request->recv_offset);
  2113.   
  2114.   if (dlpi_cl_stream_request->message_size > 0) {
  2115.     recv_message.maxlen = dlpi_cl_stream_request->message_size;
  2116.   }
  2117.   else {
  2118.     recv_message.maxlen = 4096;
  2119.   }
  2120.   recv_message.len    = 0;
  2121.   recv_message.buf    = message_ptr;
  2122.   
  2123.   rctl_message.maxlen = BUFSIZ;
  2124.   rctl_message.len    = 0;
  2125.   rctl_message.buf    = rctl_data;
  2126.   
  2127.   if (debug > 1) {
  2128.     fprintf(where,
  2129.     "recv_dlpi_cl_stream: receive alignment and offset set...n");
  2130.     fflush(where);
  2131.   }
  2132.   
  2133.   if (debug > 1) {
  2134.     fprintf(where,"recv_dlpi_cl_stream: grabbing a descriptor...n");
  2135.     fflush(where);
  2136.   }
  2137.   
  2138. #ifdef __alpha
  2139.   
  2140.   /* ok - even on a DEC box, strings are strings. I din't really want */
  2141.   /* to ntohl the words of a string. since I don't want to teach the */
  2142.   /* send_ and recv_ _request and _response routines about the types, */
  2143.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  2144.   /* solution would be to use XDR, but I am still leary of being able */
  2145.   /* to find XDR libs on all platforms I want running netperf. raj */
  2146.   {
  2147.     int *charword;
  2148.     int *initword;
  2149.     int *lastword;
  2150.     
  2151.     initword = (int *) dlpi_cl_stream_request->dlpi_device;
  2152.     lastword = initword + ((dlpi_cl_stream_request->dev_name_len + 3) / 4);
  2153.     
  2154.     for (charword = initword;
  2155.  charword < lastword;
  2156.  charword++) {
  2157.       
  2158.       *charword = htonl(*charword);
  2159.     }
  2160.   }
  2161. #endif /* __alpha */
  2162.   
  2163.   data_descriptor = dl_open(dlpi_cl_stream_request->dlpi_device,
  2164.     dlpi_cl_stream_request->ppa);
  2165.   if (data_descriptor < 0) {
  2166.     netperf_response.content.serv_errno = errno;
  2167.     send_response();
  2168.     exit(1);
  2169.   }
  2170.   
  2171.   /* The initiator may have wished-us to modify the window */
  2172.   /* sizes. We should give it a shot. If he didn't ask us to change the */
  2173.   /* sizes, we should let him know what sizes were in use at this end. */
  2174.   /* If none of this code is compiled-in, then we will tell the */
  2175.   /* initiator that we were unable to play with the sizes by */
  2176.   /* setting the size in the response to -1. */
  2177.   
  2178. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  2179.   
  2180.   if (dlpi_cl_stream_request->recv_win_size) {
  2181.     dlpi_cl_stream_response->recv_win_size = -1;
  2182.   }
  2183.   
  2184. #else /* the system won't let us play with the buffers */
  2185.   
  2186.   dlpi_cl_stream_response->recv_win_size = -1;
  2187.   
  2188. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  2189.   
  2190.   dlpi_cl_stream_response->test_length = dlpi_cl_stream_request->test_length;
  2191.   
  2192.   /* bind the sap and retrieve the dlsap assigned by the system  */
  2193.   dlpi_cl_stream_response->station_addr_len = 14; /* arbitrary */
  2194.   if (dl_bind(data_descriptor,
  2195.       dlpi_cl_stream_request->sap,
  2196.       DL_CLDLS,
  2197.       (char *)dlpi_cl_stream_response->station_addr,
  2198.       &dlpi_cl_stream_response->station_addr_len) != 0) {
  2199.     fprintf(where,"send_dlpi_cl_stream: bind failuren");
  2200.     fflush(where);
  2201.     exit(1);
  2202.   }
  2203.   
  2204.   netperf_response.content.serv_errno   = 0;
  2205.   
  2206.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  2207.   /* then we must call the calibrate routine, which will return the max */
  2208.   /* rate back to the initiator. If the CPU was not to be measured, or */
  2209.   /* something went wrong with the calibration, we will return a -1 to */
  2210.   /* the initiator. */
  2211.   
  2212.   dlpi_cl_stream_response->cpu_rate = 0.0;  /* assume no cpu */
  2213.   if (dlpi_cl_stream_request->measure_cpu) {
  2214.     /* We will pass the rate into the calibration routine. If the */
  2215.     /* user did not specify one, it will be 0.0, and we will do a */
  2216.     /* "real" calibration. Otherwise, all it will really do is */
  2217.     /* store it away... */
  2218.     dlpi_cl_stream_response->measure_cpu = 1;
  2219.     dlpi_cl_stream_response->cpu_rate = calibrate_local_cpu(dlpi_cl_stream_request->cpu_rate);
  2220.   }
  2221.   
  2222.   message_size = dlpi_cl_stream_request->message_size;
  2223.   test_time = dlpi_cl_stream_request->test_length;
  2224.   
  2225.   send_response();
  2226.   
  2227.   /* Now it's time to start receiving data on the connection. We will */
  2228.   /* first grab the apropriate counters and then start grabbing. */
  2229.   
  2230.   cpu_start(dlpi_cl_stream_request->measure_cpu);
  2231.   
  2232.   /* The loop will exit when the timer pops, or if we happen to recv a */
  2233.   /* message of less than send_size bytes... */
  2234.   
  2235.   times_up = 0;
  2236.   start_timer(test_time + PAD_TIME);
  2237.   
  2238.   if (debug) {
  2239.     fprintf(where,"recv_dlpi_cl_stream: about to enter inner sanctum.n");
  2240.     fflush(where);
  2241.   }
  2242.   
  2243.   while (!times_up) {
  2244.     if((getmsg(data_descriptor, 
  2245.        &rctl_message,    
  2246.        &recv_message,
  2247.        &flags) != 0) || 
  2248.        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
  2249.       if (errno == EINTR) {
  2250. /* Again, we have likely hit test-end time */
  2251. break;
  2252.       }
  2253.       fprintf(where,
  2254.       "dlpi_recv_cl_stream: getmsg failure: errno %d primitive 0x%xn",
  2255.       errno,
  2256.       data_ind->dl_primitive);
  2257.       fflush(where);
  2258.       netperf_response.content.serv_errno = 996;
  2259.       send_response();
  2260.       exit(1);
  2261.     }
  2262.     messages_recvd++;
  2263.   }
  2264.   
  2265.   if (debug) {
  2266.     fprintf(where,"recv_dlpi_cl_stream: got %d messages.n",messages_recvd);
  2267.     fflush(where);
  2268.   }
  2269.   
  2270.   
  2271.   /* The loop now exits due timer or < send_size bytes received. */
  2272.   
  2273.   cpu_stop(dlpi_cl_stream_request->measure_cpu,&elapsed_time);
  2274.   
  2275.   if (times_up) {
  2276.     /* we ended on a timer, subtract the PAD_TIME */
  2277.     elapsed_time -= (float)PAD_TIME;
  2278.   }
  2279.   else {
  2280.     stop_timer();
  2281.   }
  2282.   
  2283.   if (debug) {
  2284.     fprintf(where,"recv_dlpi_cl_stream: test ended in %f seconds.n",elapsed_time);
  2285.     fflush(where);
  2286.   }
  2287.   
  2288.   
  2289.   /* We will count the "off" message */
  2290.   bytes_received = (messages_recvd * message_size) + len;
  2291.   
  2292.   /* send the results to the sender */
  2293.   
  2294.   if (debug) {
  2295.     fprintf(where,
  2296.     "recv_dlpi_cl_stream: got %d bytesn",
  2297.     bytes_received);
  2298.     fflush(where);
  2299.   }
  2300.   
  2301.   netperf_response.content.response_type = DLPI_CL_STREAM_RESULTS;
  2302.   dlpi_cl_stream_results->bytes_received = bytes_received;
  2303.   dlpi_cl_stream_results->messages_recvd = messages_recvd;
  2304.   dlpi_cl_stream_results->elapsed_time = elapsed_time;
  2305.   if (dlpi_cl_stream_request->measure_cpu) {
  2306.     dlpi_cl_stream_results->cpu_util = calc_cpu_util(elapsed_time);
  2307.   }
  2308.   else {
  2309.     dlpi_cl_stream_results->cpu_util = -1.0;
  2310.   }
  2311.   
  2312.   if (debug > 1) {
  2313.     fprintf(where,
  2314.     "recv_dlpi_cl_stream: test complete, sending results.n");
  2315.     fflush(where);
  2316.   }
  2317.   
  2318.   send_response();
  2319.   
  2320. }
  2321. int send_dlpi_cl_rr(char remote_host[])
  2322. {
  2323.   
  2324.   char *tput_title = "
  2325. Local /Remoten
  2326. Window Size   Request  Resp.   Elapsed  Trans.n
  2327. Send   Recv   Size     Size    Time     Rate         n
  2328. frames frames bytes    bytes   secs.    per sec   nn";
  2329.   
  2330.   char *tput_fmt_0 =
  2331.     "%7.2fn";
  2332.   
  2333.   char *tput_fmt_1_line_1 = "
  2334. %-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   n";
  2335.   char *tput_fmt_1_line_2 = "
  2336. %-6d %-6dn";
  2337.   
  2338.   char *cpu_title = "
  2339. Local /Remoten
  2340. Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.demn
  2341. Send   Recv   Size    Size   Time    Rate     local  remote local   remoten
  2342. frames frames bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Trnn";
  2343.   
  2344.   char *cpu_fmt_0 =
  2345.     "%6.3fn";
  2346.   
  2347.   char *cpu_fmt_1_line_1 = "
  2348. %-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3fn";
  2349.   
  2350.   char *cpu_fmt_1_line_2 = "
  2351. %-6d %-6dn";
  2352.   
  2353.   char *ksink_fmt = "
  2354. Alignment      Offsetn
  2355. Local  Remote  Local  Remoten
  2356. Send   Recv    Send   Recvn
  2357. %5d  %5d   %5d  %5dn";
  2358.   
  2359.   
  2360.   float elapsed_time;
  2361.   
  2362.   int   dlsap_len;
  2363.   int   flags = 0;
  2364.   char *send_message_ptr;
  2365.   char *recv_message_ptr;
  2366.   char *temp_message_ptr;
  2367.   char  sctl_data[BUFSIZ];
  2368.   char  rctl_data[BUFSIZ];
  2369.   char  dlsap[BUFSIZ];
  2370.   struct strbuf send_message;
  2371.   struct strbuf recv_message;
  2372.   struct strbuf sctl_message;
  2373.   struct strbuf rctl_message;
  2374.   
  2375.   /* these are to make reading some of the DLPI control messages easier */
  2376.   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
  2377.   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
  2378.   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
  2379.   
  2380.   int nummessages;
  2381.   int send_descriptor;
  2382.   int trans_remaining;
  2383.   int bytes_xferd;
  2384.   
  2385.   float local_cpu_utilization;
  2386.   float local_service_demand;
  2387.   float remote_cpu_utilization;
  2388.   float remote_service_demand;
  2389.   double thruput;
  2390.   
  2391. #ifdef WANT_INTERVALS
  2392.   /* timing stuff */
  2393. #define MAX_KEPT_TIMES 1024
  2394.   int time_index = 0;
  2395.   int unused_buckets;
  2396.   int kept_times[MAX_KEPT_TIMES];
  2397.   int sleep_usecs;
  2398.   unsigned int total_times=0;
  2399.   struct timezone dummy_zone;
  2400.   struct timeval send_time;
  2401.   struct timeval recv_time;
  2402.   struct timeval sleep_timeval;
  2403. #endif /* WANT_INTERVALS */
  2404.   
  2405.   struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request;
  2406.   struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response;
  2407.   struct dlpi_cl_rr_results_struct *dlpi_cl_rr_result;
  2408.   
  2409.   dlpi_cl_rr_request = 
  2410.     (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
  2411.   dlpi_cl_rr_response = 
  2412.     (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
  2413.   dlpi_cl_rr_result = 
  2414.     (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
  2415.   
  2416.   /* we want to zero out the times, so we can detect unused entries. */
  2417. #ifdef WANT_INTERVALS
  2418.   time_index = 0;
  2419.   while (time_index < MAX_KEPT_TIMES) {
  2420.     kept_times[time_index] = 0;
  2421.     time_index += 1;
  2422.   }
  2423.   time_index = 0;
  2424. #endif /* WANT_INTERVALS */
  2425.   
  2426.   if (print_headers) {
  2427.     fprintf(where,"DLPI CL REQUEST/RESPONSE TESTn");
  2428.     if (local_cpu_usage || remote_cpu_usage)
  2429.       fprintf(where,cpu_title,format_units());
  2430.     else
  2431.       fprintf(where,tput_title,format_units());
  2432.   }
  2433.   
  2434.   /* initialize a few counters */
  2435.   
  2436.   nummessages = 0;
  2437.   bytes_xferd = 0;
  2438.   times_up  =  0;
  2439.   
  2440.   /* set-up the data buffer with the requested alignment and offset */
  2441.   temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
  2442.   if (temp_message_ptr == NULL) {
  2443.     printf("malloc(%d) failed!n", req_size+MAXALIGNMENT+MAXOFFSET);
  2444.     exit(1);
  2445.   }
  2446.   send_message_ptr = (char *)(( (long)temp_message_ptr + 
  2447.        (long) local_send_align - 1) &
  2448.       ~((long) local_send_align - 1));
  2449.   send_message_ptr = send_message_ptr + local_send_offset;
  2450.   send_message.maxlen = req_size;
  2451.   send_message.len    = req_size;
  2452.   send_message.buf    = send_message_ptr;
  2453.   
  2454.   temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
  2455.   if (temp_message_ptr == NULL) {
  2456.     printf("malloc(%d) failed!n", rsp_size+MAXALIGNMENT+MAXOFFSET);
  2457.     exit(1);
  2458.   }
  2459.   recv_message_ptr = (char *)(( (long)temp_message_ptr + 
  2460.        (long) local_recv_align - 1) &
  2461.       ~((long) local_recv_align - 1));
  2462.   recv_message_ptr = recv_message_ptr + local_recv_offset;
  2463.   recv_message.maxlen = rsp_size;
  2464.   recv_message.len    = 0;
  2465.   recv_message.buf    = recv_message_ptr;
  2466.   
  2467.   sctl_message.maxlen = BUFSIZ;
  2468.   sctl_message.len    = 0;
  2469.   sctl_message.buf    = sctl_data;
  2470.   
  2471.   rctl_message.maxlen = BUFSIZ;
  2472.   rctl_message.len    = 0;
  2473.   rctl_message.buf    = rctl_data;
  2474.   
  2475.   /* lets get ourselves a file descriptor */
  2476.   
  2477.   send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
  2478.   if (send_descriptor < 0){
  2479.     perror("netperf: send_dlpi_cl_rr: dlpi cl rr send descriptor");
  2480.     exit(1);
  2481.   }
  2482.   
  2483.   if (debug) {
  2484.     fprintf(where,"send_dlpi_cl_rr: send_descriptor obtained...n");
  2485.   }
  2486.   
  2487.   /* bind the sap to the descriptor and get the dlsap */
  2488.   dlsap_len = BUFSIZ;
  2489.   if (dl_bind(send_descriptor,
  2490.       dlpi_sap,
  2491.       DL_CLDLS,
  2492.       dlsap,
  2493.       &dlsap_len) != 0) {
  2494.     fprintf(where,"send_dlpi_cl_rr: bind failuren");
  2495.     fflush(where);
  2496.     exit(1);
  2497.   }
  2498.   
  2499.   /* Modify the local socket size. If the user has not requested that */
  2500.   /* the socket buffers be altered, we will try to find-out what their */
  2501.   /* values are. If we cannot touch the socket buffer in any way, we */
  2502.   /* will set the values to -1 to indicate that.  The receive socket */
  2503.   /* must have enough space to hold addressing information so += a */
  2504.   /* sizeof struct sockaddr_in to it. */ 
  2505.   
  2506.   /* this is actually nothing code, and should be replaced with the */
  2507.   /* alalagous calls in the STREAM test where the window size is set */
  2508.   /* with the HP DLPI Extension. raj 8/94 */
  2509. #ifdef SO_SNDBUF
  2510.   if (lsw_size > 0) {
  2511.     if (debug > 1) {
  2512.       fprintf(where,"netperf: send_dlpi_cl_rr: local window size altered from system default...n");
  2513.       fprintf(where,"                          window: %dn",lsw_size);
  2514.     }
  2515.   }
  2516.   if (lrw_size > 0) {
  2517.     if (debug > 1) {
  2518.       fprintf(where,"netperf: send_dlpi_cl_rr: remote window size altered from system default...n");
  2519.       fprintf(where,"                          remote: %dn",lrw_size);
  2520.     }
  2521.   }
  2522.   
  2523.   
  2524.   /* Now, we will find-out what the size actually became, and report */
  2525.   /* that back to the user. If the call fails, we will just report a -1 */
  2526.   /* back to the initiator for the recv buffer size. */
  2527.   
  2528.   if (debug) {
  2529.     fprintf(where,"netperf: send_dlpi_cl_rr: socket sizes determined...n");
  2530.     fprintf(where,"         send: %d recv: %dn",lsw_size,lrw_size);
  2531.   }
  2532.   
  2533. #else /* SO_SNDBUF */
  2534.   
  2535.   lsw_size = -1;
  2536.   lrw_size = -1;
  2537.   
  2538. #endif /* SO_SNDBUF */
  2539.   
  2540.   /* If the user has requested cpu utilization measurements, we must */
  2541.   /* calibrate the cpu(s). We will perform this task within the tests */
  2542.   /* themselves. If the user has specified the cpu rate, then */
  2543.   /* calibrate_local_cpu will return rather quickly as it will have */
  2544.   /* nothing to do. If local_cpu_rate is zero, then we will go through */
  2545.   /* all the "normal" calibration stuff and return the rate back. If */
  2546.   /* there is no idle counter in the kernel idle loop, the */
  2547.   /* local_cpu_rate will be set to -1. */
  2548.   
  2549.   if (local_cpu_usage) {
  2550.     local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
  2551.   }
  2552.   
  2553.   /* Tell the remote end to do a listen. The server alters the socket */
  2554.   /* paramters on the other side at this point, hence the reason for */
  2555.   /* all the values being passed in the setup message. If the user did */
  2556.   /* not specify any of the parameters, they will be passed as 0, which */
  2557.   /* will indicate to the remote that no changes beyond the system's */
  2558.   /* default should be used. Alignment is the exception, it will */
  2559.   /* default to 8, which will be no alignment alterations. */
  2560.   
  2561.   netperf_request.content.request_type         = DO_DLPI_CL_RR;
  2562.   dlpi_cl_rr_request->recv_win_size = rrw_size;
  2563.   dlpi_cl_rr_request->send_win_size = rsw_size;
  2564.   dlpi_cl_rr_request->recv_alignment = remote_recv_align;
  2565.   dlpi_cl_rr_request->recv_offset = remote_recv_offset;
  2566.   dlpi_cl_rr_request->send_alignment = remote_send_align;
  2567.   dlpi_cl_rr_request->send_offset = remote_send_offset;
  2568.   dlpi_cl_rr_request->request_size = req_size;
  2569.   dlpi_cl_rr_request->response_size = rsp_size;
  2570.   dlpi_cl_rr_request->measure_cpu = remote_cpu_usage;
  2571.   dlpi_cl_rr_request->cpu_rate         = remote_cpu_rate;
  2572.   dlpi_cl_rr_request->ppa               =       rem_ppa;
  2573.   dlpi_cl_rr_request->sap               =       dlpi_sap;
  2574.   dlpi_cl_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
  2575.   strcpy(dlpi_cl_rr_request->dlpi_device,
  2576.  rem_dlpi_device);
  2577.   
  2578. #ifdef __alpha
  2579.   
  2580.   /* ok - even on a DEC box, strings are strings. I din't really want */
  2581.   /* to ntohl the words of a string. since I don't want to teach the */
  2582.   /* send_ and recv_ _request and _response routines about the types, */
  2583.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  2584.   /* solution would be to use XDR, but I am still leary of being able */
  2585.   /* to find XDR libs on all platforms I want running netperf. raj */
  2586.   {
  2587.     int *charword;
  2588.     int *initword;
  2589.     int *lastword;
  2590.     
  2591.     initword = (int *) dlpi_cl_rr_request->dlpi_device;
  2592.     lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
  2593.     
  2594.     for (charword = initword;
  2595.  charword < lastword;
  2596.  charword++) {
  2597.       
  2598.       *charword = ntohl(*charword);
  2599.     }
  2600.   }
  2601. #endif /* __alpha */
  2602.   
  2603.   if (test_time) {
  2604.     dlpi_cl_rr_request->test_length = test_time;
  2605.   }
  2606.   else {
  2607.     dlpi_cl_rr_request->test_length = test_trans * -1;
  2608.   }
  2609.   
  2610.   if (debug > 1) {
  2611.     fprintf(where,"netperf: send_dlpi_cl_rr: requesting DLPI CL request/response testn");
  2612.   }
  2613.   
  2614.   send_request();
  2615.   
  2616.   /* The response from the remote will contain all of the relevant  */
  2617.   /* socket parameters for this test type. We will put them back into  */
  2618.   /* the variables here so they can be displayed if desired.  The */
  2619.   /* remote will have calibrated CPU if necessary, and will have done */
  2620.   /* all the needed set-up we will have calibrated the cpu locally */
  2621.   /* before sending the request, and will grab the counter value right */
  2622.   /* after the connect returns. The remote will grab the counter right */
  2623.   /* after the accept call. This saves the hassle of extra messages */
  2624.   /* being sent for the tests.                                          */
  2625.   
  2626.   recv_response();
  2627.   
  2628.   if (!netperf_response.content.serv_errno) {
  2629.     if (debug)
  2630.       fprintf(where,"remote listen done.n");
  2631.     rrw_size = dlpi_cl_rr_response->recv_win_size;
  2632.     rsw_size = dlpi_cl_rr_response->send_win_size;
  2633.     remote_cpu_usage= dlpi_cl_rr_response->measure_cpu;
  2634.     remote_cpu_rate =  dlpi_cl_rr_response->cpu_rate;
  2635.     
  2636.     /* set-up the destination addressing control info */
  2637.     data_req->dl_primitive = DL_UNITDATA_REQ;
  2638.     bcopy((char *)(dlpi_cl_rr_response->station_addr),
  2639.   ((char *)data_req + sizeof(dl_unitdata_req_t)),
  2640.   dlpi_cl_rr_response->station_addr_len);
  2641.     data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
  2642.     data_req->dl_dest_addr_length = dlpi_cl_rr_response->station_addr_len;
  2643.     /* there is a dl_priority structure too, but I am ignoring it for */
  2644.     /* the time being. */
  2645.     sctl_message.len = sizeof(dl_unitdata_req_t) + 
  2646.       data_req->dl_dest_addr_length;
  2647.     /* famous last words - some DLPI providers get unhappy if the
  2648.        priority stuff is not initialized.  fix from Nicolas Thomas. */
  2649.     data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
  2650.     data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
  2651.   }
  2652.   else {
  2653.     Set_errno(netperf_response.content.serv_errno);
  2654.     perror("netperf: remote error");
  2655.     exit(1);
  2656.   }
  2657.   
  2658.   /* Data Socket set-up is finished. If there were problems, either the */
  2659.   /* connect would have failed, or the previous response would have */
  2660.   /* indicated a problem. I failed to see the value of the extra */
  2661.   /* message after the accept on the remote. If it failed, we'll see it */
  2662.   /* here. If it didn't, we might as well start pumping data. */
  2663.   
  2664.   /* Set-up the test end conditions. For a request/response test, they */
  2665.   /* can be either time or transaction based. */
  2666.   
  2667.   if (test_time) {
  2668.     /* The user wanted to end the test after a period of time. */
  2669.     times_up = 0;
  2670.     trans_remaining = 0;
  2671.     start_timer(test_time);
  2672.   }
  2673.   else {
  2674.     /* The tester wanted to send a number of bytes. */
  2675.     trans_remaining = test_bytes;
  2676.     times_up = 1;
  2677.   }
  2678.   
  2679.   /* The cpu_start routine will grab the current time and possibly */
  2680.   /* value of the idle counter for later use in measuring cpu */
  2681.   /* utilization and/or service demand and thruput. */
  2682.   
  2683.   cpu_start(local_cpu_usage);
  2684.   
  2685.   /* We use an "OR" to control test execution. When the test is */
  2686.   /* controlled by time, the byte count check will always return false. */
  2687.   /* When the test is controlled by byte count, the time test will */
  2688.   /* always return false. When the test is finished, the whole */
  2689.   /* expression will go false and we will stop sending data. I think I */
  2690.   /* just arbitrarily decrement trans_remaining for the timed test, but */
  2691.   /* will not do that just yet... One other question is whether or not */
  2692.   /* the send buffer and the receive buffer should be the same buffer. */
  2693.   while ((!times_up) || (trans_remaining > 0)) {
  2694.     /* send the request */
  2695. #ifdef WANT_INTERVALS
  2696.     gettimeofday(&send_time,&dummy_zone);
  2697. #endif /* WANT_INTERVALS */
  2698.     if(putmsg(send_descriptor,
  2699.       &sctl_message,
  2700.       &send_message,
  2701.       0) != 0) {
  2702.       if (errno == EINTR) {
  2703. /* We likely hit */
  2704. /* test-end time. */
  2705. break;
  2706.       }
  2707.       /* there is more we could do here, but it can wait */
  2708.       perror("send_dlpi_cl_rr: data send error");
  2709.       exit(1);
  2710.     }
  2711.     
  2712.     /* receive the response. at some point, we will need to handle */
  2713.     /* sending responses which are greater than the datalink MTU. we */
  2714.     /* may also want to add some DLPI error checking, but for now we */
  2715.     /* will ignore that and just let errors stop the test with little */
  2716.     /* indication of what might actually be wrong. */
  2717.     
  2718.     if((getmsg(send_descriptor, 
  2719.        &rctl_message,    
  2720.        &recv_message,
  2721.        &flags) != 0) || 
  2722.        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
  2723.       if (errno == EINTR) {
  2724. /* Again, we have likely hit test-end time */
  2725. break;
  2726.       }
  2727.       fprintf(where,
  2728.       "send_dlpi_cl_rr: recv error: errno %d primitive 0x%xn",
  2729.       errno,
  2730.       data_ind->dl_primitive);
  2731.       fflush(where);
  2732.       exit(1);
  2733.     }
  2734. #ifdef WANT_INTERVALS
  2735.     gettimeofday(&recv_time,&dummy_zone);
  2736.     
  2737.     /* now we do some arithmatic on the two timevals */
  2738.     if (recv_time.tv_usec < send_time.tv_usec) {
  2739.       /* we wrapped around a second */
  2740.       recv_time.tv_usec += 1000000;
  2741.       recv_time.tv_sec  -= 1;
  2742.     }
  2743.     
  2744.     /* and store it away */
  2745.     kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
  2746.     kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
  2747.     
  2748.     /* at this point, we may wish to sleep for some period of */
  2749.     /* time, so we see how long that last transaction just took, */
  2750.     /* and sleep for the difference of that and the interval. We */
  2751.     /* will not sleep if the time would be less than a */
  2752.     /* millisecond.  */
  2753.     if (interval_usecs > 0) {
  2754.       sleep_usecs = interval_usecs - kept_times[time_index];
  2755.       if (sleep_usecs > 1000) {
  2756. /* we sleep */
  2757. sleep_timeval.tv_sec = sleep_usecs / 1000000;
  2758. sleep_timeval.tv_usec = sleep_usecs % 1000000;
  2759. select(0,
  2760.        0,
  2761.        0,
  2762.        0,
  2763.        &sleep_timeval);
  2764.       }
  2765.     }
  2766.     
  2767.     /* now up the time index */
  2768.     time_index = (time_index +1)%MAX_KEPT_TIMES;
  2769. #endif /* WANT_INTERVALS */
  2770.     nummessages++;          
  2771.     if (trans_remaining) {
  2772.       trans_remaining--;
  2773.     }
  2774.     
  2775.     if (debug > 3) {
  2776.       fprintf(where,"Transaction %d completedn",nummessages);
  2777.       fflush(where);
  2778.     }
  2779.     
  2780.   }
  2781.   
  2782.   /* this call will always give us the elapsed time for the test, and */
  2783.   /* will also store-away the necessaries for cpu utilization */
  2784.   
  2785.   cpu_stop(local_cpu_usage,&elapsed_time); /* was cpu being measured? */
  2786.   /* how long did we really run? */
  2787.   
  2788.   /* Get the statistics from the remote end. The remote will have */
  2789.   /* calculated service demand and all those interesting things. If it */
  2790.   /* wasn't supposed to care, it will return obvious values. */
  2791.   
  2792.   recv_response();
  2793.   if (!netperf_response.content.serv_errno) {
  2794.     if (debug)
  2795.       fprintf(where,"remote results obtainedn");
  2796.   }
  2797.   else {
  2798.     Set_errno(netperf_response.content.serv_errno);
  2799.     perror("netperf: remote error");
  2800.     
  2801.     exit(1);
  2802.   }
  2803.   
  2804.   /* We now calculate what our thruput was for the test. In the future, */
  2805.   /* we may want to include a calculation of the thruput measured by */
  2806.   /* the remote, but it should be the case that for a UDP stream test, */
  2807.   /* that the two numbers should be *very* close... We calculate */
  2808.   /* bytes_sent regardless of the way the test length was controlled. */
  2809.   /* If it was time, we needed to, and if it was by bytes, the user may */
  2810.   /* have specified a number of bytes that wasn't a multiple of the */
  2811.   /* send_size, so we really didn't send what he asked for ;-) We use */
  2812.   
  2813.   bytes_xferd = (req_size * nummessages) + (rsp_size * nummessages);
  2814.   thruput = calc_thruput(bytes_xferd);
  2815.   
  2816.   if (local_cpu_usage || remote_cpu_usage) {
  2817.     /* We must now do a little math for service demand and cpu */
  2818.     /* utilization for the system(s) */
  2819.     /* Of course, some of the information might be bogus because */
  2820.     /* there was no idle counter in the kernel(s). We need to make */
  2821.     /* a note of this for the user's benefit...*/
  2822.     if (local_cpu_usage) {
  2823.       if (local_cpu_rate == 0.0) {
  2824. fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!n");
  2825. fprintf(where,"Local CPU usage numbers based on process information only!n");
  2826. fflush(where);
  2827.       }
  2828.       local_cpu_utilization = calc_cpu_util(0.0);
  2829.       /* since calc_service demand is doing ms/Kunit we will */
  2830.       /* multiply the number of transaction by 1024 to get */
  2831.       /* "good" numbers */
  2832.       local_service_demand  = calc_service_demand((double) nummessages*1024,
  2833.   0.0,
  2834.   0.0,
  2835.   0);
  2836.     }
  2837.     else {
  2838.       local_cpu_utilization = -1.0;
  2839.       local_service_demand = -1.0;
  2840.     }
  2841.     
  2842.     if (remote_cpu_usage) {
  2843.       if (remote_cpu_rate == 0.0) {
  2844. fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!n");
  2845. fprintf(where,"Remote CPU usage numbers based on process information only!n");
  2846. fflush(where);
  2847.       }
  2848.       remote_cpu_utilization = dlpi_cl_rr_result->cpu_util;
  2849.       /* since calc_service demand is doing ms/Kunit we will */
  2850.       /* multiply the number of transaction by 1024 to get */
  2851.       /* "good" numbers */
  2852.       remote_service_demand  = calc_service_demand((double) nummessages*1024,
  2853.    0.0,
  2854.    remote_cpu_utilization,
  2855.    dlpi_cl_rr_result->num_cpus);
  2856.     }
  2857.     else {
  2858.       remote_cpu_utilization = -1.0;
  2859.       remote_service_demand  = -1.0;
  2860.     }
  2861.     
  2862.     /* We are now ready to print all the information. If the user */
  2863.     /* has specified zero-level verbosity, we will just print the */
  2864.     /* local service demand, or the remote service demand. If the */
  2865.     /* user has requested verbosity level 1, he will get the basic */
  2866.     /* "streamperf" numbers. If the user has specified a verbosity */
  2867.     /* of greater than 1, we will display a veritable plethora of */
  2868.     /* background information from outside of this block as it it */
  2869.     /* not cpu_measurement specific...  */
  2870.     
  2871.     switch (verbosity) {
  2872.     case 0:
  2873.       if (local_cpu_usage) {
  2874. fprintf(where,
  2875. cpu_fmt_0,
  2876. local_service_demand);
  2877.       }
  2878.       else {
  2879. fprintf(where,
  2880. cpu_fmt_0,
  2881. remote_service_demand);
  2882.       }
  2883.       break;
  2884.     case 1:
  2885.     case 2:
  2886.       fprintf(where,
  2887.       cpu_fmt_1_line_1, /* the format string */
  2888.       lsw_size, /* local sendbuf size */
  2889.       lrw_size,
  2890.       req_size, /* how large were the requests */
  2891.       rsp_size, /* guess */
  2892.       elapsed_time, /* how long was the test */
  2893.       nummessages/elapsed_time,
  2894.       local_cpu_utilization, /* local cpu */
  2895.       remote_cpu_utilization, /* remote cpu */
  2896.       local_service_demand, /* local service demand */
  2897.       remote_service_demand); /* remote service demand */
  2898.       fprintf(where,
  2899.       cpu_fmt_1_line_2,
  2900.       rsw_size,
  2901.       rrw_size);
  2902.       break;
  2903.     }
  2904.   }
  2905.   else {
  2906.     /* The tester did not wish to measure service demand. */
  2907.     switch (verbosity) {
  2908.     case 0:
  2909.       fprintf(where,
  2910.       tput_fmt_0,
  2911.       nummessages/elapsed_time);
  2912.       break;
  2913.     case 1:
  2914.     case 2:
  2915.       fprintf(where,
  2916.       tput_fmt_1_line_1, /* the format string */
  2917.       lsw_size,
  2918.       lrw_size,
  2919.       req_size, /* how large were the requests */
  2920.       rsp_size, /* how large were the responses */
  2921.       elapsed_time,  /* how long did it take */
  2922.       nummessages/elapsed_time);
  2923.       fprintf(where,
  2924.       tput_fmt_1_line_2,
  2925.       rsw_size,  /* remote recvbuf size */
  2926.       rrw_size);
  2927.       
  2928.       break;
  2929.     }
  2930.   }
  2931.   
  2932.   /* it would be a good thing to include information about some of the */
  2933.   /* other parameters that may have been set for this test, but at the */
  2934.   /* moment, I do not wish to figure-out all the  formatting, so I will */
  2935.   /* just put this comment here to help remind me that it is something */
  2936.   /* that should be done at a later time. */
  2937.   
  2938.   if (verbosity > 1) {
  2939.     /* The user wanted to know it all, so we will give it to him. */
  2940.     /* This information will include as much as we can find about */
  2941.     /* UDP statistics, the alignments of the sends and receives */
  2942.     /* and all that sort of rot... */
  2943.     
  2944. #ifdef WANT_INTERVALS
  2945.     kept_times[MAX_KEPT_TIMES] = 0;
  2946.     time_index = 0;
  2947.     while (time_index < MAX_KEPT_TIMES) {
  2948.       if (kept_times[time_index] > 0) {
  2949. total_times += kept_times[time_index];
  2950.       }
  2951.       else
  2952. unused_buckets++;
  2953.       time_index += 1;
  2954.     }
  2955.     total_times /= (MAX_KEPT_TIMES-unused_buckets);
  2956.     fprintf(where,
  2957.     "Average response time %d usecsn",
  2958.     total_times);
  2959. #endif
  2960.   }
  2961. }
  2962. int 
  2963.   recv_dlpi_cl_rr()
  2964. {
  2965.   
  2966.   char  *message;
  2967.   int data_descriptor;
  2968.   int   flags = 0;
  2969.   int measure_cpu;
  2970.   
  2971.   char *recv_message_ptr;
  2972.   char *send_message_ptr;
  2973.   char  sctl_data[BUFSIZ];
  2974.   char  rctl_data[BUFSIZ];
  2975.   char  dlsap[BUFSIZ];
  2976.   struct strbuf send_message;
  2977.   struct strbuf recv_message;
  2978.   struct strbuf sctl_message;
  2979.   struct strbuf rctl_message;
  2980.   
  2981.   /* these are to make reading some of the DLPI control messages easier */
  2982.   dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
  2983.   dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
  2984.   dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
  2985.   
  2986.   int trans_received;
  2987.   int trans_remaining;
  2988.   float elapsed_time;
  2989.   
  2990.   struct dlpi_cl_rr_request_struct *dlpi_cl_rr_request;
  2991.   struct dlpi_cl_rr_response_struct *dlpi_cl_rr_response;
  2992.   struct dlpi_cl_rr_results_struct *dlpi_cl_rr_results;
  2993.   
  2994.   dlpi_cl_rr_request  = 
  2995.     (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
  2996.   dlpi_cl_rr_response = 
  2997.     (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
  2998.   dlpi_cl_rr_results  = 
  2999.     (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
  3000.   
  3001.   if (debug) {
  3002.     fprintf(where,"netserver: recv_dlpi_cl_rr: entered...n");
  3003.     fflush(where);
  3004.   }
  3005.   
  3006.   /* We want to set-up the listen descriptor with all the desired */
  3007.   /* parameters and then let the initiator know that all is ready. If */
  3008.   /* socket size defaults are to be used, then the initiator will have */
  3009.   /* sent us 0's. If the descriptor sizes cannot be changed, then we will */
  3010.   /* send-back what they are. If that information cannot be determined, */
  3011.   /* then we send-back -1's for the sizes. If things go wrong for any */
  3012.   /* reason, we will drop back ten yards and punt. */
  3013.   
  3014.   /* If anything goes wrong, we want the remote to know about it. It */
  3015.   /* would be best if the error that the remote reports to the user is */
  3016.   /* the actual error we encountered, rather than some bogus unexpected */
  3017.   /* response type message. */
  3018.   
  3019.   if (debug) {
  3020.     fprintf(where,"recv_dlpi_cl_rr: setting the response type...n");
  3021.     fflush(where);
  3022.   }
  3023.   
  3024.   netperf_response.content.response_type = DLPI_CL_RR_RESPONSE;
  3025.   
  3026.   if (debug) {
  3027.     fprintf(where,"recv_dlpi_cl_rr: the response type is set...n");
  3028.     fflush(where);
  3029.   }
  3030.   /* set-up the data buffer with the requested alignment and offset */
  3031.   message = (char *)malloc(DATABUFFERLEN);
  3032.   if (message == NULL) {
  3033.     printf("malloc(%d) failed!n", DATABUFFERLEN);
  3034.     exit(1);
  3035.   }
  3036.   
  3037.   /* We now alter the message_ptr variables to be at the desired */
  3038.   /* alignments with the desired offsets. */
  3039.   
  3040.   if (debug) {
  3041.     fprintf(where,
  3042.     "recv_dlpi_cl_rr: requested recv alignment of %d offset %dn",
  3043.     dlpi_cl_rr_request->recv_alignment,
  3044.     dlpi_cl_rr_request->recv_offset);
  3045.     fprintf(where,
  3046.     "recv_dlpi_cl_rr: requested send alignment of %d offset %dn",
  3047.     dlpi_cl_rr_request->send_alignment,
  3048.     dlpi_cl_rr_request->send_offset);
  3049.     fflush(where);
  3050.   }
  3051.   recv_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->recv_alignment, dlpi_cl_rr_request->recv_offset);
  3052.   recv_message.maxlen = dlpi_cl_rr_request->request_size;
  3053.   recv_message.len    = 0;
  3054.   recv_message.buf    = recv_message_ptr;
  3055.   
  3056.   send_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->send_alignment, dlpi_cl_rr_request->send_offset);
  3057.   send_message.maxlen = dlpi_cl_rr_request->response_size;
  3058.   send_message.len    = dlpi_cl_rr_request->response_size;
  3059.   send_message.buf    = send_message_ptr;
  3060.   
  3061.   sctl_message.maxlen = BUFSIZ;
  3062.   sctl_message.len    = 0;
  3063.   sctl_message.buf    = sctl_data;
  3064.   
  3065.   rctl_message.maxlen = BUFSIZ;
  3066.   rctl_message.len    = 0;
  3067.   rctl_message.buf    = rctl_data;
  3068.   
  3069.   if (debug) {
  3070.     fprintf(where,"recv_dlpi_cl_rr: receive alignment and offset set...n");
  3071.     fprintf(where,"recv_dlpi_cl_rr: grabbing a socket...n");
  3072.     fflush(where);
  3073.   }
  3074.   
  3075.   
  3076. #ifdef __alpha
  3077.   
  3078.   /* ok - even on a DEC box, strings are strings. I din't really want */
  3079.   /* to ntohl the words of a string. since I don't want to teach the */
  3080.   /* send_ and recv_ _request and _response routines about the types, */
  3081.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  3082.   /* solution would be to use XDR, but I am still leary of being able */
  3083.   /* to find XDR libs on all platforms I want running netperf. raj */
  3084.   {
  3085.     int *charword;
  3086.     int *initword;
  3087.     int *lastword;
  3088.     
  3089.     initword = (int *) dlpi_cl_rr_request->dlpi_device;
  3090.     lastword = initword + ((dlpi_cl_rr_request->dev_name_len + 3) / 4);
  3091.     
  3092.     for (charword = initword;
  3093.  charword < lastword;
  3094.  charword++) {
  3095.       
  3096.       *charword = htonl(*charword);
  3097.     }
  3098.   }
  3099. #endif /* __alpha */
  3100.   
  3101.   data_descriptor = dl_open(dlpi_cl_rr_request->dlpi_device,
  3102.     dlpi_cl_rr_request->ppa);
  3103.   if (data_descriptor < 0) {
  3104.     netperf_response.content.serv_errno = errno;
  3105.     send_response();
  3106.     exit(1);
  3107.   }
  3108.   
  3109.   
  3110.   /* The initiator may have wished-us to modify the window */
  3111.   /* sizes. We should give it a shot. If he didn't ask us to change the */
  3112.   /* sizes, we should let him know what sizes were in use at this end. */
  3113.   /* If none of this code is compiled-in, then we will tell the */
  3114.   /* initiator that we were unable to play with the sizes by */
  3115.   /* setting the size in the response to -1. */
  3116.   
  3117. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  3118.   
  3119.   if (dlpi_cl_rr_request->recv_win_size) {
  3120.   }
  3121.   
  3122.   if (dlpi_cl_rr_request->send_win_size) {
  3123.   }
  3124.   
  3125.   /* Now, we will find-out what the sizes actually became, and report */
  3126.   /* them back to the user. If the calls fail, we will just report a -1 */
  3127.   /* back to the initiator for the buffer size. */
  3128.   
  3129. #else /* the system won't let us play with the buffers */
  3130.   
  3131.   dlpi_cl_rr_response->recv_win_size = -1;
  3132.   dlpi_cl_rr_response->send_win_size = -1;
  3133.   
  3134. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  3135.   
  3136.   /* bind the sap and retrieve the dlsap assigned by the system  */
  3137.   dlpi_cl_rr_response->station_addr_len = 14; /* arbitrary */
  3138.   if (dl_bind(data_descriptor,
  3139.       dlpi_cl_rr_request->sap,
  3140.       DL_CLDLS,
  3141.       (char *)dlpi_cl_rr_response->station_addr,
  3142.       &dlpi_cl_rr_response->station_addr_len) != 0) {
  3143.     fprintf(where,"send_dlpi_cl_rr: bind failuren");
  3144.     fflush(where);
  3145.     exit(1);
  3146.   }
  3147.   
  3148.   netperf_response.content.serv_errno   = 0;
  3149.   
  3150.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  3151.   /* then we must call the calibrate routine, which will return the max */
  3152.   /* rate back to the initiator. If the CPU was not to be measured, or */
  3153.   /* something went wrong with the calibration, we will return a 0.0 to */
  3154.   /* the initiator. */
  3155.   
  3156.   dlpi_cl_rr_response->cpu_rate = 0.0;  /* assume no cpu */
  3157.   if (dlpi_cl_rr_request->measure_cpu) {
  3158.     dlpi_cl_rr_response->measure_cpu = 1;
  3159.     dlpi_cl_rr_response->cpu_rate = calibrate_local_cpu(dlpi_cl_rr_request->cpu_rate);
  3160.   }
  3161.   
  3162.   send_response();
  3163.   
  3164.   /* Now it's time to start receiving data on the connection. We will */
  3165.   /* first grab the apropriate counters and then start receiving. */
  3166.   
  3167.   cpu_start(dlpi_cl_rr_request->measure_cpu);
  3168.   
  3169.   if (dlpi_cl_rr_request->test_length > 0) {
  3170.     times_up = 0;
  3171.     trans_remaining = 0;
  3172.     start_timer(dlpi_cl_rr_request->test_length + PAD_TIME);
  3173.   }
  3174. else {
  3175.   times_up = 1;
  3176.   trans_remaining = dlpi_cl_rr_request->test_length * -1;
  3177. }
  3178.   
  3179.   while ((!times_up) || (trans_remaining > 0)) {
  3180.     
  3181.     /* receive the request from the other side. at some point we need */
  3182.     /* to handle "logical" requests and responses which are larger */
  3183.     /* than the data link MTU */
  3184.     
  3185.     if((getmsg(data_descriptor, 
  3186.        &rctl_message,    
  3187.        &recv_message,
  3188.        &flags) != 0) || 
  3189.        (data_ind->dl_primitive != DL_UNITDATA_IND)) {
  3190.       if (errno == EINTR) {
  3191. /* Again, we have likely hit test-end time */
  3192. break;
  3193.       }
  3194.       fprintf(where,
  3195.       "dlpi_recv_cl_rr: getmsg failure: errno %d primitive 0x%xn",
  3196.       errno,
  3197.       data_ind->dl_primitive);
  3198.       fprintf(where,
  3199.       "                 recevied %u transactionsn",
  3200.       trans_received);
  3201.       fflush(where);
  3202.       netperf_response.content.serv_errno = 995;
  3203.       send_response();
  3204.       exit(1);
  3205.     }
  3206.     
  3207.     /* Now, send the response to the remote. first copy the dlsap */
  3208.     /* information from the receive to the sending control message */
  3209.     
  3210.     data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
  3211.     bcopy((char *)data_ind + data_ind->dl_src_addr_offset,
  3212.   (char *)data_req + data_req->dl_dest_addr_offset,
  3213.   data_ind->dl_src_addr_length);
  3214.     data_req->dl_dest_addr_length = data_ind->dl_src_addr_length;
  3215.     data_req->dl_primitive = DL_UNITDATA_REQ;
  3216.     /* be sure to initialize the priority fields. fix from Nicholas
  3217.        Thomas */
  3218.     data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
  3219.     data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
  3220.     sctl_message.len = sizeof(dl_unitdata_req_t) +
  3221.       data_ind->dl_src_addr_length;
  3222.     if(putmsg(data_descriptor,
  3223.       &sctl_message,
  3224.       &send_message,
  3225.       0) != 0) {
  3226.       if (errno == EINTR) {
  3227. /* We likely hit */
  3228. /* test-end time. */
  3229. break;
  3230.       }
  3231.       /* there is more we could do here, but it can wait */
  3232.       fprintf(where,
  3233.       "dlpi_recv_cl_rr: putmsg failure: errno %dn",
  3234.       errno);
  3235.       fflush(where);
  3236.       netperf_response.content.serv_errno = 993;
  3237.       send_response();
  3238.       exit(1);
  3239.     }
  3240.     
  3241.     trans_received++;
  3242.     if (trans_remaining) {
  3243.       trans_remaining--;
  3244.     }
  3245.     
  3246.     if (debug) {
  3247.       fprintf(where,
  3248.       "recv_dlpi_cl_rr: Transaction %d complete.n",
  3249.       trans_received);
  3250.       fflush(where);
  3251.     }
  3252.     
  3253.   }
  3254.   
  3255.   
  3256.   /* The loop now exits due to timeout or transaction count being */
  3257.   /* reached */
  3258.   
  3259.   cpu_stop(dlpi_cl_rr_request->measure_cpu,&elapsed_time);
  3260.   
  3261.   if (times_up) {
  3262.     /* we ended the test by time, which was at least 2 seconds */
  3263.     /* longer than we wanted to run. so, we want to subtract */
  3264.     /* PAD_TIME from the elapsed_time. */
  3265.     elapsed_time -= PAD_TIME;
  3266.   }
  3267.   /* send the results to the sender */
  3268.   
  3269.   if (debug) {
  3270.     fprintf(where,
  3271.     "recv_dlpi_cl_rr: got %d transactionsn",
  3272.     trans_received);
  3273.     fflush(where);
  3274.   }
  3275.   
  3276.   dlpi_cl_rr_results->bytes_received = (trans_received * 
  3277.    (dlpi_cl_rr_request->request_size + 
  3278.     dlpi_cl_rr_request->response_size));
  3279.   dlpi_cl_rr_results->trans_received = trans_received;
  3280.   dlpi_cl_rr_results->elapsed_time = elapsed_time;
  3281.   if (dlpi_cl_rr_request->measure_cpu) {
  3282.     dlpi_cl_rr_results->cpu_util = calc_cpu_util(elapsed_time);
  3283.   }
  3284.   
  3285.   if (debug) {
  3286.     fprintf(where,
  3287.     "recv_dlpi_cl_rr: test complete, sending results.n");
  3288.     fflush(where);
  3289.   }
  3290.   
  3291.   send_response();
  3292.   
  3293. }
  3294. int 
  3295.   recv_dlpi_co_rr()
  3296. {
  3297.   
  3298.   char  *message;
  3299.   SOCKET s_listen,data_descriptor;
  3300.   
  3301.   int measure_cpu;
  3302.   
  3303.   int   flags = 0;
  3304.   char *recv_message_ptr;
  3305.   char *send_message_ptr;
  3306.   struct strbuf send_message;
  3307.   struct strbuf recv_message;
  3308.   
  3309.   int trans_received;
  3310.   int trans_remaining;
  3311.   int request_bytes_remaining;
  3312.   int timed_out = 0;
  3313.   float elapsed_time;
  3314.   
  3315.   struct dlpi_co_rr_request_struct *dlpi_co_rr_request;
  3316.   struct dlpi_co_rr_response_struct *dlpi_co_rr_response;
  3317.   struct dlpi_co_rr_results_struct *dlpi_co_rr_results;
  3318.   
  3319.   dlpi_co_rr_request = (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
  3320.   dlpi_co_rr_response = (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
  3321.   dlpi_co_rr_results = (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
  3322.   
  3323.   if (debug) {
  3324.     fprintf(where,"netserver: recv_dlpi_co_rr: entered...n");
  3325.     fflush(where);
  3326.   }
  3327.   
  3328.   /* We want to set-up the listen socket with all the desired */
  3329.   /* parameters and then let the initiator know that all is ready. If */
  3330.   /* socket size defaults are to be used, then the initiator will have */
  3331.   /* sent us 0's. If the socket sizes cannot be changed, then we will */
  3332.   /* send-back what they are. If that information cannot be determined, */
  3333.   /* then we send-back -1's for the sizes. If things go wrong for any */
  3334.   /* reason, we will drop back ten yards and punt. */
  3335.   
  3336.   /* If anything goes wrong, we want the remote to know about it. It */
  3337.   /* would be best if the error that the remote reports to the user is */
  3338.   /* the actual error we encountered, rather than some bogus unexpected */
  3339.   /* response type message. */
  3340.   
  3341.   if (debug) {
  3342.     fprintf(where,"recv_dlpi_co_rr: setting the response type...n");
  3343.     fflush(where);
  3344.   }
  3345.   
  3346.   netperf_response.content.response_type = DLPI_CO_RR_RESPONSE;
  3347.   
  3348.   if (debug) {
  3349.     fprintf(where,"recv_dlpi_co_rr: the response type is set...n");
  3350.     fflush(where);
  3351.   }
  3352.   /* set-up the data buffer with the requested alignment and offset */
  3353.   message = (char *)malloc(DATABUFFERLEN);
  3354.   if (message == NULL) {
  3355.     printf("malloc(%d) failed!n", DATABUFFERLEN);
  3356.     exit(1);
  3357.   }
  3358.   
  3359.   /* We now alter the message_ptr variables to be at the desired */
  3360.   /* alignments with the desired offsets. */
  3361.   
  3362.   if (debug) {
  3363.     fprintf(where,
  3364.     "recv_dlpi_co_rr: requested recv alignment of %d offset %dn",
  3365.     dlpi_co_rr_request->recv_alignment,
  3366.     dlpi_co_rr_request->recv_offset);
  3367.     fprintf(where,
  3368.     "recv_dlpi_co_rr: requested send alignment of %d offset %dn",
  3369.     dlpi_co_rr_request->send_alignment,
  3370.     dlpi_co_rr_request->send_offset);
  3371.     fflush(where);
  3372.   }
  3373.   recv_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->recv_alignment, dlpi_co_rr_request->recv_offset);
  3374.   recv_message.maxlen = dlpi_co_rr_request->request_size;
  3375.   recv_message.len    = 0;
  3376.   recv_message.buf    = recv_message_ptr;
  3377.   
  3378.   send_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->send_alignment, dlpi_co_rr_request->send_offset);
  3379.   send_message.maxlen = dlpi_co_rr_request->response_size;
  3380.   send_message.len    = dlpi_co_rr_request->response_size;
  3381.   send_message.buf    = send_message_ptr;
  3382.   
  3383.   if (debug) {
  3384.     fprintf(where,"recv_dlpi_co_rr: receive alignment and offset set...n");
  3385.     fprintf(where,"recv_dlpi_co_rr: send_message.buf %x .len %d .maxlen %dn",
  3386.     send_message.buf,send_message.len,send_message.maxlen);
  3387.     fprintf(where,"recv_dlpi_co_rr: recv_message.buf %x .len %d .maxlen %dn",
  3388.     recv_message.buf,recv_message.len,recv_message.maxlen);
  3389.     fflush(where);
  3390.   }
  3391.   
  3392.   /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
  3393.   /* can put in OUR values !-) At some point, we may want to nail this */
  3394.   /* socket to a particular network-level address, but for now, */
  3395.   /* INADDR_ANY should be just fine. */
  3396.   
  3397.   /* Grab a socket to listen on, and then listen on it. */
  3398.   
  3399.   if (debug) {
  3400.     fprintf(where,"recv_dlpi_co_rr: grabbing a socket...n");
  3401.     fflush(where);
  3402.   }
  3403.   
  3404.   /* lets grab a file descriptor for a particular link */
  3405.   
  3406. #ifdef __alpha
  3407.   
  3408.   /* ok - even on a DEC box, strings are strings. I din't really want */
  3409.   /* to ntohl the words of a string. since I don't want to teach the */
  3410.   /* send_ and recv_ _request and _response routines about the types, */
  3411.   /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
  3412.   /* solution would be to use XDR, but I am still leary of being able */
  3413.   /* to find XDR libs on all platforms I want running netperf. raj */
  3414.   {
  3415.     int *charword;
  3416.     int *initword;
  3417.     int *lastword;
  3418.     
  3419.     initword = (int *) dlpi_co_rr_request->dlpi_device;
  3420.     lastword = initword + ((dlpi_co_rr_request->dev_name_len + 3) / 4);
  3421.     
  3422.     for (charword = initword;
  3423.  charword < lastword;
  3424.  charword++) {
  3425.       
  3426.       *charword = htonl(*charword);
  3427.     }
  3428.   }
  3429. #endif /* __alpha */
  3430.   
  3431.   if ((data_descriptor = dl_open(dlpi_co_rr_request->dlpi_device,
  3432.  dlpi_co_rr_request->ppa)) < 0) {
  3433.     netperf_response.content.serv_errno = errno;
  3434.     send_response();
  3435.     exit(1);
  3436.   }
  3437.   
  3438.   /* bind the file descriptor to a sap and get the resultant dlsap */
  3439.   dlpi_co_rr_response->station_addr_len = 14; /*arbitrary needs fixing */
  3440.   if (dl_bind(data_descriptor, 
  3441.               dlpi_co_rr_request->sap, 
  3442.               DL_CODLS,
  3443.               (char *)dlpi_co_rr_response->station_addr,
  3444.               &dlpi_co_rr_response->station_addr_len) != 0) {
  3445.     netperf_response.content.serv_errno = errno;
  3446.     send_response();
  3447.     exit(1);
  3448.   }
  3449.   
  3450.   /* The initiator may have wished-us to modify the socket buffer */
  3451.   /* sizes. We should give it a shot. If he didn't ask us to change the */
  3452.   /* sizes, we should let him know what sizes were in use at this end. */
  3453.   /* If none of this code is compiled-in, then we will tell the */
  3454.   /* initiator that we were unable to play with the socket buffer by */
  3455.   /* setting the size in the response to -1. */
  3456.   
  3457. #ifdef DL_HP_SET_LOCAL_WIN_REQ
  3458.   
  3459.   if (dlpi_co_rr_request->recv_win_size) {
  3460.     /* SMOP */
  3461.   }
  3462.   
  3463.   if (dlpi_co_rr_request->send_win_size) {
  3464.     /* SMOP */
  3465.   }
  3466.   
  3467.   /* Now, we will find-out what the sizes actually became, and report */
  3468.   /* them back to the user. If the calls fail, we will just report a -1 */
  3469.   /* back to the initiator for the buffer size. */
  3470.   
  3471. #else /* the system won't let us play with the buffers */
  3472.   
  3473.   dlpi_co_rr_response->recv_win_size = -1;
  3474.   dlpi_co_rr_response->send_win_size = -1;
  3475.   
  3476. #endif /* DL_HP_SET_LOCAL_WIN_REQ */
  3477.   
  3478.   /* we may have been requested to enable the copy avoidance features. */
  3479.   /* can we actually do this with DLPI, the world wonders */
  3480.   
  3481.   if (dlpi_co_rr_request->so_rcvavoid) {
  3482. #ifdef SO_RCV_COPYAVOID
  3483.     dlpi_co_rr_response->so_rcvavoid = 0;
  3484. #else
  3485.     /* it wasn't compiled in... */
  3486.     dlpi_co_rr_response->so_rcvavoid = 0;
  3487. #endif
  3488.   }
  3489.   
  3490.   if (dlpi_co_rr_request->so_sndavoid) {
  3491. #ifdef SO_SND_COPYAVOID
  3492.     dlpi_co_rr_response->so_sndavoid = 0;
  3493. #else
  3494.     /* it wasn't compiled in... */
  3495.     dlpi_co_rr_response->so_sndavoid = 0;
  3496. #endif
  3497.   }
  3498.   
  3499.   netperf_response.content.serv_errno   = 0;
  3500.   
  3501.   /* But wait, there's more. If the initiator wanted cpu measurements, */
  3502.   /* then we must call the calibrate routine, which will return the max */
  3503.   /* rate back to the initiator. If the CPU was not to be measured, or */
  3504.   /* something went wrong with the calibration, we will return a 0.0 to */
  3505.   /* the initiator. */
  3506.   
  3507.   dlpi_co_rr_response->cpu_rate = 0.0;  /* assume no cpu */
  3508.   if (dlpi_co_rr_request->measure_cpu) {
  3509.     dlpi_co_rr_response->measure_cpu = 1;
  3510.     dlpi_co_rr_response->cpu_rate = calibrate_local_cpu(dlpi_co_rr_request->cpu_rate);
  3511.   }
  3512.   
  3513.   send_response();
  3514.   
  3515.   /* accept a connection on this file descriptor. at some point, */
  3516.   /* dl_accept will "do the right thing" with the last two parms, but */
  3517.   /* for now it ignores them, so we will pass zeros. */
  3518.   
  3519.   if(dl_accept(data_descriptor, 0, 0) != 0) {
  3520.     fprintf(where,
  3521.     "recv_dlpi_co_rr: error in accept, errno %dn",
  3522.     errno);
  3523.     fflush(where);
  3524.     netperf_response.content.serv_errno = errno;
  3525.     send_response();
  3526.     exit(1);
  3527.   }
  3528.   
  3529.   if (debug) {
  3530.     fprintf(where,
  3531.     "recv_dlpi_co_rr: accept completes on the data connection.n");
  3532.     fflush(where);
  3533.   }
  3534.   
  3535.   /* Now it's time to start receiving data on the connection. We will */
  3536.   /* first grab the apropriate counters and then start grabbing. */
  3537.   
  3538.   cpu_start(dlpi_co_rr_request->measure_cpu);
  3539.   
  3540.   /* The loop will exit when the sender does a shutdown, which will */
  3541.   /* return a length of zero   */
  3542.   
  3543.   if (dlpi_co_rr_request->test_length > 0) {
  3544.     times_up = 0;
  3545.     trans_remaining = 0;
  3546.     start_timer(dlpi_co_rr_request->test_length + PAD_TIME);
  3547.   }
  3548. else {
  3549.   times_up = 1;
  3550.   trans_remaining = dlpi_co_rr_request->test_length * -1;
  3551. }
  3552.   
  3553.   while ((!times_up) || (trans_remaining > 0)) {
  3554.     request_bytes_remaining = dlpi_co_rr_request->request_size;
  3555.     
  3556.     /* receive the request from the other side. there needs to be some */
  3557.     /* more login in place for handling messages larger than link mtu, */
  3558.     /* but that can wait for later */
  3559.     while(request_bytes_remaining > 0) {
  3560.       if((getmsg(data_descriptor,
  3561.  0,
  3562.  &recv_message,
  3563.  &flags)) < 0) {
  3564. if (errno == EINTR) {
  3565.   /* the timer popped */
  3566.   timed_out = 1;
  3567.   break;
  3568. }
  3569.         if (debug) {
  3570.   fprintf(where,"failed getmsg call errno %dn",errno);
  3571.   fprintf(where,"recv_message.len %dn",recv_message.len);
  3572.   fprintf(where,"send_message.len %dn",send_message.len);
  3573.   fflush(where);
  3574.         }
  3575. netperf_response.content.serv_errno = errno;
  3576. send_response();
  3577. exit(1);
  3578.       }
  3579.       else {
  3580. request_bytes_remaining -= recv_message.len;
  3581.       }
  3582.     }
  3583.     
  3584.     if (timed_out) {
  3585.       /* we hit the end of the test based on time - lets bail out of */
  3586.       /* here now... */ 
  3587.       break;
  3588.     }
  3589.     
  3590.     if (debug) {
  3591.       fprintf(where,"recv_message.len %dn",recv_message.len);
  3592.       fprintf(where,"send_message.len %dn",send_message.len);
  3593.       fflush(where);
  3594.     }
  3595.     
  3596.     /* Now, send the response to the remote */
  3597.     if((putmsg(data_descriptor,
  3598.        0,
  3599.        &send_message,
  3600.        0)) != 0) {
  3601.       if (errno == EINTR) {
  3602. /* the test timer has popped */
  3603. timed_out = 1;
  3604. break;
  3605.       }
  3606.       netperf_response.content.serv_errno = 994;
  3607.       send_response();
  3608.       exit(1);
  3609.     }
  3610.     
  3611.     trans_received++;
  3612.     if (trans_remaining) {
  3613.       trans_remaining--;
  3614.     }
  3615.     
  3616.     if (debug) {
  3617.       fprintf(where,
  3618.       "recv_dlpi_co_rr: Transaction %d completen",
  3619.       trans_received);
  3620.       fflush(where);
  3621.     }
  3622.   }
  3623.   
  3624.   
  3625.   /* The loop now exits due to timeout or transaction count being */
  3626.   /* reached */
  3627.   
  3628.   cpu_stop(dlpi_co_rr_request->measure_cpu,&elapsed_time);
  3629.   
  3630.   if (timed_out) {
  3631.     /* we ended the test by time, which was at least 2 seconds */
  3632.     /* longer than we wanted to run. so, we want to subtract */
  3633.     /* PAD_TIME from the elapsed_time. */
  3634.     elapsed_time -= PAD_TIME;
  3635.   }
  3636.   /* send the results to the sender */
  3637.   
  3638.   if (debug) {
  3639.     fprintf(where,
  3640.     "recv_dlpi_co_rr: got %d transactionsn",
  3641.     trans_received);
  3642.     fflush(where);
  3643.   }
  3644.   
  3645.   dlpi_co_rr_results->bytes_received = (trans_received * 
  3646.    (dlpi_co_rr_request->request_size + 
  3647.     dlpi_co_rr_request->response_size));
  3648.   dlpi_co_rr_results->trans_received = trans_received;
  3649.   dlpi_co_rr_results->elapsed_time = elapsed_time;
  3650.   if (dlpi_co_rr_request->measure_cpu) {
  3651.     dlpi_co_rr_results->cpu_util = calc_cpu_util(elapsed_time);
  3652.   }
  3653.   
  3654.   if (debug) {
  3655.     fprintf(where,
  3656.     "recv_dlpi_co_rr: test complete, sending results.n");
  3657.     fflush(where);
  3658.   }
  3659.   
  3660.   send_response();
  3661.   
  3662. }
  3663. /* this routine will display the usage string for the DLPI tests */
  3664. void
  3665.   print_dlpi_usage()
  3666. {
  3667.   fwrite(dlpi_usage, sizeof(char), strlen(dlpi_usage), stdout);
  3668. }
  3669. /* this routine will scan the command line for DLPI test arguments */
  3670. void
  3671.   scan_dlpi_args(int argc, char *argv[])
  3672. {
  3673.   extern int optind, opterrs;  /* index of first unused arg  */
  3674.   extern char *optarg;   /* pointer to option string */
  3675.   
  3676.   int c;
  3677.   
  3678.   char arg1[BUFSIZ],  /* argument holders */
  3679.   arg2[BUFSIZ];
  3680.   if (no_control) {
  3681.     fprintf(where,
  3682.     "The DLPI tests do not know how to run with no control connectionn");
  3683.     exit(-1);
  3684.   }
  3685.   
  3686.   /* Go through all the command line arguments and break them */
  3687.   /* out. For those options that take two parms, specifying only */
  3688.   /* the first will set both to that value. Specifying only the */
  3689.   /* second will leave the first untouched. To change only the */
  3690.   /* first, use the form first, (see the routine break_args.. */
  3691.   
  3692. #define DLPI_ARGS "D:hM:m:p:r:s:W:w:"
  3693.   
  3694.   while ((c= getopt(argc, argv, DLPI_ARGS)) != EOF) {
  3695.     switch (c) {
  3696.     case '?':
  3697.     case 'h':
  3698.       print_dlpi_usage();
  3699.       exit(1);
  3700.     case 'D':
  3701.       /* set the dlpi device file name(s) */
  3702.       break_args(optarg,arg1,arg2);
  3703.       if (arg1[0])
  3704. strcpy(loc_dlpi_device,arg1);
  3705.       if (arg2[0])
  3706. strcpy(rem_dlpi_device,arg2);
  3707.       break;
  3708.     case 'm':
  3709.       /* set the send size */
  3710.       send_size = atoi(optarg);
  3711.       break;
  3712.     case 'M':
  3713.       /* set the recv size */
  3714.       recv_size = atoi(optarg);
  3715.       break;
  3716.     case 'p':
  3717.       /* set the local/remote ppa */
  3718.       break_args(optarg,arg1,arg2);
  3719.       if (arg1[0])
  3720. loc_ppa = atoi(arg1);
  3721.       if (arg2[0])
  3722. rem_ppa = atoi(arg2);
  3723.       break;
  3724.     case 'r':
  3725.       /* set the request/response sizes */
  3726.       break_args(optarg,arg1,arg2);
  3727.       if (arg1[0])
  3728. req_size = atoi(arg1);
  3729.       if (arg2[0])
  3730. rsp_size = atoi(arg2);
  3731.       break;
  3732.     case 's':
  3733.       /* set the 802.2 sap for the test */
  3734.       dlpi_sap = atoi(optarg);
  3735.       break;
  3736.     case 'w':
  3737.       /* set local window sizes */
  3738.       break_args(optarg,arg1,arg2);
  3739.       if (arg1[0])
  3740. lsw_size = atoi(arg1);
  3741.       if (arg2[0])
  3742. lrw_size = atoi(arg2);
  3743.       break;
  3744.     case 'W':
  3745.       /* set remote window sizes */
  3746.       break_args(optarg,arg1,arg2);
  3747.       if (arg1[0])
  3748. rsw_size = atoi(arg1);
  3749.       if (arg2[0])
  3750. rrw_size = atoi(arg2);
  3751.       break;
  3752.     };
  3753.   }
  3754. }
  3755. #endif /* WANT_DLPI */