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