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
12char	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
82static char
83  path_prefix[32];
84
85static 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
100char unix_usage[] = "\n\
101Usage: netperf [global options] -- [test options] \n\
102\n\
103STREAM/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\
112For those options taking two parms, at least one must be specified;\n\
113specifying one value without a comma will set both parms to that\n\
114value, specifying a value with a leading comma will set just the second\n\
115parm, a value with a trailing comma will set just the first. To set\n\
116each parm to unique values, specify both and separate them with a\n\
117comma.\n";
118
119 /* this routing initializes all the test specific variables */
120
121static void
122init_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 */
146SOCKET
147create_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
198void
199send_stream_stream(char remote_host[])
200{
201
202  char *tput_title = "\
203Recv   Send    Send                          \n\
204Socket Socket  Message  Elapsed              \n\
205Size   Size    Size     Time     Throughput  \n\
206bytes  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 = "\
215Recv   Send    Send                          Utilization    Service Demand\n\
216Socket Socket  Message  Elapsed              Send   Recv    Send    Recv\n\
217Size   Size    Size     Time     Throughput  local  remote  local   remote\n\
218bytes  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\
227Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
228Local  Remote  Local  Remote  Xfered   Per                 Per\n\
229Send   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
704void
705recv_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
1028void
1029send_stream_rr(char remote_host[])
1030{
1031
1032  char *tput_title = "\
1033Local /Remote\n\
1034Socket Size   Request  Resp.   Elapsed  Trans.\n\
1035Send   Recv   Size     Size    Time     Rate         \n\
1036bytes  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 = "\
1047Local /Remote\n\
1048Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
1049Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
1050bytes  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 = "\
1062Alignment      Offset\n\
1063Local  Remote  Local  Remote\n\
1064Send   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
1514void
1515send_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\
1524Size    Size     Time         Okay Errors   Throughput\n\
1525bytes   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\
1537Size    Size     Time         Okay Errors   Throughput   Util    Demand\n\
1538bytes   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
1926void
1927recv_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
2175void
2176send_dg_rr(char remote_host[])
2177{
2178
2179  char *tput_title = "\
2180Local /Remote\n\
2181Socket Size   Request  Resp.   Elapsed  Trans.\n\
2182Send   Recv   Size     Size    Time     Rate         \n\
2183bytes  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 = "\
2194Local /Remote\n\
2195Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
2196Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
2197bytes  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. */
2734void
2735recv_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
3022void
3023recv_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
3351void
3352print_unix_usage()
3353{
3354
3355  fwrite(unix_usage, sizeof(char), strlen(unix_usage), stdout);
3356  exit(1);
3357
3358}
3359void
3360scan_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