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