• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /****************************************************************/
3 /*								*/
4 /*	nettest_dlpi.c						*/
5 /*								*/
6 /*	the actual test routines...				*/
7 /*								*/
8 /*	send_dlpi_co_stream()	perform a CO DLPI stream test	*/
9 /*	recv_dlpi_co_stream()					*/
10 /*	send_dlpi_co_rr()	perform a CO DLPI req/res	*/
11 /*	recv_dlpi_co_rr()					*/
12 /*	send_dlpi_cl_stream()	perform a CL DLPI stream test	*/
13 /*	recv_dlpi_cl_stream()					*/
14 /*	send_dlpi_cl_rr()	perform a CL DLPI req/res	*/
15 /*	recv_dlpi_cl_rr()					*/
16 /*								*/
17 /****************************************************************/
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #ifdef WANT_DLPI
24 char	nettest_dlpi_id[]="\
25 @(#)nettest_dlpi.c (c) Copyright 1993-2012 Hewlett-Packard Co. Version 2.6.0";
26 
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <malloc.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/poll.h>
38 #ifdef __osf__
39 #include <sys/dlpihdr.h>
40 #else /* __osf__ */
41 #include <sys/dlpi.h>
42 #ifdef __hpux__
43 #include <sys/dlpi_ext.h>
44 #endif /* __hpux__ */
45 #endif /* __osf__ */
46 
47 #include "netlib.h"
48 #include "netsh.h"
49 #include "nettest_dlpi.h"
50 
51 /* some stuff for DLPI control messages */
52 #define DLPI_DATA_SIZE 2048
53 
54 unsigned long control_data[DLPI_DATA_SIZE];
55 struct 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 
60 static 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 
70 int
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 
76 char loc_dlpi_device[32] = "/dev/dlpi";
77 char rem_dlpi_device[32] = "/dev/dlpi";
78 
79 char dlpi_usage[] = "\n\
80 Usage: netperf [global options] -- [test options] \n\
81 \n\
82 CO/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\
94 For those options taking two parms, at least one must be specified;\n\
95 specifying one value without a comma will set both parms to that\n\
96 value, specifying a value with a leading comma will set just the second\n\
97 parm, a value with a trailing comma will set just the first. To set\n\
98 each parm to unique values, specify both and separate them with a\n\
99 comma.\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 
107 int
put_control(fd,len,pri,ack)108 put_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 
145 int
dl_open(char devfile[],int ppa)146 dl_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 
170 int
dl_bind(int fd,int sap,int mode,char * dlsap_ptr,int * dlsap_len)171 dl_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 
206 int
dl_connect(int fd,unsigned char * remote_addr,int remote_addr_len)207 dl_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 
276 int
dl_accept(fd,remote_addr,remote_addr_len)277 dl_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 
310 int
dl_set_window(fd,window)311 dl_set_window(fd, window)
312      int fd, window;
313 {
314   return(0);
315 }
316 
317 void
dl_stats(fd)318 dl_stats(fd)
319      int fd;
320 {
321 }
322 
323 int
dl_send_disc(fd)324 dl_send_disc(fd)
325      int fd;
326 {
327 }
328 
329 int
dl_recv_disc(fd)330 dl_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 
342 void
send_dlpi_co_stream()343 send_dlpi_co_stream()
344 {
345 
346   char *tput_title = "\
347 Recv   Send    Send                          \n\
348 Window Window  Message  Elapsed              \n\
349 Size   Size    Size     Time     Throughput  \n\
350 frames 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 = "\
359 Recv   Send    Send                          Utilization    Service Demand\n\
360 Window Window  Message  Elapsed              Send   Recv    Send    Recv\n\
361 Size   Size    Size     Time     Throughput  local  remote  local   remote\n\
362 frames 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\
371 Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
372 Local  Remote  Local  Remote  Xfered   Per                 Per\n\
373 Send   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 
927 int
recv_dlpi_co_stream()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 
send_dlpi_co_rr(char remote_host[])1235 int 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 
1817 void
send_dlpi_cl_stream(char remote_host[])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\
1827 Size    Size     Time         Okay Errors   Throughput\n\
1828 frames  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\
1840 Size    Size     Time         Okay Errors   Throughput   Util    Demand\n\
1841 frames  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 
2300 int
recv_dlpi_cl_stream()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 
send_dlpi_cl_rr(char remote_host[])2587 int send_dlpi_cl_rr(char remote_host[])
2588 {
2589 
2590   char *tput_title = "\
2591 Local /Remote\n\
2592 Window Size   Request  Resp.   Elapsed  Trans.\n\
2593 Send   Recv   Size     Size    Time     Rate         \n\
2594 frames 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 = "\
2605 Local /Remote\n\
2606 Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
2607 Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
2608 frames 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 = "\
2620 Alignment      Offset\n\
2621 Local  Remote  Local  Remote\n\
2622 Send   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 
3230 int
recv_dlpi_cl_rr()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   }
3444 else {
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 
3566 int
recv_dlpi_co_rr()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   }
3822 else {
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 */
3941 void
print_dlpi_usage()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 */
3950 void
scan_dlpi_args(int argc,char * argv[])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