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