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