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