1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#ifdef WANT_XTI
6#ifndef lint
7char	nettest_xti_id[]="\
8@(#)nettest_xti.c (c) Copyright 1995-2007 Hewlett-Packard Co. Version 2.4.3";
9#else
10#define DIRTY
11#define WANT_HISTOGRAM
12#define WANT_INTERVALS
13#endif /* lint */
14/****************************************************************/
15/*								*/
16/*	nettest_xti.c						*/
17/*								*/
18/*      the XTI args parsing routine...                         */
19/*                                                              */
20/*      scan_xti_args()                                         */
21/*                                                              */
22/*	the actual test routines...				*/
23/*								*/
24/*	send_xti_tcp_stream()	perform a tcp stream test	*/
25/*	recv_xti_tcp_stream()					*/
26/*	send_xti_tcp_rr()	perform a tcp request/response	*/
27/*	recv_xti_tcp_rr()					*/
28/*      send_xti_tcp_conn_rr()  an RR test including connect    */
29/*      recv_xti_tcp_conn_rr()                                  */
30/*	send_xti_udp_stream()	perform a udp stream test	*/
31/*	recv_xti_udp_stream()					*/
32/*	send_xti_udp_rr()	perform a udp request/response	*/
33/*	recv_xti_udp_rr()					*/
34/*								*/
35/****************************************************************/
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#include <sys/types.h>
42#include <fcntl.h>
43#ifndef WIN32
44#include <sys/ipc.h>
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <netdb.h>
48#include <errno.h>
49#include <signal.h>
50#else /* WIN32 */
51#include <process.h>
52#include <winsock2.h>
53#include <windows.h>
54#endif /* WIN32 */
55#include <stdio.h>
56#include <time.h>
57#include <malloc.h>
58 /* xti.h should be included *after* in.h because there are name */
59 /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */
60 /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */
61#include <xti.h>
62
63#include "netlib.h"
64#include "netsh.h"
65#include "nettest_xti.h"
66
67#ifdef WANT_HISTOGRAM
68#ifdef __sgi
69#include <sys/time.h>
70#endif /* __sgi */
71#include "hist.h"
72#endif /* WANT_HISTOGRAM */
73
74
75
76 /* these variables are specific to the XTI sockets tests. declare */
77 /* them static to make them global only to this file. */
78
79static int
80  rss_size,		/* remote socket send buffer size	*/
81  rsr_size,		/* remote socket recv buffer size	*/
82  lss_size,		/* local  socket send buffer size 	*/
83  lsr_size,		/* local  socket recv buffer size 	*/
84  req_size = 1,		/* request size                   	*/
85  rsp_size = 1,		/* response size			*/
86  send_size,		/* how big are individual sends		*/
87  recv_size;		/* how big are individual receives	*/
88
89static  int   confidence_iteration;
90static  char  local_cpu_method;
91static  char  remote_cpu_method;
92
93 /* different options for the xti				*/
94
95static int
96  loc_nodelay,		/* don't/do use NODELAY	locally		*/
97  rem_nodelay,		/* don't/do use NODELAY remotely	*/
98  loc_sndavoid,		/* avoid send copies locally		*/
99  loc_rcvavoid,		/* avoid recv copies locally		*/
100  rem_sndavoid,		/* avoid send copies remotely		*/
101  rem_rcvavoid;		/* avoid recv_copies remotely		*/
102
103static struct t_info info_struct;
104
105#ifdef WANT_HISTOGRAM
106#ifdef HAVE_GETHRTIME
107hrtime_t time_one;
108hrtime_t time_two;
109#else
110static struct timeval time_one;
111static struct timeval time_two;
112#endif /* HAVE_GETHRTIME */
113static HIST time_hist;
114#endif /* WANT_HISTOGRAM */
115
116static char loc_xti_device[32] = "/dev/tcp";
117static char rem_xti_device[32] = "/dev/tcp";
118
119static int  xti_flags = 0;
120
121char xti_usage[] = "\n\
122Usage: netperf [global options] -- [test options] \n\
123\n\
124TCP/UDP XTI API Test Options:\n\
125    -D [L][,R]        Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\
126    -h                Display this text\n\
127    -m bytes          Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
128    -M bytes          Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
129    -r bytes          Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\
130    -R bytes          Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\
131    -s send[,recv]    Set local socket send/recv buffer sizes\n\
132    -S send[,recv]    Set remote socket send/recv buffer sizes\n\
133    -X dev[,dev]      Set the local/remote XTI device file name\n\
134\n\
135For those options taking two parms, at least one must be specified;\n\
136specifying one value without a comma will set both parms to that\n\
137value, specifying a value with a leading comma will set just the second\n\
138parm, a value with a trailing comma will set just the first. To set\n\
139each parm to unique values, specify both and separate them with a\n\
140comma.\n";
141
142
143 /* This routine is intended to retrieve interesting aspects of tcp */
144 /* for the data connection. at first, it attempts to retrieve the */
145 /* maximum segment size. later, it might be modified to retrieve */
146 /* other information, but it must be information that can be */
147 /* retrieved quickly as it is called during the timing of the test. */
148 /* for that reason, a second routine may be created that can be */
149 /* called outside of the timing loop */
150void
151get_xti_info(socket, info_struct)
152     int socket;
153     struct t_info *info_struct;
154{
155
156}
157
158
159 /* This routine will create a data (listen) socket with the apropriate */
160 /* options set and return it to the caller. this replaces all the */
161 /* duplicate code in each of the test routines and should help make */
162 /* things a little easier to understand. since this routine can be */
163 /* called by either the netperf or netserver programs, all output */
164 /* should be directed towards "where." family is generally AF_INET, */
165 /* and type will be either SOCK_STREAM or SOCK_DGRAM */
166SOCKET
167create_xti_endpoint(char *name)
168{
169
170  SOCKET temp_socket;
171
172  struct t_optmgmt *opt_req;  /* we request an option */
173  struct t_optmgmt *opt_ret;  /* it tells us what we got */
174
175  /* we use this to pass-in BSD-like socket options through t_optmgmt. */
176  /* it ends up being about as clear as mud. raj 2/95 */
177  struct sock_option {
178    struct t_opthdr myopthdr;
179    long value;
180  } *sock_option;
181
182  if (debug) {
183    fprintf(where,"create_xti_endpoint: attempting to open %s\n",
184	    name);
185    fflush(where);
186  }
187
188  /*set up the data socket                        */
189  temp_socket = t_open(name,O_RDWR,NULL);
190
191  if (temp_socket == INVALID_SOCKET){
192    fprintf(where,
193	    "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n",
194	    name,
195	    errno,
196	    t_errno);
197    fflush(where);
198    exit(1);
199  }
200
201  if (debug) {
202    fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket);
203    fflush(where);
204  }
205
206  /* allocate what we need for option mgmt */
207  if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
208      NULL) {
209    fprintf(where,
210	    "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n",
211	    errno);
212    fflush(where);
213    exit(1);
214  }
215
216  if (debug) {
217    fprintf(where,
218	    "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n",
219	    opt_req->opt.buf,
220	    opt_req->opt.maxlen,
221	    opt_req->opt.len);
222
223    fflush(where);
224  }
225
226  if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
227      NULL) {
228    fprintf(where,
229	    "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n",
230	    errno);
231    fflush(where);
232    exit(1);
233  }
234
235  if (debug) {
236    fprintf(where,
237	    "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n",
238	    opt_ret->opt.buf,
239	    opt_ret->opt.maxlen,
240	    opt_ret->opt.len);
241    fflush(where);
242  }
243
244  /* Modify the local socket size. The reason we alter the send buffer */
245  /* size here rather than when the connection is made is to take care */
246  /* of decreases in buffer size. Decreasing the window size after */
247  /* connection establishment is a TCP no-no. Also, by setting the */
248  /* buffer (window) size before the connection is established, we can */
249  /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
250  /* the minimum receive buffer size at each half of the connection. */
251  /* This is why we are altering the receive buffer size on the sending */
252  /* size of a unidirectional transfer. If the user has not requested */
253  /* that the socket buffers be altered, we will try to find-out what */
254  /* their values are. If we cannot touch the socket buffer in any way, */
255  /* we will set the values to -1 to indicate that.  */
256
257#ifdef XTI_SNDBUF
258  if (lss_size > 0) {
259    /* we want to "negotiate" the option */
260    opt_req->flags = T_NEGOTIATE;
261  }
262  else {
263    /* we want to accept the default, and know what it is. I assume */
264    /* that when nothing has been changed, that T_CURRENT will return */
265    /* the same as T_DEFAULT raj 3/95 */
266    opt_req->flags = T_CURRENT;
267  }
268
269  /* the first part is for the netbuf that holds the option we want */
270  /* to negotiate or check */
271  /* the buffer of the netbuf points at the socket options structure */
272
273  /* we assume that the t_alloc call allocated a buffer that started */
274  /* on a proper alignment */
275  sock_option = (struct sock_option *)opt_req->opt.buf;
276
277  /* and next, set the fields in the sock_option structure */
278  sock_option->myopthdr.level = XTI_GENERIC;
279  sock_option->myopthdr.name  = XTI_SNDBUF;
280  sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
281  sock_option->value        = lss_size;
282
283  opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
284
285  /* now, set-up the stuff to return the value in the end */
286  /* we assume that the t_alloc call allocated a buffer that started */
287  /* on a proper alignment */
288  sock_option = (struct sock_option *)opt_ret->opt.buf;
289
290  /* finally, call t_optmgmt. clear as mud. */
291  if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
292    fprintf(where,
293	    "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n",
294	    t_errno);
295    fflush(where);
296    exit(1);
297  }
298
299  if (sock_option->myopthdr.status == T_SUCCESS) {
300    lss_size = sock_option->value;
301  }
302  else {
303    fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x",
304	    sock_option->myopthdr.status);
305    fprintf(where," value %d\n",
306	    sock_option->value);
307    fflush(where);
308    lss_size = -1;
309  }
310
311  if (lsr_size > 0) {
312    /* we want to "negotiate" the option */
313    opt_req->flags = T_NEGOTIATE;
314  }
315  else {
316    /* we want to accept the default, and know what it is. I assume */
317    /* that when nothing has been changed, that T_CURRENT will return */
318    /* the same as T_DEFAULT raj 3/95 */
319    opt_req->flags = T_CURRENT;
320  }
321
322  /* the first part is for the netbuf that holds the option we want */
323  /* to negotiate or check */
324  /* the buffer of the netbuf points at the socket options structure */
325
326  /* we assume that the t_alloc call allocated a buffer that started */
327  /* on a proper alignment */
328  sock_option = (struct sock_option *)opt_req->opt.buf;
329
330  /* and next, set the fields in the sock_option structure */
331  sock_option->myopthdr.level = XTI_GENERIC;
332  sock_option->myopthdr.name  = XTI_RCVBUF;
333  sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
334  sock_option->value        = lsr_size;
335
336  opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
337
338  /* now, set-up the stuff to return the value in the end */
339  /* we assume that the t_alloc call allocated a buffer that started */
340  /* on a proper alignment */
341  sock_option = (struct sock_option *)opt_ret->opt.buf;
342
343  /* finally, call t_optmgmt. clear as mud. */
344  if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
345    fprintf(where,
346	    "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n",
347	    t_errno);
348    fflush(where);
349    exit(1);
350  }
351  lsr_size = sock_option->value;
352
353  /* this needs code */
354
355  if (debug) {
356    fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n");
357    fprintf(where,"                       send: %d recv: %d\n",
358	    lss_size,lsr_size);
359    fflush(where);
360  }
361
362#else /* XTI_SNDBUF */
363
364  lss_size = -1;
365  lsr_size = -1;
366
367#endif /* XTI_SNDBUF */
368
369  /* now, we may wish to enable the copy avoidance features on the */
370  /* local system. of course, this may not be possible... */
371
372  if (loc_rcvavoid) {
373    fprintf(where,
374	    "netperf: create_xti_endpoint: Could not enable receive copy avoidance");
375    fflush(where);
376    loc_rcvavoid = 0;
377  }
378
379  if (loc_sndavoid) {
380    fprintf(where,
381	    "netperf: create_xti_endpoint: Could not enable send copy avoidance");
382    fflush(where);
383    loc_sndavoid = 0;
384  }
385
386  /* Now, we will see about setting the TCP_NODELAY flag on the local */
387  /* socket. We will only do this for those systems that actually */
388  /* support the option. If it fails, note the fact, but keep going. */
389  /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
390  /* will cause an error to be displayed */
391
392#ifdef TCP_NODELAY
393  if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) ||
394      (strcmp(test_name,"XTI_TCP_RR") == 0) ||
395      (strcmp(test_name,"XTI_TCP_CRR") == 0)) {
396    if (loc_nodelay) {
397      /* we want to "negotiate" the option */
398      opt_req->flags = T_NEGOTIATE;
399    }
400    else {
401      /* we want to accept the default, and know what it is. I assume */
402      /* that when nothing has been changed, that T_CURRENT will return */
403      /* the same as T_DEFAULT raj 3/95 */
404      opt_req->flags = T_CURRENT;
405    }
406
407    /* the first part is for the netbuf that holds the option we want */
408    /* to negotiate or check the buffer of the netbuf points at the */
409    /* socket options structure */
410
411    /* we assume that the t_alloc call allocated a buffer that started */
412    /* on a proper alignment */
413    sock_option = (struct sock_option *)opt_req->opt.buf;
414
415    /* and next, set the fields in the sock_option structure */
416    sock_option->myopthdr.level = INET_TCP;
417    sock_option->myopthdr.name  = TCP_NODELAY;
418    sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
419    sock_option->value          = T_YES;
420
421    opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
422
423    /* now, set-up the stuff to return the value in the end */
424    /* we assume that the t_alloc call allocated a buffer that started */
425    /* on a proper alignment */
426    sock_option = (struct sock_option *)opt_ret->opt.buf;
427
428    /* finally, call t_optmgmt. clear as mud. */
429    if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
430      fprintf(where,
431	      "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n",
432	      errno,
433	      t_errno);
434      fflush(where);
435      exit(1);
436    }
437    loc_nodelay = sock_option->value;
438  }
439#else /* TCP_NODELAY */
440
441  loc_nodelay = 0;
442
443#endif /* TCP_NODELAY */
444
445  return(temp_socket);
446
447}
448
449
450/* This routine implements the TCP unidirectional data transfer test */
451/* (a.k.a. stream) for the xti interface. It receives its */
452/* parameters via global variables from the shell and writes its */
453/* output to the standard output. */
454
455
456void
457send_xti_tcp_stream(char remote_host[])
458{
459
460  char *tput_title = "\
461Recv   Send    Send                          \n\
462Socket Socket  Message  Elapsed              \n\
463Size   Size    Size     Time     Throughput  \n\
464bytes  bytes   bytes    secs.    %s/sec  \n\n";
465
466  char *tput_fmt_0 =
467    "%7.2f\n";
468
469  char *tput_fmt_1 =
470    "%6d %6d %6d    %-6.2f   %7.2f   \n";
471
472  char *cpu_title = "\
473Recv   Send    Send                          Utilization       Service Demand\n\
474Socket Socket  Message  Elapsed              Send     Recv     Send    Recv\n\
475Size   Size    Size     Time     Throughput  local    remote   local   remote\n\
476bytes  bytes   bytes    secs.    %-8.8s/s  %% %c      %% %c      us/KB   us/KB\n\n";
477
478  char *cpu_fmt_0 =
479    "%6.3f %c\n";
480
481  char *cpu_fmt_1 =
482    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f\n";
483
484  char *ksink_fmt = "\n\
485Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
486Local  Remote  Local  Remote  Xfered   Per                 Per\n\
487Send   Recv    Send   Recv             Send (avg)          Recv (avg)\n\
488%5d   %5d  %5d   %5d %6.4g  %6.2f    %6d   %6.2f %6d\n";
489
490  char *ksink_fmt2 = "\n\
491Maximum\n\
492Segment\n\
493Size (bytes)\n\
494%6d\n";
495
496
497  float			elapsed_time;
498
499#ifdef WANT_INTERVALS
500  int interval_count;
501  sigset_t signal_set;
502#endif
503
504  /* what we want is to have a buffer space that is at least one */
505  /* send-size greater than our send window. this will insure that we */
506  /* are never trying to re-use a buffer that may still be in the hands */
507  /* of the transport. This buffer will be malloc'd after we have found */
508  /* the size of the local senc socket buffer. We will want to deal */
509  /* with alignment and offset concerns as well. */
510
511  int	*message_int_ptr;
512
513  struct ring_elt *send_ring;
514
515  int len;
516  unsigned int nummessages;
517  SOCKET send_socket;
518  int bytes_remaining;
519  int tcp_mss = -1;  /* possibly uninitialized on printf far below */
520
521  /* with links like fddi, one can send > 32 bits worth of bytes */
522  /* during a test... ;-) at some point, this should probably become a */
523  /* 64bit integral type, but those are not entirely common yet */
524
525  double	bytes_sent;
526
527  float	local_cpu_utilization;
528  float	local_service_demand;
529  float	remote_cpu_utilization;
530  float	remote_service_demand;
531
532  double	thruput;
533
534  /* some addressing information */
535  struct	hostent	        *hp;
536  struct	sockaddr_in	server;
537  unsigned      int             addr;
538
539  struct t_call server_call;
540
541  struct	xti_tcp_stream_request_struct	*xti_tcp_stream_request;
542  struct	xti_tcp_stream_response_struct	*xti_tcp_stream_response;
543  struct	xti_tcp_stream_results_struct	*xti_tcp_stream_result;
544
545  xti_tcp_stream_request  =
546    (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
547  xti_tcp_stream_response =
548    (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
549  xti_tcp_stream_result   =
550    (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
551
552#ifdef WANT_HISTOGRAM
553  time_hist = HIST_new();
554#endif /* WANT_HISTOGRAM */
555  /* since we are now disconnected from the code that established the */
556  /* control socket, and since we want to be able to use different */
557  /* protocols and such, we are passed the name of the remote host and */
558  /* must turn that into the test specific addressing information. */
559
560  bzero((char *)&server,
561	sizeof(server));
562
563  /* it would seem that while HP-UX will allow an IP address (as a */
564  /* string) in a call to gethostbyname, other, less enlightened */
565  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
566  /* order changed to check for IP address first. raj 7/96 */
567
568  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
569    /* it was not an IP address, try it as a name */
570    if ((hp = gethostbyname(remote_host)) == NULL) {
571      /* we have no idea what it is */
572      fprintf(where,
573	      "establish_control: could not resolve the destination %s\n",
574	      remote_host);
575      fflush(where);
576      exit(1);
577    }
578    else {
579      /* it was a valid remote_host */
580      bcopy(hp->h_addr,
581	    (char *)&server.sin_addr,
582	    hp->h_length);
583      server.sin_family = hp->h_addrtype;
584    }
585  }
586  else {
587    /* it was a valid IP address */
588    server.sin_addr.s_addr = addr;
589    server.sin_family = AF_INET;
590  }
591
592  if ( print_headers ) {
593    /* we want to have some additional, interesting information in */
594    /* the headers. we know some of it here, but not all, so we will */
595    /* only print the test title here and will print the results */
596    /* titles after the test is finished */
597    fprintf(where,"XTI TCP STREAM TEST");
598    fprintf(where," to %s", remote_host);
599    if (iteration_max > 1) {
600      fprintf(where,
601	      " : +/-%3.1f%% @ %2d%% conf.",
602	      interval/0.02,
603	      confidence_level);
604      }
605    if (loc_nodelay || rem_nodelay) {
606      fprintf(where," : nodelay");
607    }
608    if (loc_sndavoid ||
609	loc_rcvavoid ||
610	rem_sndavoid ||
611	rem_rcvavoid) {
612      fprintf(where," : copy avoidance");
613    }
614#ifdef WANT_HISTOGRAM
615    fprintf(where," : histogram");
616#endif /* WANT_HISTOGRAM */
617#ifdef WANT_INTERVALS
618    fprintf(where," : interval");
619#endif /* WANT_INTERVALS */
620#ifdef DIRTY
621    fprintf(where," : dirty data");
622#endif /* DIRTY */
623    fprintf(where,"\n");
624  }
625
626  send_ring = NULL;
627  confidence_iteration = 1;
628  init_stat();
629
630  /* we have a great-big while loop which controls the number of times */
631  /* we run a particular test. this is for the calculation of a */
632  /* confidence interval (I really should have stayed awake during */
633  /* probstats :). If the user did not request confidence measurement */
634  /* (no confidence is the default) then we will only go though the */
635  /* loop once. the confidence stuff originates from the folks at IBM */
636
637  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
638	 (confidence_iteration <= iteration_min)) {
639
640    /* initialize a few counters. we have to remember that we might be */
641    /* going through the loop more than once. */
642
643    nummessages    =	0;
644    bytes_sent     =	0.0;
645    times_up       = 	0;
646
647    /*set up the data socket                        */
648    send_socket = create_xti_endpoint(loc_xti_device);
649
650    if (send_socket == INVALID_SOCKET) {
651      perror("netperf: send_xti_tcp_stream: tcp stream data socket");
652      exit(1);
653    }
654
655    if (debug) {
656      fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n");
657    }
658
659    /* it would seem that with XTI, there is no implicit bind on a */
660    /* connect, so we have to make a call to t_bind. this is not */
661    /* terribly convenient, but I suppose that "standard is better */
662    /* than better" :) raj 2/95 */
663
664    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
665      t_error("send_xti_tcp_stream: t_bind");
666      exit(1);
667    }
668
669    /* at this point, we have either retrieved the socket buffer sizes, */
670    /* or have tried to set them, so now, we may want to set the send */
671    /* size based on that (because the user either did not use a -m */
672    /* option, or used one with an argument of 0). If the socket buffer */
673    /* size is not available, we will set the send size to 4KB - no */
674    /* particular reason, just arbitrary... */
675    if (send_size == 0) {
676      if (lss_size > 0) {
677	send_size = lss_size;
678      }
679      else {
680	send_size = 4096;
681      }
682    }
683
684    /* set-up the data buffer ring with the requested alignment and offset. */
685    /* note also that we have allocated a quantity */
686    /* of memory that is at least one send-size greater than our socket */
687    /* buffer size. We want to be sure that there are at least two */
688    /* buffers allocated - this can be a bit of a problem when the */
689    /* send_size is bigger than the socket size, so we must check... the */
690    /* user may have wanted to explicitly set the "width" of our send */
691    /* buffers, we should respect that wish... */
692
693    if (send_width == 0) {
694      send_width = (lss_size/send_size) + 1;
695      if (send_width == 1) send_width++;
696    }
697
698    if (send_ring == NULL) {
699      /* only allocate the send ring once. this is a networking test, */
700      /* not a memory allocation test. this way, we do not need a */
701      /* deallocate_buffer_ring() routine, and I don't feel like */
702      /* writing one anyway :) raj 11/94 */
703      send_ring = allocate_buffer_ring(send_width,
704				       send_size,
705				       local_send_align,
706				       local_send_offset);
707    }
708
709    /* If the user has requested cpu utilization measurements, we must */
710    /* calibrate the cpu(s). We will perform this task within the tests */
711    /* themselves. If the user has specified the cpu rate, then */
712    /* calibrate_local_cpu will return rather quickly as it will have */
713    /* nothing to do. If local_cpu_rate is zero, then we will go through */
714    /* all the "normal" calibration stuff and return the rate back. */
715
716    if (local_cpu_usage) {
717      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
718    }
719
720    /* Tell the remote end to do a listen. The server alters the socket */
721    /* paramters on the other side at this point, hence the reason for */
722    /* all the values being passed in the setup message. If the user did */
723    /* not specify any of the parameters, they will be passed as 0, which */
724    /* will indicate to the remote that no changes beyond the system's */
725    /* default should be used. Alignment is the exception, it will */
726    /* default to 1, which will be no alignment alterations. */
727
728    netperf_request.content.request_type          = DO_XTI_TCP_STREAM;
729    xti_tcp_stream_request->send_buf_size  = rss_size;
730    xti_tcp_stream_request->recv_buf_size  = rsr_size;
731    xti_tcp_stream_request->receive_size   = recv_size;
732    xti_tcp_stream_request->no_delay       = rem_nodelay;
733    xti_tcp_stream_request->recv_alignment = remote_recv_align;
734    xti_tcp_stream_request->recv_offset    = remote_recv_offset;
735    xti_tcp_stream_request->measure_cpu    = remote_cpu_usage;
736    xti_tcp_stream_request->cpu_rate       = remote_cpu_rate;
737    if (test_time) {
738      xti_tcp_stream_request->test_length  = test_time;
739    }
740    else {
741      xti_tcp_stream_request->test_length  = test_bytes;
742    }
743    xti_tcp_stream_request->so_rcvavoid    = rem_rcvavoid;
744    xti_tcp_stream_request->so_sndavoid    = rem_sndavoid;
745
746    strcpy(xti_tcp_stream_request->xti_device, rem_xti_device);
747
748#ifdef __alpha
749
750    /* ok - even on a DEC box, strings are strings. I didn't really want */
751    /* to ntohl the words of a string. since I don't want to teach the */
752    /* send_ and recv_ _request and _response routines about the types, */
753    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
754    /* solution would be to use XDR, but I am still leary of being able */
755    /* to find XDR libs on all platforms I want running netperf. raj */
756    {
757      int *charword;
758      int *initword;
759      int *lastword;
760
761      initword = (int *) xti_tcp_stream_request->xti_device;
762      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
763
764      for (charword = initword;
765	   charword < lastword;
766	   charword++) {
767
768	*charword = ntohl(*charword);
769      }
770    }
771#endif /* __alpha */
772
773#ifdef DIRTY
774    xti_tcp_stream_request->dirty_count         = rem_dirty_count;
775    xti_tcp_stream_request->clean_count         = rem_clean_count;
776#endif /* DIRTY */
777
778
779    if (debug > 1) {
780      fprintf(where,
781              "netperf: send_xti_tcp_stream: requesting TCP stream test\n");
782    }
783
784    send_request();
785
786    /* The response from the remote will contain all of the relevant    */
787    /* socket parameters for this test type. We will put them back into */
788    /* the variables here so they can be displayed if desired.  The     */
789    /* remote will have calibrated CPU if necessary, and will have done */
790    /* all the needed set-up we will have calibrated the cpu locally    */
791    /* before sending the request, and will grab the counter value right*/
792    /* after the connect returns. The remote will grab the counter right*/
793    /* after the accept call. This saves the hassle of extra messages   */
794    /* being sent for the TCP tests.                                    */
795
796    recv_response();
797
798    if (!netperf_response.content.serv_errno) {
799      if (debug)
800        fprintf(where,"remote listen done.\n");
801      rsr_size         = xti_tcp_stream_response->recv_buf_size;
802      rss_size         = xti_tcp_stream_response->send_buf_size;
803      rem_nodelay      = xti_tcp_stream_response->no_delay;
804      remote_cpu_usage = xti_tcp_stream_response->measure_cpu;
805      remote_cpu_rate  = xti_tcp_stream_response->cpu_rate;
806
807      /* we have to make sure that the server port number is in */
808      /* network order */
809      server.sin_port   = (short)xti_tcp_stream_response->data_port_number;
810      server.sin_port   = htons(server.sin_port);
811      rem_rcvavoid      = xti_tcp_stream_response->so_rcvavoid;
812      rem_sndavoid      = xti_tcp_stream_response->so_sndavoid;
813    }
814    else {
815      Set_errno(netperf_response.content.serv_errno);
816      perror("netperf: remote error");
817
818      exit(1);
819    }
820
821    /*Connect up to the remote port on the data socket  */
822    memset (&server_call, 0, sizeof(server_call));
823    server_call.addr.maxlen = sizeof(struct sockaddr_in);
824    server_call.addr.len    = sizeof(struct sockaddr_in);
825    server_call.addr.buf    = (char *)&server;
826
827    if (t_connect(send_socket,
828		  &server_call,
829		  NULL) == INVALID_SOCKET){
830      t_error("netperf: send_xti_tcp_stream: data socket connect failed");
831      printf(" port: %d\n",ntohs(server.sin_port));
832      exit(1);
833    }
834
835    /* Data Socket set-up is finished. If there were problems, either */
836    /* the connect would have failed, or the previous response would */
837    /* have indicated a problem. I failed to see the value of the */
838    /* extra  message after the accept on the remote. If it failed, */
839    /* we'll see it here. If it didn't, we might as well start pumping */
840    /* data. */
841
842    /* Set-up the test end conditions. For a stream test, they can be */
843    /* either time or byte-count based. */
844
845    if (test_time) {
846      /* The user wanted to end the test after a period of time. */
847      times_up = 0;
848      bytes_remaining = 0;
849      /* in previous revisions, we had the same code repeated throught */
850      /* all the test suites. this was unnecessary, and meant more */
851      /* work for me when I wanted to switch to POSIX signals, so I */
852      /* have abstracted this out into a routine in netlib.c. if you */
853      /* are experiencing signal problems, you might want to look */
854      /* there. raj 11/94 */
855      start_timer(test_time);
856    }
857    else {
858      /* The tester wanted to send a number of bytes. */
859      bytes_remaining = test_bytes;
860      times_up = 1;
861    }
862
863    /* The cpu_start routine will grab the current time and possibly */
864    /* value of the idle counter for later use in measuring cpu */
865    /* utilization and/or service demand and thruput. */
866
867    cpu_start(local_cpu_usage);
868
869#ifdef WANT_INTERVALS
870    if ((interval_burst) || (demo_mode)) {
871      /* zero means that we never pause, so we never should need the */
872      /* interval timer, unless we are in demo_mode */
873      start_itimer(interval_wate);
874    }
875    interval_count = interval_burst;
876    /* get the signal set for the call to sigsuspend */
877    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
878      fprintf(where,
879              "send_xti_tcp_stream: unable to get sigmask errno %d\n",
880              errno);
881      fflush(where);
882      exit(1);
883    }
884#endif /* WANT_INTERVALS */
885
886    /* before we start, initialize a few variables */
887
888    /* We use an "OR" to control test execution. When the test is */
889    /* controlled by time, the byte count check will always return false. */
890    /* When the test is controlled by byte count, the time test will */
891    /* always return false. When the test is finished, the whole */
892    /* expression will go false and we will stop sending data. */
893
894    while ((!times_up) || (bytes_remaining > 0)) {
895
896#ifdef DIRTY
897      /* we want to dirty some number of consecutive integers in the buffer */
898      /* we are about to send. we may also want to bring some number of */
899      /* them cleanly into the cache. The clean ones will follow any dirty */
900      /* ones into the cache. at some point, we might want to replace */
901      /* the rand() call with something from a table to reduce our call */
902      /* overhead during the test, but it is not a high priority item. */
903      access_buffer(send_ring->buffer_ptr,
904		    send_size,
905		    loc_dirty_count,
906		    loc_clean_count);
907#endif /* DIRTY */
908
909#ifdef WANT_HISTOGRAM
910      /* timestamp just before we go into send and then again just after */
911      /* we come out raj 8/94 */
912      HIST_timestamp(&time_one);
913#endif /* WANT_HISTOGRAM */
914
915      if((len=t_snd(send_socket,
916		    send_ring->buffer_ptr,
917		    send_size,
918		    0)) != send_size) {
919        if ((len >=0) || (errno == EINTR)) {
920          /* the test was interrupted, must be the end of test */
921          break;
922        }
923        fprintf(where,
924		"send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
925		errno,
926		t_errno,
927		t_look(send_socket));
928	fflush(where);
929        exit(1);
930      }
931
932#ifdef WANT_HISTOGRAM
933      /* timestamp the exit from the send call and update the histogram */
934      HIST_timestamp(&time_two);
935      HIST_add(time_hist,delta_micro(&time_one,&time_two));
936#endif /* WANT_HISTOGRAM */
937
938#ifdef WANT_INTERVALS
939      if (demo_mode) {
940        units_this_tick += send_size;
941      }
942      /* in this case, the interval count is the count-down couter */
943      /* to decide to sleep for a little bit */
944      if ((interval_burst) && (--interval_count == 0)) {
945        /* call sigsuspend and wait for the interval timer to get us */
946        /* out */
947        if (debug) {
948          fprintf(where,"about to suspend\n");
949          fflush(where);
950        }
951        if (sigsuspend(&signal_set) == EFAULT) {
952          fprintf(where,
953                  "send_xti_tcp_stream: fault with signal set!\n");
954          fflush(where);
955          exit(1);
956        }
957        interval_count = interval_burst;
958      }
959#endif /* WANT_INTERVALS */
960
961      /* now we want to move our pointer to the next position in the */
962      /* data buffer...we may also want to wrap back to the "beginning" */
963      /* of the bufferspace, so we will mod the number of messages sent */
964      /* by the send width, and use that to calculate the offset to add */
965      /* to the base pointer. */
966      nummessages++;
967      send_ring = send_ring->next;
968      if (bytes_remaining) {
969        bytes_remaining -= send_size;
970      }
971    }
972
973    /* The test is over. Flush the buffers to the remote end. We do a */
974    /* graceful release to insure that all data has been taken by the */
975    /* remote. */
976
977    /* but first, if the verbosity is greater than 1, find-out what */
978    /* the TCP maximum segment_size was (if possible) */
979    if (verbosity > 1) {
980      tcp_mss = -1;
981      get_xti_info(send_socket,info_struct);
982    }
983
984    if (t_sndrel(send_socket) == -1) {
985      t_error("netperf: cannot shutdown tcp stream socket");
986      exit(1);
987    }
988
989    /* hang a t_rcvrel() off the socket to block until the remote has */
990    /* brought all the data up into the application. it will do a */
991    /* t_sedrel to cause a FIN to be sent our way. We will assume that */
992    /* any exit from the t_rcvrel() call is good... raj 2/95 */
993
994    if (debug > 1) {
995      fprintf(where,"about to hang a receive for graceful release.\n");
996      fflush(where);
997    }
998
999    t_rcvrel(send_socket);
1000
1001    /* this call will always give us the elapsed time for the test, and */
1002    /* will also store-away the necessaries for cpu utilization */
1003
1004    cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
1005                                                /* measured and how */
1006                                                /* long did we really */
1007                                                /* run? */
1008
1009    /* Get the statistics from the remote end. The remote will have */
1010    /* calculated service demand and all those interesting things. If it */
1011    /* wasn't supposed to care, it will return obvious values. */
1012
1013    recv_response();
1014    if (!netperf_response.content.serv_errno) {
1015      if (debug)
1016        fprintf(where,"remote results obtained\n");
1017    }
1018    else {
1019      Set_errno(netperf_response.content.serv_errno);
1020      perror("netperf: remote error");
1021
1022      exit(1);
1023    }
1024
1025    /* We now calculate what our thruput was for the test. In the future, */
1026    /* we may want to include a calculation of the thruput measured by */
1027    /* the remote, but it should be the case that for a TCP stream test, */
1028    /* that the two numbers should be *very* close... We calculate */
1029    /* bytes_sent regardless of the way the test length was controlled. */
1030    /* If it was time, we needed to, and if it was by bytes, the user may */
1031    /* have specified a number of bytes that wasn't a multiple of the */
1032    /* send_size, so we really didn't send what he asked for ;-) */
1033
1034    bytes_sent  = xti_tcp_stream_result->bytes_received;
1035
1036    thruput     = calc_thruput(bytes_sent);
1037
1038    if (local_cpu_usage || remote_cpu_usage) {
1039      /* We must now do a little math for service demand and cpu */
1040      /* utilization for the system(s) */
1041      /* Of course, some of the information might be bogus because */
1042      /* there was no idle counter in the kernel(s). We need to make */
1043      /* a note of this for the user's benefit...*/
1044      if (local_cpu_usage) {
1045
1046        local_cpu_utilization   = calc_cpu_util(0.0);
1047        local_service_demand    = calc_service_demand(bytes_sent,
1048                                                      0.0,
1049                                                      0.0,
1050						      0);
1051      }
1052      else {
1053        local_cpu_utilization   = -1.0;
1054        local_service_demand    = -1.0;
1055      }
1056
1057      if (remote_cpu_usage) {
1058
1059        remote_cpu_utilization  = xti_tcp_stream_result->cpu_util;
1060        remote_service_demand   = calc_service_demand(bytes_sent,
1061                                                      0.0,
1062                                                      remote_cpu_utilization,
1063						      xti_tcp_stream_result->num_cpus);
1064      }
1065      else {
1066        remote_cpu_utilization = -1.0;
1067        remote_service_demand  = -1.0;
1068      }
1069    }
1070    else {
1071      /* we were not measuring cpu, for the confidence stuff, we */
1072      /* should make it -1.0 */
1073      local_cpu_utilization  = -1.0;
1074      local_service_demand   = -1.0;
1075      remote_cpu_utilization = -1.0;
1076      remote_service_demand  = -1.0;
1077    }
1078
1079    /* at this point, we want to calculate the confidence information. */
1080    /* if debugging is on, calculate_confidence will print-out the */
1081    /* parameters we pass it */
1082
1083    calculate_confidence(confidence_iteration,
1084                         elapsed_time,
1085                         thruput,
1086                         local_cpu_utilization,
1087                         remote_cpu_utilization,
1088                         local_service_demand,
1089                         remote_service_demand);
1090
1091
1092    confidence_iteration++;
1093  }
1094
1095  /* at this point, we have finished making all the runs that we */
1096  /* will be making. so, we should extract what the calcuated values */
1097  /* are for all the confidence stuff. we could make the values */
1098  /* global, but that seemed a little messy, and it did not seem worth */
1099  /* all the mucking with header files. so, we create a routine much */
1100  /* like calcualte_confidence, which just returns the mean values. */
1101  /* raj 11/94 */
1102
1103  retrieve_confident_values(&elapsed_time,
1104                            &thruput,
1105                            &local_cpu_utilization,
1106                            &remote_cpu_utilization,
1107                            &local_service_demand,
1108                            &remote_service_demand);
1109
1110  /* We are now ready to print all the information. If the user */
1111  /* has specified zero-level verbosity, we will just print the */
1112  /* local service demand, or the remote service demand. If the */
1113  /* user has requested verbosity level 1, he will get the basic */
1114  /* "streamperf" numbers. If the user has specified a verbosity */
1115  /* of greater than 1, we will display a veritable plethora of */
1116  /* background information from outside of this block as it it */
1117  /* not cpu_measurement specific...  */
1118
1119  if (confidence < 0) {
1120    /* we did not hit confidence, but were we asked to look for it? */
1121    if (iteration_max > 1) {
1122      display_confidence();
1123    }
1124  }
1125
1126  if (local_cpu_usage || remote_cpu_usage) {
1127    local_cpu_method = format_cpu_method(cpu_method);
1128    remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method);
1129
1130    switch (verbosity) {
1131    case 0:
1132      if (local_cpu_usage) {
1133        fprintf(where,
1134                cpu_fmt_0,
1135                local_service_demand,
1136		local_cpu_method);
1137      }
1138      else {
1139	fprintf(where,
1140		cpu_fmt_0,
1141		remote_service_demand,
1142		remote_cpu_method);
1143      }
1144      break;
1145    case 1:
1146    case 2:
1147      if (print_headers) {
1148	fprintf(where,
1149		cpu_title,
1150		format_units(),
1151		local_cpu_method,
1152		remote_cpu_method);
1153      }
1154
1155      fprintf(where,
1156	      cpu_fmt_1,		/* the format string */
1157	      rsr_size,		        /* remote recvbuf size */
1158	      lss_size,		        /* local sendbuf size */
1159	      send_size,		/* how large were the sends */
1160	      elapsed_time,		/* how long was the test */
1161	      thruput, 		        /* what was the xfer rate */
1162	      local_cpu_utilization,	/* local cpu */
1163	      remote_cpu_utilization,	/* remote cpu */
1164	      local_service_demand,	/* local service demand */
1165	      remote_service_demand);	/* remote service demand */
1166      break;
1167    }
1168  }
1169  else {
1170    /* The tester did not wish to measure service demand. */
1171
1172    switch (verbosity) {
1173    case 0:
1174      fprintf(where,
1175	      tput_fmt_0,
1176	      thruput);
1177      break;
1178    case 1:
1179    case 2:
1180      if (print_headers) {
1181	fprintf(where,tput_title,format_units());
1182      }
1183      fprintf(where,
1184	      tput_fmt_1,		/* the format string */
1185	      rsr_size, 		/* remote recvbuf size */
1186	      lss_size, 		/* local sendbuf size */
1187	      send_size,		/* how large were the sends */
1188	      elapsed_time, 		/* how long did it take */
1189	      thruput);/* how fast did it go */
1190      break;
1191    }
1192  }
1193
1194  /* it would be a good thing to include information about some of the */
1195  /* other parameters that may have been set for this test, but at the */
1196  /* moment, I do not wish to figure-out all the  formatting, so I will */
1197  /* just put this comment here to help remind me that it is something */
1198  /* that should be done at a later time. */
1199
1200  if (verbosity > 1) {
1201    /* The user wanted to know it all, so we will give it to him. */
1202    /* This information will include as much as we can find about */
1203    /* TCP statistics, the alignments of the sends and receives */
1204    /* and all that sort of rot... */
1205
1206    /* this stuff needs to be worked-out in the presence of confidence */
1207    /* intervals and multiple iterations of the test... raj 11/94 */
1208
1209    fprintf(where,
1210	    ksink_fmt,
1211	    "Bytes",
1212	    "Bytes",
1213	    "Bytes",
1214	    local_send_align,
1215	    remote_recv_align,
1216	    local_send_offset,
1217	    remote_recv_offset,
1218	    bytes_sent,
1219	    bytes_sent / (double)nummessages,
1220	    nummessages,
1221	    bytes_sent / (double)xti_tcp_stream_result->recv_calls,
1222	    xti_tcp_stream_result->recv_calls);
1223    fprintf(where,
1224	    ksink_fmt2,
1225	    tcp_mss);
1226    fflush(where);
1227#ifdef WANT_HISTOGRAM
1228    fprintf(where,"\n\nHistogram of time spent in send() call.\n");
1229    fflush(where);
1230    HIST_report(time_hist);
1231#endif /* WANT_HISTOGRAM */
1232  }
1233
1234}
1235
1236
1237/* This is the server-side routine for the tcp stream test. It is */
1238/* implemented as one routine. I could break things-out somewhat, but */
1239/* didn't feel it was necessary. */
1240
1241void
1242recv_xti_tcp_stream()
1243{
1244
1245  struct sockaddr_in myaddr_in, peeraddr_in;
1246  struct t_bind      bind_req, bind_resp;
1247  struct t_call      call_req;
1248
1249  SOCKET       s_listen,s_data;
1250  int           addrlen;
1251  int	        len;
1252  unsigned int	receive_calls;
1253  float	        elapsed_time;
1254  double        bytes_received;
1255
1256  struct ring_elt *recv_ring;
1257
1258  int   *message_int_ptr;
1259  int   i;
1260
1261  struct xti_tcp_stream_request_struct	*xti_tcp_stream_request;
1262  struct xti_tcp_stream_response_struct	*xti_tcp_stream_response;
1263  struct xti_tcp_stream_results_struct	*xti_tcp_stream_results;
1264
1265  xti_tcp_stream_request	=
1266    (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
1267  xti_tcp_stream_response	=
1268    (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
1269  xti_tcp_stream_results	=
1270    (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
1271
1272  if (debug) {
1273    fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n");
1274    fflush(where);
1275  }
1276
1277  /* We want to set-up the listen socket with all the desired */
1278  /* parameters and then let the initiator know that all is ready. If */
1279  /* socket size defaults are to be used, then the initiator will have */
1280  /* sent us 0's. If the socket sizes cannot be changed, then we will */
1281  /* send-back what they are. If that information cannot be determined, */
1282  /* then we send-back -1's for the sizes. If things go wrong for any */
1283  /* reason, we will drop back ten yards and punt. */
1284
1285  /* If anything goes wrong, we want the remote to know about it. It */
1286  /* would be best if the error that the remote reports to the user is */
1287  /* the actual error we encountered, rather than some bogus unexpected */
1288  /* response type message. */
1289
1290  if (debug) {
1291    fprintf(where,"recv_xti_tcp_stream: setting the response type...\n");
1292    fflush(where);
1293  }
1294
1295  netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE;
1296
1297  if (debug) {
1298    fprintf(where,"recv_xti_tcp_stream: the response type is set...\n");
1299    fflush(where);
1300  }
1301
1302  /* We now alter the message_ptr variable to be at the desired */
1303  /* alignment with the desired offset. */
1304
1305  if (debug) {
1306    fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n",
1307	    xti_tcp_stream_request->recv_alignment);
1308    fflush(where);
1309  }
1310
1311  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
1312  /* can put in OUR values !-) At some point, we may want to nail this */
1313  /* socket to a particular network-level address, but for now, */
1314  /* INADDR_ANY should be just fine. */
1315
1316  bzero((char *)&myaddr_in,
1317	sizeof(myaddr_in));
1318  myaddr_in.sin_family      = AF_INET;
1319  myaddr_in.sin_addr.s_addr = INADDR_ANY;
1320  myaddr_in.sin_port        = 0;
1321
1322  /* Grab a socket to listen on, and then listen on it. */
1323
1324  if (debug) {
1325    fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n");
1326    fflush(where);
1327  }
1328
1329  /* create_xti_endpoint expects to find some things in the global */
1330  /* variables, so set the globals based on the values in the request. */
1331  /* once the socket has been created, we will set the response values */
1332  /* based on the updated value of those globals. raj 7/94 */
1333  lss_size = xti_tcp_stream_request->send_buf_size;
1334  lsr_size = xti_tcp_stream_request->recv_buf_size;
1335  loc_nodelay = xti_tcp_stream_request->no_delay;
1336  loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid;
1337  loc_sndavoid = xti_tcp_stream_request->so_sndavoid;
1338
1339#ifdef __alpha
1340
1341  /* ok - even on a DEC box, strings are strings. I din't really want */
1342  /* to ntohl the words of a string. since I don't want to teach the */
1343  /* send_ and recv_ _request and _response routines about the types, */
1344  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1345  /* solution would be to use XDR, but I am still leary of being able */
1346  /* to find XDR libs on all platforms I want running netperf. raj */
1347  {
1348    int *charword;
1349    int *initword;
1350    int *lastword;
1351
1352    initword = (int *) xti_tcp_stream_request->xti_device;
1353    lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4);
1354
1355    for (charword = initword;
1356	 charword < lastword;
1357	 charword++) {
1358
1359      *charword = htonl(*charword);
1360    }
1361  }
1362
1363#endif /* __alpha */
1364
1365  s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device);
1366
1367  if (s_listen == INVALID_SOCKET) {
1368    netperf_response.content.serv_errno = errno;
1369    send_response();
1370    exit(1);
1371  }
1372
1373  /* Let's get an address assigned to this socket so we can tell the */
1374  /* initiator how to reach the data socket. There may be a desire to */
1375  /* nail this socket to a specific IP address in a multi-homed, */
1376  /* multi-connection situation, but for now, we'll ignore the issue */
1377  /* and concentrate on single connection testing. */
1378
1379  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
1380  bind_req.addr.len    = sizeof(struct sockaddr_in);
1381  bind_req.addr.buf    = (char *)&myaddr_in;
1382  bind_req.qlen        = 1;
1383
1384  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
1385  bind_resp.addr.len    = sizeof(struct sockaddr_in);
1386  bind_resp.addr.buf    = (char *)&myaddr_in;
1387  bind_resp.qlen        = 1;
1388
1389  if (t_bind(s_listen,
1390	     &bind_req,
1391	     &bind_resp) == SOCKET_ERROR) {
1392    netperf_response.content.serv_errno = t_errno;
1393    close(s_listen);
1394    send_response();
1395
1396    exit(1);
1397  }
1398
1399  if (debug) {
1400    fprintf(where,
1401	    "recv_xti_tcp_stream: t_bind complete port %d\n",
1402	    ntohs(myaddr_in.sin_port));
1403    fflush(where);
1404  }
1405
1406  /* what sort of sizes did we end-up with? */
1407  if (xti_tcp_stream_request->receive_size == 0) {
1408    if (lsr_size > 0) {
1409      recv_size = lsr_size;
1410    }
1411    else {
1412      recv_size = 4096;
1413    }
1414  }
1415  else {
1416    recv_size = xti_tcp_stream_request->receive_size;
1417  }
1418
1419  /* we want to set-up our recv_ring in a manner analagous to what we */
1420  /* do on the sending side. this is more for the sake of symmetry */
1421  /* than for the needs of say copy avoidance, but it might also be */
1422  /* more realistic - this way one could conceivably go with a */
1423  /* double-buffering scheme when taking the data an putting it into */
1424  /* the filesystem or something like that. raj 7/94 */
1425
1426  if (recv_width == 0) {
1427    recv_width = (lsr_size/recv_size) + 1;
1428    if (recv_width == 1) recv_width++;
1429  }
1430
1431  recv_ring = allocate_buffer_ring(recv_width,
1432				   recv_size,
1433				   xti_tcp_stream_request->recv_alignment,
1434				   xti_tcp_stream_request->recv_offset);
1435
1436  if (debug) {
1437    fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n");
1438    fflush(where);
1439  }
1440
1441  /* Now myaddr_in contains the port and the internet address this is */
1442  /* returned to the sender also implicitly telling the sender that the */
1443  /* socket buffer sizing has been done. */
1444
1445  xti_tcp_stream_response->data_port_number =
1446    (int) ntohs(myaddr_in.sin_port);
1447  netperf_response.content.serv_errno   = 0;
1448
1449  /* But wait, there's more. If the initiator wanted cpu measurements, */
1450  /* then we must call the calibrate routine, which will return the max */
1451  /* rate back to the initiator. If the CPU was not to be measured, or */
1452  /* something went wrong with the calibration, we will return a -1 to */
1453  /* the initiator. */
1454
1455  xti_tcp_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
1456  if (xti_tcp_stream_request->measure_cpu) {
1457    xti_tcp_stream_response->measure_cpu = 1;
1458    xti_tcp_stream_response->cpu_rate =
1459      calibrate_local_cpu(xti_tcp_stream_request->cpu_rate);
1460  }
1461  else {
1462    xti_tcp_stream_response->measure_cpu = 0;
1463  }
1464
1465  /* before we send the response back to the initiator, pull some of */
1466  /* the socket parms from the globals */
1467  xti_tcp_stream_response->send_buf_size = lss_size;
1468  xti_tcp_stream_response->recv_buf_size = lsr_size;
1469  xti_tcp_stream_response->no_delay = loc_nodelay;
1470  xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid;
1471  xti_tcp_stream_response->so_sndavoid = loc_sndavoid;
1472  xti_tcp_stream_response->receive_size = recv_size;
1473
1474  send_response();
1475
1476  /* Now, let's set-up the socket to listen for connections. for xti, */
1477  /* the t_listen call is blocking by default - this is different */
1478  /* semantics from BSD - probably has to do with being able to reject */
1479  /* a call before an accept */
1480  call_req.addr.maxlen = sizeof(struct sockaddr_in);
1481  call_req.addr.len    = sizeof(struct sockaddr_in);
1482  call_req.addr.buf    = (char *)&peeraddr_in;
1483  call_req.opt.maxlen  = 0;
1484  call_req.opt.len     = 0;
1485  call_req.opt.buf     = NULL;
1486  call_req.udata.maxlen= 0;
1487  call_req.udata.len   = 0;
1488  call_req.udata.buf   = 0;
1489
1490  if (t_listen(s_listen, &call_req) == -1) {
1491    fprintf(where,
1492	    "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n",
1493	    errno,
1494	    t_errno);
1495    fflush(where);
1496    netperf_response.content.serv_errno = t_errno;
1497    close(s_listen);
1498    send_response();
1499    exit(1);
1500  }
1501
1502  if (debug) {
1503    fprintf(where,
1504	    "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n",
1505	    t_look(s_listen));
1506    fflush(where);
1507  }
1508
1509  /* now just rubber stamp the thing. we want to use the same fd? so */
1510  /* we will just equate s_data with s_listen. this seems a little */
1511  /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
1512  s_data = s_listen;
1513  if (t_accept(s_listen,
1514	       s_data,
1515	       &call_req) == -1) {
1516    fprintf(where,
1517	    "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n",
1518	    errno,
1519	    t_errno);
1520    fflush(where);
1521    close(s_listen);
1522    exit(1);
1523  }
1524
1525  if (debug) {
1526    fprintf(where,
1527	    "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n",
1528	    t_look(s_data));
1529    fprintf(where,
1530	    "                     remote is %s port %d\n",
1531	    inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
1532	    ntohs(peeraddr_in.sin_port));
1533    fflush(where);
1534  }
1535
1536  /* Now it's time to start receiving data on the connection. We will */
1537  /* first grab the apropriate counters and then start grabbing. */
1538
1539  cpu_start(xti_tcp_stream_request->measure_cpu);
1540
1541  /* The loop will exit when the sender does a t_sndrel, which will */
1542  /* return T_LOOK error from the t_recv */
1543
1544#ifdef DIRTY
1545    /* we want to dirty some number of consecutive integers in the buffer */
1546    /* we are about to recv. we may also want to bring some number of */
1547    /* them cleanly into the cache. The clean ones will follow any dirty */
1548    /* ones into the cache. */
1549
1550  access_buffer(recv_ring->buffer_ptr,
1551		recv_size,
1552		xti_tcp_stream_request->dirty_count,
1553		xti_tcp_stream_request->clean_count);
1554
1555#endif /* DIRTY */
1556
1557  bytes_received = 0;
1558  receive_calls  = 0;
1559
1560  while ((len = t_rcv(s_data,
1561		      recv_ring->buffer_ptr,
1562		      recv_size,
1563		      &xti_flags)) != -1) {
1564    bytes_received += len;
1565    receive_calls++;
1566
1567    /* more to the next buffer in the recv_ring */
1568    recv_ring = recv_ring->next;
1569
1570#ifdef DIRTY
1571
1572  access_buffer(recv_ring->buffer_ptr,
1573		recv_size,
1574		xti_tcp_stream_request->dirty_count,
1575		xti_tcp_stream_request->clean_count);
1576
1577#endif /* DIRTY */
1578  }
1579
1580  if (t_look(s_data) == T_ORDREL) {
1581    /* this is a normal exit path */
1582    if (debug) {
1583      fprintf(where,
1584	      "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n");
1585      fflush(where);
1586    }
1587  }
1588  else {
1589    /* something went wrong */
1590    fprintf(where,
1591	    "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d",
1592	    errno,
1593	    t_errno,
1594	    len);
1595    fprintf(where,
1596	    " t_look 0x%.4x",
1597	    t_look(s_data));
1598    fflush(where);
1599    netperf_response.content.serv_errno = t_errno;
1600    send_response();
1601    exit(1);
1602  }
1603
1604  /* receive the release and let the initiator know that we have */
1605  /* received all the data. raj 3/95 */
1606
1607  if (t_rcvrel(s_data) == -1) {
1608    netperf_response.content.serv_errno = errno;
1609    send_response();
1610    exit(1);
1611  }
1612
1613  if (debug) {
1614    fprintf(where,
1615	    "recv_xti_tcp_stream: t_rcvrel complete\n");
1616    fflush(where);
1617  }
1618
1619  if (t_sndrel(s_data) == -1) {
1620    netperf_response.content.serv_errno = errno;
1621    send_response();
1622    exit(1);
1623  }
1624
1625  if (debug) {
1626    fprintf(where,
1627	    "recv_xti_tcp_stream: t_sndrel complete\n");
1628    fflush(where);
1629  }
1630
1631  cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time);
1632
1633  /* send the results to the sender			*/
1634
1635  if (debug) {
1636    fprintf(where,
1637	    "recv_xti_tcp_stream: got %g bytes\n",
1638	    bytes_received);
1639    fprintf(where,
1640	    "recv_xti_tcp_stream: got %d recvs\n",
1641	    receive_calls);
1642    fflush(where);
1643  }
1644
1645  xti_tcp_stream_results->bytes_received	= bytes_received;
1646  xti_tcp_stream_results->elapsed_time	= elapsed_time;
1647  xti_tcp_stream_results->recv_calls	= receive_calls;
1648
1649  if (xti_tcp_stream_request->measure_cpu) {
1650    xti_tcp_stream_results->cpu_util	= calc_cpu_util(0.0);
1651  };
1652
1653  if (debug) {
1654    fprintf(where,
1655	    "recv_xti_tcp_stream: test complete, sending results.\n");
1656    fprintf(where,
1657	    "                 bytes_received %g receive_calls %d\n",
1658	    bytes_received,
1659	    receive_calls);
1660    fprintf(where,
1661	    "                 len %d\n",
1662	    len);
1663    fflush(where);
1664  }
1665
1666  xti_tcp_stream_results->cpu_method = cpu_method;
1667  send_response();
1668
1669  /* we are now done with the socket */
1670  t_close(s_data);
1671
1672}
1673
1674
1675 /* this routine implements the sending (netperf) side of the XTI_TCP_RR */
1676 /* test. */
1677
1678void
1679send_xti_tcp_rr(char remote_host[])
1680{
1681
1682  char *tput_title = "\
1683Local /Remote\n\
1684Socket Size   Request  Resp.   Elapsed  Trans.\n\
1685Send   Recv   Size     Size    Time     Rate         \n\
1686bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
1687
1688  char *tput_fmt_0 =
1689    "%7.2f\n";
1690
1691  char *tput_fmt_1_line_1 = "\
1692%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
1693  char *tput_fmt_1_line_2 = "\
1694%-6d %-6d\n";
1695
1696  char *cpu_title = "\
1697Local /Remote\n\
1698Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
1699Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
1700bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
1701
1702  char *cpu_fmt_0 =
1703    "%6.3f %c\n";
1704
1705  char *cpu_fmt_1_line_1 = "\
1706%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f\n";
1707
1708  char *cpu_fmt_1_line_2 = "\
1709%-6d %-6d\n";
1710
1711  char *ksink_fmt = "\
1712Alignment      Offset\n\
1713Local  Remote  Local  Remote\n\
1714Send   Recv    Send   Recv\n\
1715%5d  %5d   %5d  %5d\n";
1716
1717
1718  int			timed_out = 0;
1719  float			elapsed_time;
1720
1721  int	len;
1722  char	*temp_message_ptr;
1723  int	nummessages;
1724  SOCKET send_socket;
1725  int	trans_remaining;
1726  double	bytes_xferd;
1727
1728  struct ring_elt *send_ring;
1729  struct ring_elt *recv_ring;
1730
1731  int	rsp_bytes_left;
1732  int	rsp_bytes_recvd;
1733
1734  float	local_cpu_utilization;
1735  float	local_service_demand;
1736  float	remote_cpu_utilization;
1737  float	remote_service_demand;
1738  double	thruput;
1739
1740  struct	hostent	        *hp;
1741  struct	sockaddr_in	server;
1742  unsigned      int             addr;
1743
1744  struct t_call server_call;
1745
1746  struct	xti_tcp_rr_request_struct	*xti_tcp_rr_request;
1747  struct	xti_tcp_rr_response_struct	*xti_tcp_rr_response;
1748  struct	xti_tcp_rr_results_struct	*xti_tcp_rr_result;
1749
1750#ifdef WANT_INTERVALS
1751  int	interval_count;
1752  sigset_t signal_set;
1753#endif /* WANT_INTERVALS */
1754
1755  xti_tcp_rr_request =
1756    (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
1757  xti_tcp_rr_response=
1758    (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
1759  xti_tcp_rr_result	=
1760    (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
1761
1762#ifdef WANT_HISTOGRAM
1763  time_hist = HIST_new();
1764#endif /* WANT_HISTOGRAM */
1765
1766  /* since we are now disconnected from the code that established the */
1767  /* control socket, and since we want to be able to use different */
1768  /* protocols and such, we are passed the name of the remote host and */
1769  /* must turn that into the test specific addressing information. */
1770
1771  bzero((char *)&server,
1772	sizeof(server));
1773
1774  /* it would seem that while HP-UX will allow an IP address (as a */
1775  /* string) in a call to gethostbyname, other, less enlightened */
1776  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
1777  /* order changed to check for IP address first. raj 7/96 */
1778
1779  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
1780    /* it was not an IP address, try it as a name */
1781    if ((hp = gethostbyname(remote_host)) == NULL) {
1782      /* we have no idea what it is */
1783      fprintf(where,
1784	      "establish_control: could not resolve the destination %s\n",
1785	      remote_host);
1786      fflush(where);
1787      exit(1);
1788    }
1789    else {
1790      /* it was a valid remote_host */
1791      bcopy(hp->h_addr,
1792	    (char *)&server.sin_addr,
1793	    hp->h_length);
1794      server.sin_family = hp->h_addrtype;
1795    }
1796  }
1797  else {
1798    /* it was a valid IP address */
1799    server.sin_addr.s_addr = addr;
1800    server.sin_family = AF_INET;
1801  }
1802
1803  if ( print_headers ) {
1804    fprintf(where,"XTI TCP REQUEST/RESPONSE TEST");
1805    fprintf(where," to %s", remote_host);
1806    if (iteration_max > 1) {
1807      fprintf(where,
1808	      " : +/-%3.1f%% @ %2d%% conf.",
1809	      interval/0.02,
1810	      confidence_level);
1811      }
1812    if (loc_nodelay || rem_nodelay) {
1813      fprintf(where," : nodelay");
1814    }
1815    if (loc_sndavoid ||
1816	loc_rcvavoid ||
1817	rem_sndavoid ||
1818	rem_rcvavoid) {
1819      fprintf(where," : copy avoidance");
1820    }
1821#ifdef WANT_HISTOGRAM
1822    fprintf(where," : histogram");
1823#endif /* WANT_HISTOGRAM */
1824#ifdef WANT_INTERVALS
1825    fprintf(where," : interval");
1826#endif /* WANT_INTERVALS */
1827#ifdef DIRTY
1828    fprintf(where," : dirty data");
1829#endif /* DIRTY */
1830    fprintf(where,"\n");
1831  }
1832
1833  /* initialize a few counters */
1834
1835  send_ring = NULL;
1836  recv_ring = NULL;
1837  confidence_iteration = 1;
1838  init_stat();
1839
1840  /* we have a great-big while loop which controls the number of times */
1841  /* we run a particular test. this is for the calculation of a */
1842  /* confidence interval (I really should have stayed awake during */
1843  /* probstats :). If the user did not request confidence measurement */
1844  /* (no confidence is the default) then we will only go though the */
1845  /* loop once. the confidence stuff originates from the folks at IBM */
1846
1847  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
1848	 (confidence_iteration <= iteration_min)) {
1849
1850    /* initialize a few counters. we have to remember that we might be */
1851    /* going through the loop more than once. */
1852
1853    nummessages     = 0;
1854    bytes_xferd     = 0.0;
1855    times_up        = 0;
1856    timed_out       = 0;
1857    trans_remaining = 0;
1858
1859    /* set-up the data buffers with the requested alignment and offset. */
1860    /* since this is a request/response test, default the send_width and */
1861    /* recv_width to 1 and not two raj 7/94 */
1862
1863    if (send_width == 0) send_width = 1;
1864    if (recv_width == 0) recv_width = 1;
1865
1866    if (send_ring == NULL) {
1867      send_ring = allocate_buffer_ring(send_width,
1868				       req_size,
1869				       local_send_align,
1870				       local_send_offset);
1871    }
1872
1873    if (recv_ring == NULL) {
1874      recv_ring = allocate_buffer_ring(recv_width,
1875				       rsp_size,
1876				       local_recv_align,
1877				       local_recv_offset);
1878    }
1879
1880    /*set up the data socket                        */
1881    send_socket = create_xti_endpoint(loc_xti_device);
1882
1883    if (send_socket == INVALID_SOCKET){
1884      perror("netperf: send_xti_tcp_rr: tcp stream data socket");
1885      exit(1);
1886    }
1887
1888    if (debug) {
1889      fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n");
1890    }
1891
1892    /* it would seem that with XTI, there is no implicit bind on a */
1893    /* connect, so we have to make a call to t_bind. this is not */
1894    /* terribly convenient, but I suppose that "standard is better */
1895    /* than better" :) raj 2/95 */
1896
1897    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
1898      t_error("send_xti_tcp_stream: t_bind");
1899      exit(1);
1900    }
1901
1902    /* If the user has requested cpu utilization measurements, we must */
1903    /* calibrate the cpu(s). We will perform this task within the tests */
1904    /* themselves. If the user has specified the cpu rate, then */
1905    /* calibrate_local_cpu will return rather quickly as it will have */
1906    /* nothing to do. If local_cpu_rate is zero, then we will go through */
1907    /* all the "normal" calibration stuff and return the rate back.*/
1908
1909    if (local_cpu_usage) {
1910      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
1911    }
1912
1913    /* Tell the remote end to do a listen. The server alters the socket */
1914    /* paramters on the other side at this point, hence the reason for */
1915    /* all the values being passed in the setup message. If the user did */
1916    /* not specify any of the parameters, they will be passed as 0, which */
1917    /* will indicate to the remote that no changes beyond the system's */
1918    /* default should be used. Alignment is the exception, it will */
1919    /* default to 8, which will be no alignment alterations. */
1920
1921    netperf_request.content.request_type	=	DO_XTI_TCP_RR;
1922    xti_tcp_rr_request->recv_buf_size	=	rsr_size;
1923    xti_tcp_rr_request->send_buf_size	=	rss_size;
1924    xti_tcp_rr_request->recv_alignment  =	remote_recv_align;
1925    xti_tcp_rr_request->recv_offset	=	remote_recv_offset;
1926    xti_tcp_rr_request->send_alignment  =	remote_send_align;
1927    xti_tcp_rr_request->send_offset	=	remote_send_offset;
1928    xti_tcp_rr_request->request_size	=	req_size;
1929    xti_tcp_rr_request->response_size	=	rsp_size;
1930    xti_tcp_rr_request->no_delay	=	rem_nodelay;
1931    xti_tcp_rr_request->measure_cpu	=	remote_cpu_usage;
1932    xti_tcp_rr_request->cpu_rate	=	remote_cpu_rate;
1933    xti_tcp_rr_request->so_rcvavoid	=	rem_rcvavoid;
1934    xti_tcp_rr_request->so_sndavoid	=	rem_sndavoid;
1935    if (test_time) {
1936      xti_tcp_rr_request->test_length	=	test_time;
1937    }
1938    else {
1939      xti_tcp_rr_request->test_length	=	test_trans * -1;
1940    }
1941
1942    strcpy(xti_tcp_rr_request->xti_device, rem_xti_device);
1943
1944#ifdef __alpha
1945
1946    /* ok - even on a DEC box, strings are strings. I didn't really want */
1947    /* to ntohl the words of a string. since I don't want to teach the */
1948    /* send_ and recv_ _request and _response routines about the types, */
1949    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
1950    /* solution would be to use XDR, but I am still leary of being able */
1951    /* to find XDR libs on all platforms I want running netperf. raj */
1952    {
1953      int *charword;
1954      int *initword;
1955      int *lastword;
1956
1957      initword = (int *) xti_tcp_rr_request->xti_device;
1958      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
1959
1960      for (charword = initword;
1961	   charword < lastword;
1962	   charword++) {
1963
1964	*charword = ntohl(*charword);
1965      }
1966    }
1967#endif /* __alpha */
1968
1969    if (debug > 1) {
1970      fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n");
1971    }
1972
1973    send_request();
1974
1975    /* The response from the remote will contain all of the relevant 	*/
1976    /* socket parameters for this test type. We will put them back into */
1977    /* the variables here so they can be displayed if desired.  The	*/
1978    /* remote will have calibrated CPU if necessary, and will have done	*/
1979    /* all the needed set-up we will have calibrated the cpu locally	*/
1980    /* before sending the request, and will grab the counter value right*/
1981    /* after the connect returns. The remote will grab the counter right*/
1982    /* after the accept call. This saves the hassle of extra messages	*/
1983    /* being sent for the TCP tests.					*/
1984
1985    recv_response();
1986
1987    if (!netperf_response.content.serv_errno) {
1988      if (debug)
1989	fprintf(where,"remote listen done.\n");
1990      rsr_size          = xti_tcp_rr_response->recv_buf_size;
1991      rss_size          = xti_tcp_rr_response->send_buf_size;
1992      rem_nodelay       = xti_tcp_rr_response->no_delay;
1993      remote_cpu_usage  = xti_tcp_rr_response->measure_cpu;
1994      remote_cpu_rate   = xti_tcp_rr_response->cpu_rate;
1995      /* make sure that port numbers are in network order */
1996      server.sin_port   = (short)xti_tcp_rr_response->data_port_number;
1997      server.sin_port   = htons(server.sin_port);
1998    }
1999    else {
2000      Set_errno(netperf_response.content.serv_errno);
2001      perror("netperf: remote error");
2002
2003      exit(1);
2004    }
2005
2006    /*Connect up to the remote port on the data socket  */
2007    memset (&server_call, 0, sizeof(server_call));
2008    server_call.addr.maxlen = sizeof(struct sockaddr_in);
2009    server_call.addr.len    = sizeof(struct sockaddr_in);
2010    server_call.addr.buf    = (char *)&server;
2011
2012    if (t_connect(send_socket,
2013		  &server_call,
2014		  NULL) == INVALID_SOCKET){
2015      t_error("netperf: send_xti_tcp_rr: data socket connect failed");
2016      printf(" port: %d\n",ntohs(server.sin_port));
2017      exit(1);
2018    }
2019
2020    /* Data Socket set-up is finished. If there were problems, either the */
2021    /* connect would have failed, or the previous response would have */
2022    /* indicated a problem. I failed to see the value of the extra */
2023    /* message after the accept on the remote. If it failed, we'll see it */
2024    /* here. If it didn't, we might as well start pumping data. */
2025
2026    /* Set-up the test end conditions. For a request/response test, they */
2027    /* can be either time or transaction based. */
2028
2029    if (test_time) {
2030      /* The user wanted to end the test after a period of time. */
2031      times_up = 0;
2032      trans_remaining = 0;
2033      start_timer(test_time);
2034    }
2035    else {
2036      /* The tester wanted to send a number of bytes. */
2037      trans_remaining = test_bytes;
2038      times_up = 1;
2039    }
2040
2041    /* The cpu_start routine will grab the current time and possibly */
2042    /* value of the idle counter for later use in measuring cpu */
2043    /* utilization and/or service demand and thruput. */
2044
2045    cpu_start(local_cpu_usage);
2046
2047#ifdef WANT_INTERVALS
2048    if ((interval_burst) || (demo_mode)) {
2049      /* zero means that we never pause, so we never should need the */
2050      /* interval timer, unless we are in demo_mode */
2051      start_itimer(interval_wate);
2052    }
2053    interval_count = interval_burst;
2054    /* get the signal set for the call to sigsuspend */
2055    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2056      fprintf(where,
2057	      "send_xti_tcp_rr: unable to get sigmask errno %d\n",
2058	      errno);
2059      fflush(where);
2060      exit(1);
2061    }
2062#endif /* WANT_INTERVALS */
2063
2064    /* We use an "OR" to control test execution. When the test is */
2065    /* controlled by time, the byte count check will always return false. */
2066    /* When the test is controlled by byte count, the time test will */
2067    /* always return false. When the test is finished, the whole */
2068    /* expression will go false and we will stop sending data. I think I */
2069    /* just arbitrarily decrement trans_remaining for the timed test, but */
2070    /* will not do that just yet... One other question is whether or not */
2071    /* the send buffer and the receive buffer should be the same buffer. */
2072
2073    while ((!times_up) || (trans_remaining > 0)) {
2074      /* send the request. we assume that if we use a blocking socket, */
2075      /* the request will be sent at one shot. */
2076
2077#ifdef WANT_HISTOGRAM
2078      /* timestamp just before our call to send, and then again just */
2079      /* after the receive raj 8/94 */
2080      HIST_timestamp(&time_one);
2081#endif /* WANT_HISTOGRAM */
2082
2083      if((len=t_snd(send_socket,
2084		    send_ring->buffer_ptr,
2085		    req_size,
2086		    0)) != req_size) {
2087	if ((errno == EINTR) || (errno == 0)) {
2088	  /* we hit the end of a */
2089	  /* timed test. */
2090	  timed_out = 1;
2091	  break;
2092	}
2093        fprintf(where,
2094		"send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
2095		errno,
2096		t_errno,
2097		t_look(send_socket));
2098	fflush(where);
2099        exit(1);
2100      }
2101      send_ring = send_ring->next;
2102
2103      /* receive the response */
2104      rsp_bytes_left = rsp_size;
2105      temp_message_ptr  = recv_ring->buffer_ptr;
2106      while(rsp_bytes_left > 0) {
2107	if((rsp_bytes_recvd=t_rcv(send_socket,
2108				  temp_message_ptr,
2109				  rsp_bytes_left,
2110				  &xti_flags)) == SOCKET_ERROR) {
2111	  if (errno == EINTR) {
2112	    /* We hit the end of a timed test. */
2113	    timed_out = 1;
2114	    break;
2115	  }
2116	  fprintf(where,
2117		  "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n",
2118		  errno,
2119		  t_errno,
2120		  t_look(send_socket));
2121	  fflush(where);
2122	  exit(1);
2123	}
2124	rsp_bytes_left -= rsp_bytes_recvd;
2125	temp_message_ptr  += rsp_bytes_recvd;
2126      }
2127      recv_ring = recv_ring->next;
2128
2129      if (timed_out) {
2130	/* we may have been in a nested while loop - we need */
2131	/* another call to break. */
2132	break;
2133      }
2134
2135#ifdef WANT_HISTOGRAM
2136      HIST_timestamp(&time_two);
2137      HIST_add(time_hist,delta_micro(&time_one,&time_two));
2138#endif /* WANT_HISTOGRAM */
2139#ifdef WANT_INTERVALS
2140      if (demo_mode) {
2141	units_this_tick += 1;
2142      }
2143      /* in this case, the interval count is the count-down couter */
2144      /* to decide to sleep for a little bit */
2145      if ((interval_burst) && (--interval_count == 0)) {
2146	/* call sigsuspend and wait for the interval timer to get us */
2147	/* out */
2148	if (debug) {
2149	  fprintf(where,"about to suspend\n");
2150	  fflush(where);
2151	}
2152	if (sigsuspend(&signal_set) == EFAULT) {
2153	  fprintf(where,
2154		  "send_xti_udp_rr: fault with signal set!\n");
2155	  fflush(where);
2156	  exit(1);
2157	}
2158	interval_count = interval_burst;
2159      }
2160#endif /* WANT_INTERVALS */
2161
2162      nummessages++;
2163      if (trans_remaining) {
2164	trans_remaining--;
2165      }
2166
2167      if (debug > 3) {
2168	if ((nummessages % 100) == 0) {
2169	  fprintf(where,
2170		  "Transaction %d completed\n",
2171		  nummessages);
2172	  fflush(where);
2173	}
2174      }
2175    }
2176
2177
2178    /* this call will always give us the elapsed time for the test, and */
2179    /* will also store-away the necessaries for cpu utilization */
2180
2181    cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being */
2182						/* measured? how long */
2183						/* did we really run? */
2184
2185    /* Get the statistics from the remote end. The remote will have */
2186    /* calculated service demand and all those interesting things. If it */
2187    /* wasn't supposed to care, it will return obvious values. */
2188
2189    recv_response();
2190    if (!netperf_response.content.serv_errno) {
2191      if (debug)
2192	fprintf(where,"remote results obtained\n");
2193    }
2194    else {
2195      Set_errno(netperf_response.content.serv_errno);
2196      perror("netperf: remote error");
2197
2198      exit(1);
2199    }
2200
2201    /* We now calculate what our thruput was for the test. */
2202
2203    bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
2204    thruput	= nummessages/elapsed_time;
2205
2206    if (local_cpu_usage || remote_cpu_usage) {
2207      /* We must now do a little math for service demand and cpu */
2208      /* utilization for the system(s) */
2209      /* Of course, some of the information might be bogus because */
2210      /* there was no idle counter in the kernel(s). We need to make */
2211      /* a note of this for the user's benefit...*/
2212      if (local_cpu_usage) {
2213	local_cpu_utilization = calc_cpu_util(0.0);
2214	/* since calc_service demand is doing ms/Kunit we will */
2215	/* multiply the number of transaction by 1024 to get */
2216	/* "good" numbers */
2217	local_service_demand  = calc_service_demand((double) nummessages*1024,
2218						    0.0,
2219						    0.0,
2220						    0);
2221      }
2222      else {
2223	local_cpu_utilization	= -1.0;
2224	local_service_demand	= -1.0;
2225      }
2226
2227      if (remote_cpu_usage) {
2228	remote_cpu_utilization = xti_tcp_rr_result->cpu_util;
2229	/* since calc_service demand is doing ms/Kunit we will */
2230	/* multiply the number of transaction by 1024 to get */
2231	/* "good" numbers */
2232	remote_service_demand = calc_service_demand((double) nummessages*1024,
2233						    0.0,
2234						    remote_cpu_utilization,
2235						    xti_tcp_rr_result->num_cpus);
2236      }
2237      else {
2238	remote_cpu_utilization = -1.0;
2239	remote_service_demand  = -1.0;
2240      }
2241
2242    }
2243    else {
2244      /* we were not measuring cpu, for the confidence stuff, we */
2245      /* should make it -1.0 */
2246      local_cpu_utilization	= -1.0;
2247      local_service_demand	= -1.0;
2248      remote_cpu_utilization = -1.0;
2249      remote_service_demand  = -1.0;
2250    }
2251
2252    /* at this point, we want to calculate the confidence information. */
2253    /* if debugging is on, calculate_confidence will print-out the */
2254    /* parameters we pass it */
2255
2256    calculate_confidence(confidence_iteration,
2257			 elapsed_time,
2258			 thruput,
2259			 local_cpu_utilization,
2260			 remote_cpu_utilization,
2261			 local_service_demand,
2262			 remote_service_demand);
2263
2264
2265    confidence_iteration++;
2266
2267    /* we are now done with the socket, so close it */
2268    t_close(send_socket);
2269
2270  }
2271
2272  retrieve_confident_values(&elapsed_time,
2273			    &thruput,
2274			    &local_cpu_utilization,
2275			    &remote_cpu_utilization,
2276			    &local_service_demand,
2277			    &remote_service_demand);
2278
2279  /* We are now ready to print all the information. If the user */
2280  /* has specified zero-level verbosity, we will just print the */
2281  /* local service demand, or the remote service demand. If the */
2282  /* user has requested verbosity level 1, he will get the basic */
2283  /* "streamperf" numbers. If the user has specified a verbosity */
2284  /* of greater than 1, we will display a veritable plethora of */
2285  /* background information from outside of this block as it it */
2286  /* not cpu_measurement specific...  */
2287
2288  if (confidence < 0) {
2289    /* we did not hit confidence, but were we asked to look for it? */
2290    if (iteration_max > 1) {
2291      display_confidence();
2292    }
2293  }
2294
2295  if (local_cpu_usage || remote_cpu_usage) {
2296    local_cpu_method = format_cpu_method(cpu_method);
2297    remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method);
2298
2299    switch (verbosity) {
2300    case 0:
2301      if (local_cpu_usage) {
2302	fprintf(where,
2303		cpu_fmt_0,
2304		local_service_demand,
2305		local_cpu_method);
2306      }
2307      else {
2308	fprintf(where,
2309		cpu_fmt_0,
2310		remote_service_demand,
2311		remote_cpu_method);
2312      }
2313      break;
2314    case 1:
2315    case 2:
2316      if (print_headers) {
2317	fprintf(where,
2318		cpu_title,
2319		local_cpu_method,
2320		remote_cpu_method);
2321      }
2322
2323      fprintf(where,
2324	      cpu_fmt_1_line_1,		/* the format string */
2325	      lss_size,		/* local sendbuf size */
2326	      lsr_size,
2327	      req_size,		/* how large were the requests */
2328	      rsp_size,		/* guess */
2329	      elapsed_time,		/* how long was the test */
2330	      thruput,
2331	      local_cpu_utilization,	/* local cpu */
2332	      remote_cpu_utilization,	/* remote cpu */
2333	      local_service_demand,	/* local service demand */
2334	      remote_service_demand);	/* remote service demand */
2335      fprintf(where,
2336	      cpu_fmt_1_line_2,
2337	      rss_size,
2338	      rsr_size);
2339      break;
2340    }
2341  }
2342  else {
2343    /* The tester did not wish to measure service demand. */
2344
2345    switch (verbosity) {
2346    case 0:
2347      fprintf(where,
2348	      tput_fmt_0,
2349	      thruput);
2350      break;
2351    case 1:
2352    case 2:
2353      if (print_headers) {
2354	fprintf(where,tput_title,format_units());
2355      }
2356
2357      fprintf(where,
2358	      tput_fmt_1_line_1,	/* the format string */
2359	      lss_size,
2360	      lsr_size,
2361	      req_size,		/* how large were the requests */
2362	      rsp_size,		/* how large were the responses */
2363	      elapsed_time, 		/* how long did it take */
2364	      thruput);
2365      fprintf(where,
2366	      tput_fmt_1_line_2,
2367	      rss_size, 		/* remote recvbuf size */
2368	      rsr_size);
2369
2370      break;
2371    }
2372  }
2373
2374  /* it would be a good thing to include information about some of the */
2375  /* other parameters that may have been set for this test, but at the */
2376  /* moment, I do not wish to figure-out all the  formatting, so I will */
2377  /* just put this comment here to help remind me that it is something */
2378  /* that should be done at a later time. */
2379
2380  /* how to handle the verbose information in the presence of */
2381  /* confidence intervals is yet to be determined... raj 11/94 */
2382  if (verbosity > 1) {
2383    /* The user wanted to know it all, so we will give it to him. */
2384    /* This information will include as much as we can find about */
2385    /* TCP statistics, the alignments of the sends and receives */
2386    /* and all that sort of rot... */
2387
2388    fprintf(where,
2389	    ksink_fmt,
2390	    local_send_align,
2391	    remote_recv_offset,
2392	    local_send_offset,
2393	    remote_recv_offset);
2394
2395#ifdef WANT_HISTOGRAM
2396    fprintf(where,"\nHistogram of request/response times\n");
2397    fflush(where);
2398    HIST_report(time_hist);
2399#endif /* WANT_HISTOGRAM */
2400
2401  }
2402
2403}
2404
2405void
2406send_xti_udp_stream(char remote_host[])
2407{
2408  /**********************************************************************/
2409  /*									*/
2410  /*               	UDP Unidirectional Send Test                    */
2411  /*									*/
2412  /**********************************************************************/
2413  char *tput_title = "\
2414Socket  Message  Elapsed      Messages                \n\
2415Size    Size     Time         Okay Errors   Throughput\n\
2416bytes   bytes    secs            #      #   %s/sec\n\n";
2417
2418  char *tput_fmt_0 =
2419    "%7.2f\n";
2420
2421  char *tput_fmt_1 = "\
2422%6d  %6d   %-7.2f   %7d %6d    %7.2f\n\
2423%6d           %-7.2f   %7d           %7.2f\n\n";
2424
2425
2426  char *cpu_title = "\
2427Socket  Message  Elapsed      Messages                   CPU      Service\n\
2428Size    Size     Time         Okay Errors   Throughput   Util     Demand\n\
2429bytes   bytes    secs            #      #   %s/sec %% %c%c     us/KB\n\n";
2430
2431  char *cpu_fmt_0 =
2432    "%6.2f %c\n";
2433
2434  char *cpu_fmt_1 = "\
2435%6d  %6d   %-7.2f   %7d %6d    %7.1f     %-6.2f   %-6.3f\n\
2436%6d           %-7.2f   %7d           %7.1f     %-6.2f   %-6.3f\n\n";
2437
2438  unsigned int	messages_recvd;
2439  unsigned int 	messages_sent;
2440  unsigned int	failed_sends;
2441
2442  float	elapsed_time,
2443        recv_elapsed,
2444        local_cpu_utilization,
2445        remote_cpu_utilization;
2446
2447  float	 local_service_demand, remote_service_demand;
2448  double local_thruput, remote_thruput;
2449  double bytes_sent;
2450  double bytes_recvd;
2451
2452
2453  int	len;
2454  int	*message_int_ptr;
2455  struct ring_elt *send_ring;
2456  SOCKET data_socket;
2457
2458  unsigned int sum_messages_sent;
2459  unsigned int sum_messages_recvd;
2460  unsigned int sum_failed_sends;
2461  double sum_local_thruput;
2462
2463#ifdef WANT_INTERVALS
2464  int	interval_count;
2465  sigset_t signal_set;
2466#endif /* WANT_INTERVALS */
2467
2468  struct   hostent     *hp;
2469  struct   sockaddr_in server;
2470  unsigned int         addr;
2471
2472  struct t_unitdata unitdata;
2473
2474  struct xti_udp_stream_request_struct	*xti_udp_stream_request;
2475  struct xti_udp_stream_response_struct	*xti_udp_stream_response;
2476  struct xti_udp_stream_results_struct	*xti_udp_stream_results;
2477
2478  xti_udp_stream_request  =
2479    (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
2480  xti_udp_stream_response =
2481    (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
2482  xti_udp_stream_results  =
2483    (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
2484
2485#ifdef WANT_HISTOGRAM
2486  time_hist = HIST_new();
2487#endif /* WANT_HISTOGRAM */
2488
2489  /* since we are now disconnected from the code that established the */
2490  /* control socket, and since we want to be able to use different */
2491  /* protocols and such, we are passed the name of the remote host and */
2492  /* must turn that into the test specific addressing information. */
2493
2494  bzero((char *)&server,
2495	sizeof(server));
2496
2497  /* it would seem that while HP-UX will allow an IP address (as a */
2498  /* string) in a call to gethostbyname, other, less enlightened */
2499  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
2500  /* order changed to check for IP address first. raj 7/96 */
2501
2502  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
2503    /* it was not an IP address, try it as a name */
2504    if ((hp = gethostbyname(remote_host)) == NULL) {
2505      /* we have no idea what it is */
2506      fprintf(where,
2507	      "establish_control: could not resolve the destination %s\n",
2508	      remote_host);
2509      fflush(where);
2510      exit(1);
2511    }
2512    else {
2513      /* it was a valid remote_host */
2514      bcopy(hp->h_addr,
2515	    (char *)&server.sin_addr,
2516	    hp->h_length);
2517      server.sin_family = hp->h_addrtype;
2518    }
2519  }
2520  else {
2521    /* it was a valid IP address */
2522    server.sin_addr.s_addr = addr;
2523    server.sin_family = AF_INET;
2524  }
2525
2526  if ( print_headers ) {
2527    fprintf(where,"UDP UNIDIRECTIONAL SEND TEST");
2528    fprintf(where," to %s", remote_host);
2529    if (iteration_max > 1) {
2530      fprintf(where,
2531	      " : +/-%3.1f%% @ %2d%% conf.",
2532	      interval/0.02,
2533	      confidence_level);
2534      }
2535    if (loc_sndavoid ||
2536	loc_rcvavoid ||
2537	rem_sndavoid ||
2538	rem_rcvavoid) {
2539      fprintf(where," : copy avoidance");
2540    }
2541#ifdef WANT_HISTOGRAM
2542    fprintf(where," : histogram");
2543#endif /* WANT_HISTOGRAM */
2544#ifdef WANT_INTERVALS
2545    fprintf(where," : interval");
2546#endif /* WANT_INTERVALS */
2547#ifdef DIRTY
2548    fprintf(where," : dirty data");
2549#endif /* DIRTY */
2550    fprintf(where,"\n");
2551  }
2552
2553  send_ring            = NULL;
2554  confidence_iteration = 1;
2555  init_stat();
2556  sum_messages_sent    = 0;
2557  sum_messages_recvd   = 0;
2558  sum_failed_sends     = 0;
2559  sum_local_thruput    = 0.0;
2560
2561  /* we have a great-big while loop which controls the number of times */
2562  /* we run a particular test. this is for the calculation of a */
2563  /* confidence interval (I really should have stayed awake during */
2564  /* probstats :). If the user did not request confidence measurement */
2565  /* (no confidence is the default) then we will only go though the */
2566  /* loop once. the confidence stuff originates from the folks at IBM */
2567
2568  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
2569	 (confidence_iteration <= iteration_min)) {
2570
2571    /* initialize a few counters. we have to remember that we might be */
2572    /* going through the loop more than once. */
2573    messages_sent  = 0;
2574    messages_recvd = 0;
2575    failed_sends   = 0;
2576    times_up       = 0;
2577
2578    /*set up the data socket			*/
2579    data_socket = create_xti_endpoint(loc_xti_device);
2580
2581    if (data_socket == INVALID_SOCKET) {
2582      perror("send_xti_udp_stream: create_xti_endpoint");
2583      exit(1);
2584    }
2585
2586    if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) {
2587      t_error("send_xti_udp_stream: t_bind");
2588      exit(1);
2589    }
2590
2591    /* now, we want to see if we need to set the send_size */
2592    if (send_size == 0) {
2593      if (lss_size > 0) {
2594	send_size = lss_size;
2595      }
2596      else {
2597	send_size = 4096;
2598      }
2599    }
2600
2601    /* set-up the data buffer with the requested alignment and offset, */
2602    /* most of the numbers here are just a hack to pick something nice */
2603    /* and big in an attempt to never try to send a buffer a second time */
2604    /* before it leaves the node...unless the user set the width */
2605    /* explicitly. */
2606    if (send_width == 0) send_width = 32;
2607
2608    if (send_ring == NULL ) {
2609      send_ring = allocate_buffer_ring(send_width,
2610				       send_size,
2611				       local_send_align,
2612				       local_send_offset);
2613    }
2614
2615
2616    /* if the user supplied a cpu rate, this call will complete rather */
2617    /* quickly, otherwise, the cpu rate will be retured to us for */
2618    /* possible display. The Library will keep it's own copy of this data */
2619    /* for use elsewhere. We will only display it. (Does that make it */
2620    /* "opaque" to us?) */
2621
2622    if (local_cpu_usage)
2623      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
2624
2625    /* Tell the remote end to set up the data connection. The server */
2626    /* sends back the port number and alters the socket parameters there. */
2627    /* Of course this is a datagram service so no connection is actually */
2628    /* set up, the server just sets up the socket and binds it. */
2629
2630    netperf_request.content.request_type      = DO_XTI_UDP_STREAM;
2631    xti_udp_stream_request->recv_buf_size  = rsr_size;
2632    xti_udp_stream_request->message_size   = send_size;
2633    xti_udp_stream_request->recv_alignment = remote_recv_align;
2634    xti_udp_stream_request->recv_offset    = remote_recv_offset;
2635    xti_udp_stream_request->measure_cpu    = remote_cpu_usage;
2636    xti_udp_stream_request->cpu_rate       = remote_cpu_rate;
2637    xti_udp_stream_request->test_length    = test_time;
2638    xti_udp_stream_request->so_rcvavoid    = rem_rcvavoid;
2639    xti_udp_stream_request->so_sndavoid    = rem_sndavoid;
2640
2641    strcpy(xti_udp_stream_request->xti_device, rem_xti_device);
2642
2643#ifdef __alpha
2644
2645    /* ok - even on a DEC box, strings are strings. I didn't really want */
2646    /* to ntohl the words of a string. since I don't want to teach the */
2647    /* send_ and recv_ _request and _response routines about the types, */
2648    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
2649    /* solution would be to use XDR, but I am still leary of being able */
2650    /* to find XDR libs on all platforms I want running netperf. raj */
2651    {
2652      int *charword;
2653      int *initword;
2654      int *lastword;
2655
2656      initword = (int *) xti_udp_stream_request->xti_device;
2657      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
2658
2659      for (charword = initword;
2660	   charword < lastword;
2661	   charword++) {
2662
2663	*charword = ntohl(*charword);
2664      }
2665    }
2666#endif /* __alpha */
2667
2668    send_request();
2669
2670    recv_response();
2671
2672    if (!netperf_response.content.serv_errno) {
2673      if (debug)
2674	fprintf(where,"send_xti_udp_stream: remote data connection done.\n");
2675    }
2676    else {
2677      Set_errno(netperf_response.content.serv_errno);
2678      perror("send_xti_udp_stream: error on remote");
2679      exit(1);
2680    }
2681
2682    /* Place the port number returned by the remote into the sockaddr */
2683    /* structure so our sends can be sent to the correct place. Also get */
2684    /* some of the returned socket buffer information for user display. */
2685
2686    /* make sure that port numbers are in the proper order */
2687    server.sin_port = (short)xti_udp_stream_response->data_port_number;
2688    server.sin_port = htons(server.sin_port);
2689    rsr_size        = xti_udp_stream_response->recv_buf_size;
2690    rss_size        = xti_udp_stream_response->send_buf_size;
2691    remote_cpu_rate = xti_udp_stream_response->cpu_rate;
2692
2693    /* it would seem that XTI does not allow the expedient of */
2694    /* "connecting" a UDP end-point the way BSD does. so, we will do */
2695    /* everything with t_sndudata and t_rcvudata. Our "virtual" */
2696    /* connect here will be to assign the destination portion of the */
2697    /* t_unitdata struct here, where we would have otherwise called */
2698    /* t_connect() raj 3/95 */
2699
2700    memset (&unitdata, 0, sizeof(unitdata));
2701    unitdata.addr.maxlen = sizeof(struct sockaddr_in);
2702    unitdata.addr.len    = sizeof(struct sockaddr_in);
2703    unitdata.addr.buf    = (char *)&server;
2704
2705    /* we don't use any options, so might as well set that part here */
2706    /* too */
2707
2708    unitdata.opt.maxlen = 0;
2709    unitdata.opt.len    = 0;
2710    unitdata.opt.buf    = NULL;
2711
2712    /* we need to initialize the send buffer for the first time as */
2713    /* well since we move to the next pointer after the send call. */
2714
2715    unitdata.udata.maxlen = send_size;
2716    unitdata.udata.len    = send_size;
2717    unitdata.udata.buf    = send_ring->buffer_ptr;
2718
2719    /* set up the timer to call us after test_time. one of these days, */
2720    /* it might be nice to figure-out a nice reliable way to have the */
2721    /* test controlled by a byte count as well, but since UDP is not */
2722    /* reliable, that could prove difficult. so, in the meantime, we */
2723    /* only allow a XTI_UDP_STREAM test to be a timed test. */
2724
2725    if (test_time) {
2726      times_up = 0;
2727      start_timer(test_time);
2728    }
2729    else {
2730      fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n");
2731      fflush(where);
2732      exit(1);
2733    }
2734
2735    /* Get the start count for the idle counter and the start time */
2736
2737    cpu_start(local_cpu_usage);
2738
2739#ifdef WANT_INTERVALS
2740    if ((interval_burst) || (demo_mode)) {
2741      /* zero means that we never pause, so we never should need the */
2742      /* interval timer, unless we are in demo_mode */
2743      start_itimer(interval_wate);
2744    }
2745    interval_count = interval_burst;
2746    /* get the signal set for the call to sigsuspend */
2747    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
2748      fprintf(where,
2749	      "send_xti_udp_stream: unable to get sigmask errno %d\n",
2750	      errno);
2751      fflush(where);
2752      exit(1);
2753    }
2754#endif /* WANT_INTERVALS */
2755
2756    /* Send datagrams like there was no tomorrow. at somepoint it might */
2757    /* be nice to set this up so that a quantity of bytes could be sent, */
2758    /* but we still need some sort of end of test trigger on the receive */
2759    /* side. that could be a select with a one second timeout, but then */
2760    /* if there is a test where none of the data arrives for awile and */
2761    /* then starts again, we would end the test too soon. something to */
2762    /* think about... */
2763    while (!times_up) {
2764
2765#ifdef DIRTY
2766      /* we want to dirty some number of consecutive integers in the buffer */
2767      /* we are about to send. we may also want to bring some number of */
2768      /* them cleanly into the cache. The clean ones will follow any dirty */
2769      /* ones into the cache. */
2770
2771      access_buffer(send_ring->buffer_ptr,
2772		    send_size,
2773		    loc_dirty_count,
2774		    loc_clean_count);
2775
2776#endif /* DIRTY */
2777
2778#ifdef WANT_HISTOGRAM
2779      HIST_timestamp(&time_one);
2780#endif /* WANT_HISTOGRAM */
2781
2782      if ((t_sndudata(data_socket,
2783		      &unitdata))  != 0) {
2784	if (errno == EINTR)
2785	  break;
2786	if (errno == ENOBUFS) {
2787	  failed_sends++;
2788	  continue;
2789	}
2790	perror("xti_udp_send: data send error");
2791	t_error("xti_udp_send: data send error");
2792	exit(1);
2793      }
2794      messages_sent++;
2795
2796      /* now we want to move our pointer to the next position in the */
2797      /* data buffer...and update the unitdata structure */
2798
2799      send_ring          = send_ring->next;
2800      unitdata.udata.buf = send_ring->buffer_ptr;
2801
2802#ifdef WANT_HISTOGRAM
2803      /* get the second timestamp */
2804      HIST_timestamp(&time_two);
2805      HIST_add(time_hist,delta_micro(&time_one,&time_two));
2806#endif /* WANT_HISTOGRAM */
2807#ifdef WANT_INTERVALS
2808      if (demo_mode) {
2809	units_this_tick += send_size;
2810      }
2811      /* in this case, the interval count is the count-down couter */
2812      /* to decide to sleep for a little bit */
2813      if ((interval_burst) && (--interval_count == 0)) {
2814	/* call sigsuspend and wait for the interval timer to get us */
2815	/* out */
2816	if (debug) {
2817	  fprintf(where,"about to suspend\n");
2818	  fflush(where);
2819	}
2820	if (sigsuspend(&signal_set) == EFAULT) {
2821	  fprintf(where,
2822		  "send_xti_udp_stream: fault with signal set!\n");
2823	  fflush(where);
2824	  exit(1);
2825	}
2826	interval_count = interval_burst;
2827      }
2828#endif /* WANT_INTERVALS */
2829
2830    }
2831
2832    /* This is a timed test, so the remote will be returning to us after */
2833    /* a time. We should not need to send any "strange" messages to tell */
2834    /* the remote that the test is completed, unless we decide to add a */
2835    /* number of messages to the test. */
2836
2837    /* the test is over, so get stats and stuff */
2838    cpu_stop(local_cpu_usage,
2839	     &elapsed_time);
2840
2841    /* Get the statistics from the remote end	*/
2842    recv_response();
2843    if (!netperf_response.content.serv_errno) {
2844      if (debug)
2845	fprintf(where,"send_xti_udp_stream: remote results obtained\n");
2846    }
2847    else {
2848      Set_errno(netperf_response.content.serv_errno);
2849      perror("send_xti_udp_stream: error on remote");
2850      exit(1);
2851    }
2852
2853    bytes_sent    = (double) send_size * (double) messages_sent;
2854    local_thruput = calc_thruput(bytes_sent);
2855
2856    messages_recvd = xti_udp_stream_results->messages_recvd;
2857    bytes_recvd    = (double) send_size * (double) messages_recvd;
2858
2859    /* we asume that the remote ran for as long as we did */
2860
2861    remote_thruput = calc_thruput(bytes_recvd);
2862
2863    /* print the results for this socket and message size */
2864
2865    if (local_cpu_usage || remote_cpu_usage) {
2866      /* We must now do a little math for service demand and cpu */
2867      /* utilization for the system(s) We pass zeros for the local */
2868      /* cpu utilization and elapsed time to tell the routine to use */
2869      /* the libraries own values for those. */
2870      if (local_cpu_usage) {
2871	local_cpu_utilization	= calc_cpu_util(0.0);
2872	/* shouldn't this really be based on bytes_recvd, since that is */
2873	/* the effective throughput of the test? I think that it should, */
2874	/* so will make the change raj 11/94 */
2875	local_service_demand	= calc_service_demand(bytes_recvd,
2876						      0.0,
2877						      0.0,
2878						      0);
2879      }
2880      else {
2881	local_cpu_utilization	= -1.0;
2882	local_service_demand	= -1.0;
2883      }
2884
2885      /* The local calculations could use variables being kept by */
2886      /* the local netlib routines. The remote calcuations need to */
2887      /* have a few things passed to them. */
2888      if (remote_cpu_usage) {
2889	remote_cpu_utilization	= xti_udp_stream_results->cpu_util;
2890	remote_service_demand	= calc_service_demand(bytes_recvd,
2891						      0.0,
2892						      remote_cpu_utilization,
2893						      xti_udp_stream_results->num_cpus);
2894      }
2895      else {
2896	remote_cpu_utilization	= -1.0;
2897	remote_service_demand	= -1.0;
2898      }
2899    }
2900    else {
2901      /* we were not measuring cpu, for the confidence stuff, we */
2902      /* should make it -1.0 */
2903      local_cpu_utilization  = -1.0;
2904      local_service_demand   = -1.0;
2905      remote_cpu_utilization = -1.0;
2906      remote_service_demand  = -1.0;
2907    }
2908
2909    /* at this point, we want to calculate the confidence information. */
2910    /* if debugging is on, calculate_confidence will print-out the */
2911    /* parameters we pass it */
2912
2913    calculate_confidence(confidence_iteration,
2914			 elapsed_time,
2915			 remote_thruput,
2916			 local_cpu_utilization,
2917			 remote_cpu_utilization,
2918			 local_service_demand,
2919			 remote_service_demand);
2920
2921    /* since the routine calculate_confidence is rather generic, and */
2922    /* we have a few other parms of interest, we will do a little work */
2923    /* here to caclulate their average. */
2924    sum_messages_sent  += messages_sent;
2925    sum_messages_recvd += messages_recvd;
2926    sum_failed_sends   += failed_sends;
2927    sum_local_thruput  += local_thruput;
2928
2929    confidence_iteration++;
2930
2931    /* this datapoint is done, so we don't need the socket any longer */
2932    close(data_socket);
2933
2934  }
2935
2936  /* we should reach this point once the test is finished */
2937
2938  retrieve_confident_values(&elapsed_time,
2939			    &remote_thruput,
2940			    &local_cpu_utilization,
2941			    &remote_cpu_utilization,
2942			    &local_service_demand,
2943			    &remote_service_demand);
2944
2945  /* some of the interesting values aren't covered by the generic */
2946  /* confidence routine */
2947  messages_sent    = sum_messages_sent / (confidence_iteration -1);
2948  messages_recvd   = sum_messages_recvd / (confidence_iteration -1);
2949  failed_sends     = sum_failed_sends / (confidence_iteration -1);
2950  local_thruput    = sum_local_thruput / (confidence_iteration -1);
2951
2952  /* We are now ready to print all the information. If the user */
2953  /* has specified zero-level verbosity, we will just print the */
2954  /* local service demand, or the remote service demand. If the */
2955  /* user has requested verbosity level 1, he will get the basic */
2956  /* "streamperf" numbers. If the user has specified a verbosity */
2957  /* of greater than 1, we will display a veritable plethora of */
2958  /* background information from outside of this block as it it */
2959  /* not cpu_measurement specific...  */
2960
2961
2962  if (confidence < 0) {
2963    /* we did not hit confidence, but were we asked to look for it? */
2964    if (iteration_max > 1) {
2965      display_confidence();
2966    }
2967  }
2968
2969  if (local_cpu_usage || remote_cpu_usage) {
2970    local_cpu_method = format_cpu_method(cpu_method);
2971    remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method);
2972
2973    switch (verbosity) {
2974    case 0:
2975      if (local_cpu_usage) {
2976	fprintf(where,
2977		cpu_fmt_0,
2978		local_service_demand,
2979		local_cpu_method);
2980      }
2981      else {
2982	fprintf(where,
2983		cpu_fmt_0,
2984		remote_service_demand,
2985		local_cpu_method);
2986      }
2987      break;
2988    case 1:
2989    case 2:
2990      if (print_headers) {
2991	fprintf(where,
2992		cpu_title,
2993		format_units(),
2994		local_cpu_method,
2995		remote_cpu_method);
2996      }
2997
2998      fprintf(where,
2999	      cpu_fmt_1,		/* the format string */
3000	      lss_size,		        /* local sendbuf size */
3001	      send_size,		/* how large were the sends */
3002	      elapsed_time,		/* how long was the test */
3003	      messages_sent,
3004	      failed_sends,
3005	      local_thruput, 		/* what was the xfer rate */
3006	      local_cpu_utilization,	/* local cpu */
3007	      local_service_demand,	/* local service demand */
3008	      rsr_size,
3009	      elapsed_time,
3010	      messages_recvd,
3011	      remote_thruput,
3012	      remote_cpu_utilization,	/* remote cpu */
3013	      remote_service_demand);	/* remote service demand */
3014      break;
3015    }
3016  }
3017  else {
3018    /* The tester did not wish to measure service demand. */
3019    switch (verbosity) {
3020    case 0:
3021      fprintf(where,
3022	      tput_fmt_0,
3023	      local_thruput);
3024      break;
3025    case 1:
3026    case 2:
3027      if (print_headers) {
3028	fprintf(where,tput_title,format_units());
3029      }
3030      fprintf(where,
3031	      tput_fmt_1,		/* the format string */
3032	      lss_size, 		/* local sendbuf size */
3033	      send_size,		/* how large were the sends */
3034	      elapsed_time, 		/* how long did it take */
3035	      messages_sent,
3036	      failed_sends,
3037	      local_thruput,
3038	      rsr_size, 		/* remote recvbuf size */
3039	      elapsed_time,
3040	      messages_recvd,
3041	      remote_thruput);
3042      break;
3043    }
3044  }
3045
3046  fflush(where);
3047#ifdef WANT_HISTOGRAM
3048  if (verbosity > 1) {
3049    fprintf(where,"\nHistogram of time spent in send() call\n");
3050    fflush(where);
3051    HIST_report(time_hist);
3052  }
3053#endif /* WANT_HISTOGRAM */
3054
3055}
3056
3057
3058 /* this routine implements the receive side (netserver) of the */
3059 /* XTI_UDP_STREAM performance test. */
3060
3061void
3062recv_xti_udp_stream()
3063{
3064  struct ring_elt *recv_ring;
3065
3066  struct t_bind bind_req, bind_resp;
3067  struct t_unitdata unitdata;
3068  int	            flags = 0;
3069
3070  struct sockaddr_in myaddr_in;
3071  struct sockaddr_in fromaddr_in;
3072
3073  SOCKET s_data;
3074  int 	addrlen;
3075  unsigned int	bytes_received = 0;
3076  float	elapsed_time;
3077
3078  unsigned int	message_size;
3079  unsigned int	messages_recvd = 0;
3080
3081  struct xti_udp_stream_request_struct	*xti_udp_stream_request;
3082  struct xti_udp_stream_response_struct	*xti_udp_stream_response;
3083  struct xti_udp_stream_results_struct	*xti_udp_stream_results;
3084
3085  xti_udp_stream_request  =
3086    (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
3087  xti_udp_stream_response =
3088    (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
3089  xti_udp_stream_results  =
3090    (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
3091
3092  if (debug) {
3093    fprintf(where,"netserver: recv_xti_udp_stream: entered...\n");
3094    fflush(where);
3095  }
3096
3097  /* We want to set-up the listen socket with all the desired */
3098  /* parameters and then let the initiator know that all is ready. If */
3099  /* socket size defaults are to be used, then the initiator will have */
3100  /* sent us 0's. If the socket sizes cannot be changed, then we will */
3101  /* send-back what they are. If that information cannot be determined, */
3102  /* then we send-back -1's for the sizes. If things go wrong for any */
3103  /* reason, we will drop back ten yards and punt. */
3104
3105  /* If anything goes wrong, we want the remote to know about it. It */
3106  /* would be best if the error that the remote reports to the user is */
3107  /* the actual error we encountered, rather than some bogus unexpected */
3108  /* response type message. */
3109
3110  if (debug > 1) {
3111    fprintf(where,"recv_xti_udp_stream: setting the response type...\n");
3112    fflush(where);
3113  }
3114
3115  netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE;
3116
3117  if (debug > 2) {
3118    fprintf(where,"recv_xti_udp_stream: the response type is set...\n");
3119    fflush(where);
3120  }
3121
3122  /* We now alter the message_ptr variable to be at the desired */
3123  /* alignment with the desired offset. */
3124
3125  if (debug > 1) {
3126    fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n",
3127	    xti_udp_stream_request->recv_alignment);
3128    fflush(where);
3129  }
3130
3131  if (recv_width == 0) recv_width = 1;
3132
3133  recv_ring = allocate_buffer_ring(recv_width,
3134				   xti_udp_stream_request->message_size,
3135				   xti_udp_stream_request->recv_alignment,
3136				   xti_udp_stream_request->recv_offset);
3137
3138  if (debug > 1) {
3139    fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n");
3140    fflush(where);
3141  }
3142
3143  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
3144  /* can put in OUR values !-) At some point, we may want to nail this */
3145  /* socket to a particular network-level address, but for now, */
3146  /* INADDR_ANY should be just fine. */
3147
3148  bzero((char *)&myaddr_in,
3149	sizeof(myaddr_in));
3150  myaddr_in.sin_family      = AF_INET;
3151  myaddr_in.sin_addr.s_addr = INADDR_ANY;
3152  myaddr_in.sin_port        = 0;
3153
3154  /* Grab a socket to listen on, and then listen on it. */
3155
3156  if (debug > 1) {
3157    fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n");
3158    fflush(where);
3159  }
3160
3161  /* create_xti_endpoint expects to find some things in the global */
3162  /* variables, so set the globals based on the values in the request. */
3163  /* once the socket has been created, we will set the response values */
3164  /* based on the updated value of those globals. raj 7/94 */
3165  lsr_size = xti_udp_stream_request->recv_buf_size;
3166  loc_rcvavoid = xti_udp_stream_request->so_rcvavoid;
3167  loc_sndavoid = xti_udp_stream_request->so_sndavoid;
3168
3169#ifdef __alpha
3170
3171  /* ok - even on a DEC box, strings are strings. I din't really want */
3172  /* to ntohl the words of a string. since I don't want to teach the */
3173  /* send_ and recv_ _request and _response routines about the types, */
3174  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3175  /* solution would be to use XDR, but I am still leary of being able */
3176  /* to find XDR libs on all platforms I want running netperf. raj */
3177  {
3178    int *charword;
3179    int *initword;
3180    int *lastword;
3181
3182    initword = (int *) xti_udp_stream_request->xti_device;
3183    lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4);
3184
3185    for (charword = initword;
3186	 charword < lastword;
3187	 charword++) {
3188
3189      *charword = htonl(*charword);
3190    }
3191  }
3192
3193#endif /* __alpha */
3194
3195  s_data = create_xti_endpoint(xti_udp_stream_request->xti_device);
3196
3197  if (s_data == INVALID_SOCKET) {
3198    netperf_response.content.serv_errno = errno;
3199    send_response();
3200    exit(1);
3201  }
3202
3203  /* Let's get an address assigned to this socket so we can tell the */
3204  /* initiator how to reach the data socket. There may be a desire to */
3205  /* nail this socket to a specific IP address in a multi-homed, */
3206  /* multi-connection situation, but for now, we'll ignore the issue */
3207  /* and concentrate on single connection testing. */
3208
3209  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
3210  bind_req.addr.len    = sizeof(struct sockaddr_in);
3211  bind_req.addr.buf    = (char *)&myaddr_in;
3212  bind_req.qlen        = 1;
3213
3214  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
3215  bind_resp.addr.len    = sizeof(struct sockaddr_in);
3216  bind_resp.addr.buf    = (char *)&myaddr_in;
3217  bind_resp.qlen        = 1;
3218
3219  if (t_bind(s_data,
3220	     &bind_req,
3221	     &bind_resp) == SOCKET_ERROR) {
3222    netperf_response.content.serv_errno = t_errno;
3223    send_response();
3224
3225    exit(1);
3226  }
3227
3228  xti_udp_stream_response->test_length =
3229    xti_udp_stream_request->test_length;
3230
3231  /* Now myaddr_in contains the port and the internet address this is */
3232  /* returned to the sender also implicitly telling the sender that the */
3233  /* socket buffer sizing has been done. */
3234
3235  xti_udp_stream_response->data_port_number =
3236    (int) ntohs(myaddr_in.sin_port);
3237  netperf_response.content.serv_errno   = 0;
3238
3239  /* But wait, there's more. If the initiator wanted cpu measurements, */
3240  /* then we must call the calibrate routine, which will return the max */
3241  /* rate back to the initiator. If the CPU was not to be measured, or */
3242  /* something went wrong with the calibration, we will return a -1 to */
3243  /* the initiator. */
3244
3245  xti_udp_stream_response->cpu_rate    = 0.0; /* assume no cpu */
3246  xti_udp_stream_response->measure_cpu = 0;
3247  if (xti_udp_stream_request->measure_cpu) {
3248    /* We will pass the rate into the calibration routine. If the */
3249    /* user did not specify one, it will be 0.0, and we will do a */
3250    /* "real" calibration. Otherwise, all it will really do is */
3251    /* store it away... */
3252    xti_udp_stream_response->measure_cpu = 1;
3253    xti_udp_stream_response->cpu_rate =
3254      calibrate_local_cpu(xti_udp_stream_request->cpu_rate);
3255  }
3256
3257  message_size	= xti_udp_stream_request->message_size;
3258  test_time	= xti_udp_stream_request->test_length;
3259
3260  /* before we send the response back to the initiator, pull some of */
3261  /* the socket parms from the globals */
3262  xti_udp_stream_response->send_buf_size = lss_size;
3263  xti_udp_stream_response->recv_buf_size = lsr_size;
3264  xti_udp_stream_response->so_rcvavoid = loc_rcvavoid;
3265  xti_udp_stream_response->so_sndavoid = loc_sndavoid;
3266
3267  /* since we are going to call t_rcvudata() instead of t_rcv() we */
3268  /* need to init the unitdata structure raj 3/95 */
3269
3270  unitdata.addr.maxlen = sizeof(fromaddr_in);
3271  unitdata.addr.len    = sizeof(fromaddr_in);
3272  unitdata.addr.buf    = (char *)&fromaddr_in;
3273
3274  unitdata.opt.maxlen = 0;
3275  unitdata.opt.len    = 0;
3276  unitdata.opt.buf    = NULL;
3277
3278  unitdata.udata.maxlen = xti_udp_stream_request->message_size;
3279  unitdata.udata.len    = xti_udp_stream_request->message_size;
3280  unitdata.udata.buf    = recv_ring->buffer_ptr;
3281
3282  send_response();
3283
3284  /* Now it's time to start receiving data on the connection. We will */
3285  /* first grab the apropriate counters and then start grabbing. */
3286
3287  cpu_start(xti_udp_stream_request->measure_cpu);
3288
3289  /* The loop will exit when the timer pops, or if we happen to recv a */
3290  /* message of less than send_size bytes... */
3291
3292  times_up = 0;
3293  start_timer(test_time + PAD_TIME);
3294
3295  if (debug) {
3296    fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n");
3297    fflush(where);
3298  }
3299
3300  while (!times_up) {
3301#ifdef RAJ_DEBUG
3302    if (debug) {
3303      fprintf(where,"t_rcvudata, errno %d, t_errno %d",
3304	      errno,
3305	      t_errno);
3306      fprintf(where," after %d messages\n",messages_recvd);
3307      fprintf(where,"addrmax %d addrlen %d addrbuf %x\n",
3308	      unitdata.addr.maxlen,
3309	      unitdata.addr.len,
3310	      unitdata.addr.buf);
3311      fprintf(where,"optmax %d optlen %d optbuf %x\n",
3312	      unitdata.opt.maxlen,
3313	      unitdata.opt.len,
3314	      unitdata.opt.buf);
3315      fprintf(where,"udatamax %d udatalen %d udatabuf %x\n",
3316	      unitdata.udata.maxlen,
3317	      unitdata.udata.len,
3318	      unitdata.udata.buf);
3319      fflush(where);
3320    }
3321#endif /* RAJ_DEBUG */
3322    if (t_rcvudata(s_data,
3323		   &unitdata,
3324		   &flags) != 0) {
3325      if (errno == TNODATA) {
3326	continue;
3327      }
3328      if (errno != EINTR) {
3329	netperf_response.content.serv_errno = t_errno;
3330	send_response();
3331	exit(1);
3332      }
3333      break;
3334    }
3335    messages_recvd++;
3336    recv_ring = recv_ring->next;
3337    unitdata.udata.buf = recv_ring->buffer_ptr;
3338  }
3339
3340  if (debug) {
3341    fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd);
3342    fflush(where);
3343  }
3344
3345
3346  /* The loop now exits due timer or < send_size bytes received. */
3347
3348  cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time);
3349
3350  if (times_up) {
3351    /* we ended on a timer, subtract the PAD_TIME */
3352    elapsed_time -= (float)PAD_TIME;
3353  }
3354  else {
3355    stop_timer();
3356  }
3357
3358  if (debug) {
3359    fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time);
3360    fflush(where);
3361  }
3362
3363  bytes_received = (messages_recvd * message_size);
3364
3365  /* send the results to the sender			*/
3366
3367  if (debug) {
3368    fprintf(where,
3369	    "recv_xti_udp_stream: got %d bytes\n",
3370	    bytes_received);
3371    fflush(where);
3372  }
3373
3374  netperf_response.content.response_type	= XTI_UDP_STREAM_RESULTS;
3375  xti_udp_stream_results->bytes_received	= bytes_received;
3376  xti_udp_stream_results->messages_recvd	= messages_recvd;
3377  xti_udp_stream_results->elapsed_time	= elapsed_time;
3378  xti_udp_stream_results->cpu_method        = cpu_method;
3379  if (xti_udp_stream_request->measure_cpu) {
3380    xti_udp_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
3381  }
3382  else {
3383    xti_udp_stream_results->cpu_util	= -1.0;
3384  }
3385
3386  if (debug > 1) {
3387    fprintf(where,
3388	    "recv_xti_udp_stream: test complete, sending results.\n");
3389    fflush(where);
3390  }
3391
3392  send_response();
3393
3394}
3395
3396void send_xti_udp_rr(char remote_host[])
3397{
3398
3399  char *tput_title = "\
3400Local /Remote\n\
3401Socket Size   Request  Resp.   Elapsed  Trans.\n\
3402Send   Recv   Size     Size    Time     Rate         \n\
3403bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
3404
3405  char *tput_fmt_0 =
3406    "%7.2f\n";
3407
3408  char *tput_fmt_1_line_1 = "\
3409%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
3410  char *tput_fmt_1_line_2 = "\
3411%-6d %-6d\n";
3412
3413  char *cpu_title = "\
3414Local /Remote\n\
3415Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
3416Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
3417bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
3418
3419  char *cpu_fmt_0 =
3420    "%6.3f %c\n";
3421
3422  char *cpu_fmt_1_line_1 = "\
3423%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
3424
3425  char *cpu_fmt_1_line_2 = "\
3426%-6d %-6d\n";
3427
3428  char *ksink_fmt = "\
3429Alignment      Offset\n\
3430Local  Remote  Local  Remote\n\
3431Send   Recv    Send   Recv\n\
3432%5d  %5d   %5d  %5d\n";
3433
3434
3435  float			elapsed_time;
3436
3437  struct ring_elt *send_ring;
3438  struct ring_elt *recv_ring;
3439
3440  struct t_bind bind_req, bind_resp;
3441  struct t_unitdata unitdata;
3442  struct t_unitdata send_unitdata;
3443  struct t_unitdata recv_unitdata;
3444  int	            flags = 0;
3445
3446  int	len;
3447  int	nummessages;
3448  SOCKET send_socket;
3449  int	trans_remaining;
3450  int	bytes_xferd;
3451
3452  int	rsp_bytes_recvd;
3453
3454  float	local_cpu_utilization;
3455  float	local_service_demand;
3456  float	remote_cpu_utilization;
3457  float	remote_service_demand;
3458  double thruput;
3459
3460  struct	hostent	        *hp;
3461  struct	sockaddr_in	server, myaddr_in;
3462  unsigned      int             addr;
3463  int	                        addrlen;
3464
3465  struct	xti_udp_rr_request_struct	*xti_udp_rr_request;
3466  struct	xti_udp_rr_response_struct	*xti_udp_rr_response;
3467  struct	xti_udp_rr_results_struct	*xti_udp_rr_result;
3468
3469#ifdef WANT_INTERVALS
3470  int	interval_count;
3471  sigset_t signal_set;
3472#endif /* WANT_INTERVALS */
3473
3474  xti_udp_rr_request  =
3475    (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
3476  xti_udp_rr_response =
3477    (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
3478  xti_udp_rr_result	 =
3479    (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
3480
3481#ifdef WANT_HISTOGRAM
3482  time_hist = HIST_new();
3483#endif
3484
3485  /* since we are now disconnected from the code that established the */
3486  /* control socket, and since we want to be able to use different */
3487  /* protocols and such, we are passed the name of the remote host and */
3488  /* must turn that into the test specific addressing information. */
3489
3490  bzero((char *)&server,
3491	sizeof(server));
3492
3493  /* it would seem that while HP-UX will allow an IP address (as a */
3494  /* string) in a call to gethostbyname, other, less enlightened */
3495  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
3496  /* order changed to check for IP address first. raj 7/96 */
3497
3498  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
3499    /* it was not an IP address, try it as a name */
3500    if ((hp = gethostbyname(remote_host)) == NULL) {
3501      /* we have no idea what it is */
3502      fprintf(where,
3503	      "establish_control: could not resolve the destination %s\n",
3504	      remote_host);
3505      fflush(where);
3506      exit(1);
3507    }
3508    else {
3509      /* it was a valid remote_host */
3510      bcopy(hp->h_addr,
3511	    (char *)&server.sin_addr,
3512	    hp->h_length);
3513      server.sin_family = hp->h_addrtype;
3514    }
3515  }
3516  else {
3517    /* it was a valid IP address */
3518    server.sin_addr.s_addr = addr;
3519    server.sin_family = AF_INET;
3520  }
3521
3522  if ( print_headers ) {
3523    fprintf(where,"XTI UDP REQUEST/RESPONSE TEST");
3524        fprintf(where," to %s", remote_host);
3525    if (iteration_max > 1) {
3526      fprintf(where,
3527	      " : +/-%3.1f%% @ %2d%% conf.",
3528	      interval/0.02,
3529	      confidence_level);
3530      }
3531    if (loc_sndavoid ||
3532	loc_rcvavoid ||
3533	rem_sndavoid ||
3534	rem_rcvavoid) {
3535      fprintf(where," : copy avoidance");
3536    }
3537#ifdef WANT_HISTOGRAM
3538    fprintf(where," : histogram");
3539#endif /* WANT_HISTOGRAM */
3540#ifdef WANT_INTERVALS
3541    fprintf(where," : interval");
3542#endif /* WANT_INTERVALS */
3543#ifdef DIRTY
3544    fprintf(where," : dirty data");
3545#endif /* DIRTY */
3546    fprintf(where,"\n");
3547  }
3548
3549  /* initialize a few counters */
3550
3551  send_ring     = NULL;
3552  recv_ring     = NULL;
3553  nummessages	= 0;
3554  bytes_xferd	= 0;
3555  times_up 	= 0;
3556  confidence_iteration = 1;
3557  init_stat();
3558
3559
3560  /* we have a great-big while loop which controls the number of times */
3561  /* we run a particular test. this is for the calculation of a */
3562  /* confidence interval (I really should have stayed awake during */
3563  /* probstats :). If the user did not request confidence measurement */
3564  /* (no confidence is the default) then we will only go though the */
3565  /* loop once. the confidence stuff originates from the folks at IBM */
3566
3567  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
3568	 (confidence_iteration <= iteration_min)) {
3569
3570    nummessages     = 0;
3571    bytes_xferd     = 0.0;
3572    times_up        = 0;
3573    trans_remaining = 0;
3574
3575    /* set-up the data buffers with the requested alignment and offset */
3576
3577    if (send_width == 0) send_width = 1;
3578    if (recv_width == 0) recv_width = 1;
3579
3580    if (send_ring == NULL) {
3581      send_ring = allocate_buffer_ring(send_width,
3582				       req_size,
3583				       local_send_align,
3584				       local_send_offset);
3585    }
3586
3587    if (recv_ring == NULL) {
3588      recv_ring = allocate_buffer_ring(recv_width,
3589				       rsp_size,
3590				       local_recv_align,
3591				       local_recv_offset);
3592    }
3593
3594  /* since we are going to call t_rcvudata() instead of t_rcv() we */
3595  /* need to init the unitdata structure raj 8/95 */
3596
3597    memset (&recv_unitdata, 0, sizeof(recv_unitdata));
3598    recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3599    recv_unitdata.addr.len    = sizeof(struct sockaddr_in);
3600    recv_unitdata.addr.buf    = (char *)&server;
3601
3602    recv_unitdata.opt.maxlen = 0;
3603    recv_unitdata.opt.len    = 0;
3604    recv_unitdata.opt.buf    = NULL;
3605
3606    recv_unitdata.udata.maxlen = rsp_size;
3607    recv_unitdata.udata.len    = rsp_size;
3608    recv_unitdata.udata.buf    = recv_ring->buffer_ptr;
3609
3610    /* since we are going to call t_sndudata() instead of t_snd() we */
3611    /* need to init the unitdata structure raj 8/95 */
3612
3613    memset (&send_unitdata, 0, sizeof(send_unitdata));
3614    send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
3615    send_unitdata.addr.len    = sizeof(struct sockaddr_in);
3616    send_unitdata.addr.buf    = (char *)&server;
3617
3618    send_unitdata.opt.maxlen = 0;
3619    send_unitdata.opt.len    = 0;
3620    send_unitdata.opt.buf    = NULL;
3621
3622    send_unitdata.udata.maxlen = req_size;
3623    send_unitdata.udata.len    = req_size;
3624    send_unitdata.udata.buf    = send_ring->buffer_ptr;
3625
3626    /*set up the data socket                        */
3627    send_socket = create_xti_endpoint(loc_xti_device);
3628
3629    if (send_socket == INVALID_SOCKET){
3630      perror("netperf: send_xti_udp_rr: udp rr data socket");
3631      exit(1);
3632    }
3633
3634    if (debug) {
3635      fprintf(where,"send_xti_udp_rr: send_socket obtained...\n");
3636    }
3637
3638    /* it would seem that with XTI, there is no implicit bind  */
3639    /* so we have to make a call to t_bind. this is not */
3640    /* terribly convenient, but I suppose that "standard is better */
3641    /* than better" :) raj 2/95 */
3642
3643    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
3644      t_error("send_xti_tcp_stream: t_bind");
3645      exit(1);
3646    }
3647
3648    /* If the user has requested cpu utilization measurements, we must */
3649    /* calibrate the cpu(s). We will perform this task within the tests */
3650    /* themselves. If the user has specified the cpu rate, then */
3651    /* calibrate_local_cpu will return rather quickly as it will have */
3652    /* nothing to do. If local_cpu_rate is zero, then we will go through */
3653    /* all the "normal" calibration stuff and return the rate back. If */
3654    /* there is no idle counter in the kernel idle loop, the */
3655    /* local_cpu_rate will be set to -1. */
3656
3657    if (local_cpu_usage) {
3658      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
3659    }
3660
3661    /* Tell the remote end to do a listen. The server alters the socket */
3662    /* paramters on the other side at this point, hence the reason for */
3663    /* all the values being passed in the setup message. If the user did */
3664    /* not specify any of the parameters, they will be passed as 0, which */
3665    /* will indicate to the remote that no changes beyond the system's */
3666    /* default should be used. Alignment is the exception, it will */
3667    /* default to 8, which will be no alignment alterations. */
3668
3669    netperf_request.content.request_type	= DO_XTI_UDP_RR;
3670    xti_udp_rr_request->recv_buf_size	= rsr_size;
3671    xti_udp_rr_request->send_buf_size	= rss_size;
3672    xti_udp_rr_request->recv_alignment  = remote_recv_align;
3673    xti_udp_rr_request->recv_offset	= remote_recv_offset;
3674    xti_udp_rr_request->send_alignment  = remote_send_align;
3675    xti_udp_rr_request->send_offset	= remote_send_offset;
3676    xti_udp_rr_request->request_size	= req_size;
3677    xti_udp_rr_request->response_size	= rsp_size;
3678    xti_udp_rr_request->measure_cpu	= remote_cpu_usage;
3679    xti_udp_rr_request->cpu_rate	= remote_cpu_rate;
3680    xti_udp_rr_request->so_rcvavoid	= rem_rcvavoid;
3681    xti_udp_rr_request->so_sndavoid	= rem_sndavoid;
3682    if (test_time) {
3683      xti_udp_rr_request->test_length	= test_time;
3684    }
3685    else {
3686      xti_udp_rr_request->test_length	= test_trans * -1;
3687    }
3688
3689    strcpy(xti_udp_rr_request->xti_device, rem_xti_device);
3690
3691#ifdef __alpha
3692
3693    /* ok - even on a DEC box, strings are strings. I didn't really want */
3694    /* to ntohl the words of a string. since I don't want to teach the */
3695    /* send_ and recv_ _request and _response routines about the types, */
3696    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
3697    /* solution would be to use XDR, but I am still leary of being able */
3698    /* to find XDR libs on all platforms I want running netperf. raj */
3699    {
3700      int *charword;
3701      int *initword;
3702      int *lastword;
3703
3704      initword = (int *) xti_udp_rr_request->xti_device;
3705      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
3706
3707      for (charword = initword;
3708	   charword < lastword;
3709	   charword++) {
3710
3711	*charword = ntohl(*charword);
3712      }
3713    }
3714#endif /* __alpha */
3715
3716    if (debug > 1) {
3717      fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n");
3718    }
3719
3720    send_request();
3721
3722    /* The response from the remote will contain all of the relevant 	*/
3723    /* socket parameters for this test type. We will put them back into */
3724    /* the variables here so they can be displayed if desired.  The	*/
3725    /* remote will have calibrated CPU if necessary, and will have done	*/
3726    /* all the needed set-up we will have calibrated the cpu locally	*/
3727    /* before sending the request, and will grab the counter value right*/
3728    /* after the connect returns. The remote will grab the counter right*/
3729    /* after the accept call. This saves the hassle of extra messages	*/
3730    /* being sent for the UDP tests.					*/
3731
3732    recv_response();
3733
3734    if (!netperf_response.content.serv_errno) {
3735      if (debug)
3736	fprintf(where,"remote listen done.\n");
3737      rsr_size	       =	xti_udp_rr_response->recv_buf_size;
3738      rss_size	       =	xti_udp_rr_response->send_buf_size;
3739      remote_cpu_usage =	xti_udp_rr_response->measure_cpu;
3740      remote_cpu_rate  = 	xti_udp_rr_response->cpu_rate;
3741      /* port numbers in proper order */
3742      server.sin_port  =	(short)xti_udp_rr_response->data_port_number;
3743      server.sin_port  = 	htons(server.sin_port);
3744    }
3745    else {
3746      Set_errno(netperf_response.content.serv_errno);
3747      perror("netperf: remote error");
3748
3749      exit(1);
3750    }
3751
3752    /* Data Socket set-up is finished. If there were problems, either the */
3753    /* connect would have failed, or the previous response would have */
3754    /* indicated a problem. I failed to see the value of the extra */
3755    /* message after the accept on the remote. If it failed, we'll see it */
3756    /* here. If it didn't, we might as well start pumping data. */
3757
3758    /* Set-up the test end conditions. For a request/response test, they */
3759    /* can be either time or transaction based. */
3760
3761    if (test_time) {
3762      /* The user wanted to end the test after a period of time. */
3763      times_up = 0;
3764      trans_remaining = 0;
3765      start_timer(test_time);
3766    }
3767    else {
3768      /* The tester wanted to send a number of bytes. */
3769      trans_remaining = test_bytes;
3770      times_up = 1;
3771    }
3772
3773    /* The cpu_start routine will grab the current time and possibly */
3774    /* value of the idle counter for later use in measuring cpu */
3775    /* utilization and/or service demand and thruput. */
3776
3777    cpu_start(local_cpu_usage);
3778
3779#ifdef WANT_INTERVALS
3780    if ((interval_burst) || (demo_mode)) {
3781      /* zero means that we never pause, so we never should need the */
3782      /* interval timer, unless we are in demo_mode */
3783      start_itimer(interval_wate);
3784    }
3785    interval_count = interval_burst;
3786    /* get the signal set for the call to sigsuspend */
3787    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
3788      fprintf(where,
3789	      "send_xti_udp_rr: unable to get sigmask errno %d\n",
3790	      errno);
3791      fflush(where);
3792      exit(1);
3793    }
3794#endif /* WANT_INTERVALS */
3795
3796    /* We use an "OR" to control test execution. When the test is */
3797    /* controlled by time, the byte count check will always return */
3798    /* false. When the test is controlled by byte count, the time test */
3799    /* will always return false. When the test is finished, the whole */
3800    /* expression will go false and we will stop sending data. I think */
3801    /* I just arbitrarily decrement trans_remaining for the timed */
3802    /* test, but will not do that just yet... One other question is */
3803    /* whether or not the send buffer and the receive buffer should be */
3804    /* the same buffer. */
3805
3806    while ((!times_up) || (trans_remaining > 0)) {
3807      /* send the request */
3808#ifdef WANT_HISTOGRAM
3809      HIST_timestamp(&time_one);
3810#endif
3811      if((t_sndudata(send_socket,
3812		     &send_unitdata)) != 0) {
3813	if (errno == EINTR) {
3814	  /* We likely hit */
3815	  /* test-end time. */
3816	  break;
3817	}
3818        fprintf(where,
3819		"send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n",
3820		errno,
3821		t_errno,
3822		t_look(send_socket));
3823	fflush(where);
3824	exit(1);
3825      }
3826      send_ring = send_ring->next;
3827
3828      /* receive the response. with UDP we will get it all, or nothing */
3829
3830      if((t_rcvudata(send_socket,
3831		     &recv_unitdata,
3832		     &flags)) != 0) {
3833	if (errno == TNODATA) {
3834	  continue;
3835	}
3836	if (errno == EINTR) {
3837	  /* Again, we have likely hit test-end time */
3838	  break;
3839	}
3840	fprintf(where,
3841		"send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n",
3842		errno,
3843		t_errno,
3844		t_look(send_socket));
3845	fprintf(where,
3846		"recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf);
3847	fprintf(where,
3848		"recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen);
3849	fprintf(where,
3850		"recv_unitdata.udata.len %x\n",recv_unitdata.udata.len);
3851	fprintf(where,
3852		"recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf);
3853	fprintf(where,
3854		"recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen);
3855	fprintf(where,
3856		"recv_unitdata.addr.len %x\n",recv_unitdata.addr.len);
3857	fflush(where);
3858	exit(1);
3859      }
3860      recv_ring = recv_ring->next;
3861
3862#ifdef WANT_HISTOGRAM
3863      HIST_timestamp(&time_two);
3864      HIST_add(time_hist,delta_micro(&time_one,&time_two));
3865
3866      /* at this point, we may wish to sleep for some period of */
3867      /* time, so we see how long that last transaction just took, */
3868      /* and sleep for the difference of that and the interval. We */
3869      /* will not sleep if the time would be less than a */
3870      /* millisecond.  */
3871#endif
3872#ifdef WANT_INTERVALS
3873      if (demo_mode) {
3874	units_this_tick += 1;
3875      }
3876      /* in this case, the interval count is the count-down couter */
3877      /* to decide to sleep for a little bit */
3878      if ((interval_burst) && (--interval_count == 0)) {
3879	/* call sigsuspend and wait for the interval timer to get us */
3880	/* out */
3881	if (debug) {
3882	  fprintf(where,"about to suspend\n");
3883	  fflush(where);
3884	}
3885	if (sigsuspend(&signal_set) == EFAULT) {
3886	  fprintf(where,
3887		  "send_xti_udp_rr: fault with signal set!\n");
3888	  fflush(where);
3889	  exit(1);
3890	}
3891	interval_count = interval_burst;
3892      }
3893#endif /* WANT_INTERVALS */
3894
3895      nummessages++;
3896      if (trans_remaining) {
3897	trans_remaining--;
3898      }
3899
3900      if (debug > 3) {
3901	if ((nummessages % 100) == 0) {
3902	  fprintf(where,"Transaction %d completed\n",nummessages);
3903	  fflush(where);
3904	}
3905      }
3906
3907    }
3908
3909    /* this call will always give us the elapsed time for the test, and */
3910    /* will also store-away the necessaries for cpu utilization */
3911
3912    cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being */
3913						/* measured? how long */
3914						/* did we really run? */
3915
3916    /* Get the statistics from the remote end. The remote will have */
3917    /* calculated service demand and all those interesting things. If */
3918    /* it wasn't supposed to care, it will return obvious values. */
3919
3920    recv_response();
3921    if (!netperf_response.content.serv_errno) {
3922      if (debug)
3923	fprintf(where,"remote results obtained\n");
3924    }
3925    else {
3926      Set_errno(netperf_response.content.serv_errno);
3927      perror("netperf: remote error");
3928
3929      exit(1);
3930    }
3931
3932    /* We now calculate what our thruput was for the test. In the */
3933    /* future, we may want to include a calculation of the thruput */
3934    /* measured by the remote, but it should be the case that for a */
3935    /* UDP rr test, that the two numbers should be *very* close... */
3936    /* We calculate bytes_sent regardless of the way the test length */
3937    /* was controlled.  */
3938
3939    bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
3940    thruput	= nummessages / elapsed_time;
3941
3942    if (local_cpu_usage || remote_cpu_usage) {
3943
3944      /* We must now do a little math for service demand and cpu */
3945      /* utilization for the system(s) Of course, some of the */
3946      /* information might be bogus because there was no idle counter */
3947      /* in the kernel(s). We need to make a note of this for the */
3948      /* user's benefit by placing a code for the metod used in the */
3949      /* test banner */
3950
3951      if (local_cpu_usage) {
3952	local_cpu_utilization = calc_cpu_util(0.0);
3953
3954	/* since calc_service demand is doing ms/Kunit we will */
3955	/* multiply the number of transaction by 1024 to get */
3956	/* "good" numbers */
3957
3958	local_service_demand  = calc_service_demand((double) nummessages*1024,
3959						    0.0,
3960						    0.0,
3961						    0);
3962      }
3963      else {
3964	local_cpu_utilization	= -1.0;
3965	local_service_demand	= -1.0;
3966      }
3967
3968      if (remote_cpu_usage) {
3969	remote_cpu_utilization = xti_udp_rr_result->cpu_util;
3970
3971	/* since calc_service demand is doing ms/Kunit we will */
3972	/* multiply the number of transaction by 1024 to get */
3973	/* "good" numbers */
3974
3975	remote_service_demand  = calc_service_demand((double) nummessages*1024,
3976						     0.0,
3977						     remote_cpu_utilization,
3978						     xti_udp_rr_result->num_cpus);
3979      }
3980      else {
3981	remote_cpu_utilization = -1.0;
3982	remote_service_demand  = -1.0;
3983      }
3984    }
3985    else {
3986      /* we were not measuring cpu, for the confidence stuff, we */
3987      /* should make it -1.0 */
3988      local_cpu_utilization	= -1.0;
3989      local_service_demand	= -1.0;
3990      remote_cpu_utilization = -1.0;
3991      remote_service_demand  = -1.0;
3992    }
3993
3994    /* at this point, we want to calculate the confidence information. */
3995    /* if debugging is on, calculate_confidence will print-out the */
3996    /* parameters we pass it */
3997
3998    calculate_confidence(confidence_iteration,
3999			 elapsed_time,
4000			 thruput,
4001			 local_cpu_utilization,
4002			 remote_cpu_utilization,
4003			 local_service_demand,
4004			 remote_service_demand);
4005
4006
4007    confidence_iteration++;
4008
4009    /* we are done with the socket */
4010    t_close(send_socket);
4011  }
4012
4013  /* at this point, we have made all the iterations we are going to */
4014  /* make. */
4015  retrieve_confident_values(&elapsed_time,
4016			    &thruput,
4017			    &local_cpu_utilization,
4018			    &remote_cpu_utilization,
4019			    &local_service_demand,
4020			    &remote_service_demand);
4021
4022  /* We are now ready to print all the information. If the user */
4023  /* has specified zero-level verbosity, we will just print the */
4024  /* local service demand, or the remote service demand. If the */
4025  /* user has requested verbosity level 1, he will get the basic */
4026  /* "streamperf" numbers. If the user has specified a verbosity */
4027  /* of greater than 1, we will display a veritable plethora of */
4028  /* background information from outside of this block as it it */
4029  /* not cpu_measurement specific...  */
4030
4031  if (confidence < 0) {
4032    /* we did not hit confidence, but were we asked to look for it? */
4033    if (iteration_max > 1) {
4034      display_confidence();
4035    }
4036  }
4037
4038  if (local_cpu_usage || remote_cpu_usage) {
4039    local_cpu_method = format_cpu_method(cpu_method);
4040    remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method);
4041
4042    switch (verbosity) {
4043    case 0:
4044      if (local_cpu_usage) {
4045	fprintf(where,
4046		cpu_fmt_0,
4047		local_service_demand,
4048		local_cpu_method);
4049      }
4050      else {
4051	fprintf(where,
4052		cpu_fmt_0,
4053		remote_service_demand,
4054		remote_cpu_method);
4055      }
4056      break;
4057    case 1:
4058    case 2:
4059      if (print_headers) {
4060	fprintf(where,
4061		cpu_title,
4062		local_cpu_method,
4063		remote_cpu_method);
4064      }
4065
4066      fprintf(where,
4067	      cpu_fmt_1_line_1,		/* the format string */
4068	      lss_size,		/* local sendbuf size */
4069	      lsr_size,
4070	      req_size,		/* how large were the requests */
4071	      rsp_size,		/* guess */
4072	      elapsed_time,		/* how long was the test */
4073	      nummessages/elapsed_time,
4074	      local_cpu_utilization,	/* local cpu */
4075	      remote_cpu_utilization,	/* remote cpu */
4076	      local_service_demand,	/* local service demand */
4077	      remote_service_demand);	/* remote service demand */
4078      fprintf(where,
4079	      cpu_fmt_1_line_2,
4080	      rss_size,
4081	      rsr_size);
4082      break;
4083    }
4084  }
4085  else {
4086    /* The tester did not wish to measure service demand. */
4087    switch (verbosity) {
4088    case 0:
4089      fprintf(where,
4090	      tput_fmt_0,
4091	      nummessages/elapsed_time);
4092      break;
4093    case 1:
4094    case 2:
4095      if (print_headers) {
4096	fprintf(where,tput_title,format_units());
4097      }
4098
4099      fprintf(where,
4100	      tput_fmt_1_line_1,	/* the format string */
4101	      lss_size,
4102	      lsr_size,
4103	      req_size,		/* how large were the requests */
4104	      rsp_size,		/* how large were the responses */
4105	      elapsed_time, 		/* how long did it take */
4106	      nummessages/elapsed_time);
4107      fprintf(where,
4108	      tput_fmt_1_line_2,
4109	      rss_size, 		/* remote recvbuf size */
4110	      rsr_size);
4111
4112      break;
4113    }
4114  }
4115  fflush(where);
4116
4117  /* it would be a good thing to include information about some of the */
4118  /* other parameters that may have been set for this test, but at the */
4119  /* moment, I do not wish to figure-out all the  formatting, so I will */
4120  /* just put this comment here to help remind me that it is something */
4121  /* that should be done at a later time. */
4122
4123  /* how to handle the verbose information in the presence of */
4124  /* confidence intervals is yet to be determined... raj 11/94 */
4125
4126  if (verbosity > 1) {
4127    /* The user wanted to know it all, so we will give it to him. */
4128    /* This information will include as much as we can find about */
4129    /* UDP statistics, the alignments of the sends and receives */
4130    /* and all that sort of rot... */
4131
4132#ifdef WANT_HISTOGRAM
4133    fprintf(where,"\nHistogram of request/reponse times.\n");
4134    fflush(where);
4135    HIST_report(time_hist);
4136#endif /* WANT_HISTOGRAM */
4137  }
4138}
4139
4140 /* this routine implements the receive side (netserver) of a XTI_UDP_RR */
4141 /* test. */
4142void
4143  recv_xti_udp_rr()
4144{
4145
4146  struct ring_elt *recv_ring;
4147  struct ring_elt *send_ring;
4148
4149  struct t_bind bind_req, bind_resp;
4150  struct t_unitdata send_unitdata;
4151  struct t_unitdata recv_unitdata;
4152  int	            flags = 0;
4153
4154  struct sockaddr_in myaddr_in, peeraddr_in;
4155  SOCKET s_data;
4156  int 	addrlen;
4157  int	trans_received;
4158  int	trans_remaining;
4159  float	elapsed_time;
4160
4161  struct	xti_udp_rr_request_struct	*xti_udp_rr_request;
4162  struct	xti_udp_rr_response_struct	*xti_udp_rr_response;
4163  struct	xti_udp_rr_results_struct	*xti_udp_rr_results;
4164
4165
4166  /* a little variable initialization */
4167  memset (&myaddr_in, 0, sizeof(struct sockaddr_in));
4168  myaddr_in.sin_family      = AF_INET;
4169  myaddr_in.sin_addr.s_addr = INADDR_ANY;
4170  myaddr_in.sin_port        = 0;
4171  memset (&peeraddr_in, 0, sizeof(struct sockaddr_in));
4172
4173  /* and some not so paranoid :) */
4174  xti_udp_rr_request  =
4175    (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
4176  xti_udp_rr_response =
4177    (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
4178  xti_udp_rr_results  =
4179    (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
4180
4181  if (debug) {
4182    fprintf(where,"netserver: recv_xti_udp_rr: entered...\n");
4183    fflush(where);
4184  }
4185
4186  /* We want to set-up the listen socket with all the desired */
4187  /* parameters and then let the initiator know that all is ready. If */
4188  /* socket size defaults are to be used, then the initiator will have */
4189  /* sent us 0's. If the socket sizes cannot be changed, then we will */
4190  /* send-back what they are. If that information cannot be determined, */
4191  /* then we send-back -1's for the sizes. If things go wrong for any */
4192  /* reason, we will drop back ten yards and punt. */
4193
4194  /* If anything goes wrong, we want the remote to know about it. It */
4195  /* would be best if the error that the remote reports to the user is */
4196  /* the actual error we encountered, rather than some bogus unexpected */
4197  /* response type message. */
4198
4199  if (debug) {
4200    fprintf(where,"recv_xti_udp_rr: setting the response type...\n");
4201    fflush(where);
4202  }
4203
4204  netperf_response.content.response_type = XTI_UDP_RR_RESPONSE;
4205
4206  if (debug) {
4207    fprintf(where,"recv_xti_udp_rr: the response type is set...\n");
4208    fflush(where);
4209  }
4210
4211  /* We now alter the message_ptr variables to be at the desired */
4212  /* alignments with the desired offsets. */
4213
4214  if (debug) {
4215    fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n",
4216	    xti_udp_rr_request->recv_alignment,
4217	    xti_udp_rr_request->recv_offset);
4218    fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n",
4219	    xti_udp_rr_request->send_alignment,
4220	    xti_udp_rr_request->send_offset);
4221    fflush(where);
4222  }
4223
4224  if (send_width == 0) send_width = 1;
4225  if (recv_width == 0) recv_width = 1;
4226
4227  recv_ring = allocate_buffer_ring(recv_width,
4228				   xti_udp_rr_request->request_size,
4229				   xti_udp_rr_request->recv_alignment,
4230				   xti_udp_rr_request->recv_offset);
4231
4232  send_ring = allocate_buffer_ring(send_width,
4233				   xti_udp_rr_request->response_size,
4234				   xti_udp_rr_request->send_alignment,
4235				   xti_udp_rr_request->send_offset);
4236
4237  if (debug) {
4238    fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n");
4239    fflush(where);
4240  }
4241
4242  /* create_xti_endpoint expects to find some things in the global */
4243  /* variables, so set the globals based on the values in the request. */
4244  /* once the socket has been created, we will set the response values */
4245  /* based on the updated value of those globals. raj 7/94 */
4246  lss_size = xti_udp_rr_request->send_buf_size;
4247  lsr_size = xti_udp_rr_request->recv_buf_size;
4248  loc_rcvavoid = xti_udp_rr_request->so_rcvavoid;
4249  loc_sndavoid = xti_udp_rr_request->so_sndavoid;
4250
4251#ifdef __alpha
4252
4253  /* ok - even on a DEC box, strings are strings. I din't really want */
4254  /* to ntohl the words of a string. since I don't want to teach the */
4255  /* send_ and recv_ _request and _response routines about the types, */
4256  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4257  /* solution would be to use XDR, but I am still leary of being able */
4258  /* to find XDR libs on all platforms I want running netperf. raj */
4259  {
4260    int *charword;
4261    int *initword;
4262    int *lastword;
4263
4264    initword = (int *) xti_udp_rr_request->xti_device;
4265    lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4);
4266
4267    for (charword = initword;
4268	 charword < lastword;
4269	 charword++) {
4270
4271      *charword = htonl(*charword);
4272    }
4273  }
4274
4275#endif /* __alpha */
4276
4277  s_data = create_xti_endpoint(xti_udp_rr_request->xti_device);
4278
4279  if (s_data == INVALID_SOCKET) {
4280    netperf_response.content.serv_errno = errno;
4281    send_response();
4282    exit(1);
4283  }
4284
4285  if (debug) {
4286    fprintf(where,"recv_xti_udp_rr: endpoint created...\n");
4287    fflush(where);
4288  }
4289
4290  /* Let's get an address assigned to this socket so we can tell the */
4291  /* initiator how to reach the data socket. There may be a desire to */
4292  /* nail this socket to a specific IP address in a multi-homed, */
4293  /* multi-connection situation, but for now, we'll ignore the issue */
4294  /* and concentrate on single connection testing. */
4295
4296  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4297  bind_req.addr.len    = sizeof(struct sockaddr_in);
4298  bind_req.addr.buf    = (char *)&myaddr_in;
4299  bind_req.qlen        = 1;
4300
4301  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4302  bind_resp.addr.len    = sizeof(struct sockaddr_in);
4303  bind_resp.addr.buf    = (char *)&myaddr_in;
4304  bind_resp.qlen        = 1;
4305
4306  if (t_bind(s_data,
4307	     &bind_req,
4308	     &bind_resp) == SOCKET_ERROR) {
4309    if (debug) {
4310      fprintf(where,
4311	      "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n",
4312	      t_errno,
4313	      errno);
4314      fflush(where);
4315    }
4316
4317    netperf_response.content.serv_errno = t_errno;
4318    send_response();
4319
4320    exit(1);
4321  }
4322
4323  if (debug) {
4324    fprintf(where,
4325	    "recv_xti_udp_rr: endpoint bound to port %d...\n",
4326	    ntohs(myaddr_in.sin_port));
4327    fflush(where);
4328  }
4329
4330  xti_udp_rr_response->test_length =
4331    xti_udp_rr_request->test_length;
4332
4333
4334  /* Now myaddr_in contains the port and the internet address this is */
4335  /* returned to the sender also implicitly telling the sender that the */
4336  /* socket buffer sizing has been done. */
4337
4338  xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4339  netperf_response.content.serv_errno   = 0;
4340
4341  fprintf(where,"recv port number %d\n",myaddr_in.sin_port);
4342  fflush(where);
4343
4344  /* But wait, there's more. If the initiator wanted cpu measurements, */
4345  /* then we must call the calibrate routine, which will return the max */
4346  /* rate back to the initiator. If the CPU was not to be measured, or */
4347  /* something went wrong with the calibration, we will return a 0.0 to */
4348  /* the initiator. */
4349
4350  xti_udp_rr_response->cpu_rate    = 0.0; 	/* assume no cpu */
4351  xti_udp_rr_response->measure_cpu = 0;
4352  if (xti_udp_rr_request->measure_cpu) {
4353    xti_udp_rr_response->measure_cpu = 1;
4354    xti_udp_rr_response->cpu_rate =
4355      calibrate_local_cpu(xti_udp_rr_request->cpu_rate);
4356  }
4357
4358  /* before we send the response back to the initiator, pull some of */
4359  /* the socket parms from the globals */
4360  xti_udp_rr_response->send_buf_size = lss_size;
4361  xti_udp_rr_response->recv_buf_size = lsr_size;
4362  xti_udp_rr_response->so_rcvavoid   = loc_rcvavoid;
4363  xti_udp_rr_response->so_sndavoid   = loc_sndavoid;
4364
4365  /* since we are going to call t_rcvudata() instead of t_rcv() we */
4366  /* need to init the unitdata structure raj 3/95 */
4367
4368  memset (&recv_unitdata, 0, sizeof(recv_unitdata));
4369  recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4370  recv_unitdata.addr.len    = sizeof(struct sockaddr_in);
4371  recv_unitdata.addr.buf    = (char *)&peeraddr_in;
4372
4373  recv_unitdata.opt.maxlen = 0;
4374  recv_unitdata.opt.len    = 0;
4375  recv_unitdata.opt.buf    = NULL;
4376
4377  recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size;
4378  recv_unitdata.udata.len    = xti_udp_rr_request->request_size;
4379  recv_unitdata.udata.buf    = recv_ring->buffer_ptr;
4380
4381  /* since we are going to call t_sndudata() instead of t_snd() we */
4382  /* need to init the unitdata structure raj 8/95 */
4383
4384  memset (&send_unitdata, 0, sizeof(send_unitdata));
4385  send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
4386  send_unitdata.addr.len    = sizeof(struct sockaddr_in);
4387  send_unitdata.addr.buf    = (char *)&peeraddr_in;
4388
4389  send_unitdata.opt.maxlen = 0;
4390  send_unitdata.opt.len    = 0;
4391  send_unitdata.opt.buf    = NULL;
4392
4393  send_unitdata.udata.maxlen = xti_udp_rr_request->response_size;
4394  send_unitdata.udata.len    = xti_udp_rr_request->response_size;
4395  send_unitdata.udata.buf    = send_ring->buffer_ptr;
4396
4397  send_response();
4398
4399
4400  /* Now it's time to start receiving data on the connection. We will */
4401  /* first grab the apropriate counters and then start grabbing. */
4402
4403  cpu_start(xti_udp_rr_request->measure_cpu);
4404
4405  if (xti_udp_rr_request->test_length > 0) {
4406    times_up = 0;
4407    trans_remaining = 0;
4408    start_timer(xti_udp_rr_request->test_length + PAD_TIME);
4409  }
4410  else {
4411    times_up = 1;
4412    trans_remaining = xti_udp_rr_request->test_length * -1;
4413  }
4414
4415  addrlen = sizeof(peeraddr_in);
4416  bzero((char *)&peeraddr_in, addrlen);
4417
4418  trans_received = 0;
4419
4420  while ((!times_up) || (trans_remaining > 0)) {
4421
4422    /* receive the request from the other side */
4423    if (t_rcvudata(s_data,
4424		   &recv_unitdata,
4425		   &flags) != 0) {
4426      if (errno == TNODATA) {
4427	continue;
4428      }
4429      if (errno == EINTR) {
4430	/* we must have hit the end of test time. */
4431	break;
4432      }
4433      if (debug) {
4434	fprintf(where,
4435		"recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n",
4436		t_errno,
4437		errno);
4438	fflush(where);
4439      }
4440      netperf_response.content.serv_errno = t_errno;
4441      send_response();
4442      exit(1);
4443    }
4444    recv_ring = recv_ring->next;
4445    recv_unitdata.udata.buf = recv_ring->buffer_ptr;
4446
4447    /* Now, send the response to the remote */
4448    if (t_sndudata(s_data,
4449		   &send_unitdata) != 0) {
4450      if (errno == EINTR) {
4451	/* we have hit end of test time. */
4452	break;
4453      }
4454      if (debug) {
4455	fprintf(where,
4456		"recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n",
4457		t_errno,
4458		errno);
4459	fflush(where);
4460      }
4461      netperf_response.content.serv_errno = errno;
4462      send_response();
4463      exit(1);
4464    }
4465    send_ring = send_ring->next;
4466    send_unitdata.udata.buf = send_ring->buffer_ptr;
4467
4468    trans_received++;
4469    if (trans_remaining) {
4470      trans_remaining--;
4471    }
4472
4473    if (debug) {
4474      fprintf(where,
4475	      "recv_xti_udp_rr: Transaction %d complete.\n",
4476	      trans_received);
4477      fflush(where);
4478    }
4479
4480  }
4481
4482
4483  /* The loop now exits due to timeout or transaction count being */
4484  /* reached */
4485
4486  cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time);
4487
4488  if (times_up) {
4489    /* we ended the test by time, which was at least 2 seconds */
4490    /* longer than we wanted to run. so, we want to subtract */
4491    /* PAD_TIME from the elapsed_time. */
4492    elapsed_time -= PAD_TIME;
4493  }
4494  /* send the results to the sender			*/
4495
4496  if (debug) {
4497    fprintf(where,
4498	    "recv_xti_udp_rr: got %d transactions\n",
4499	    trans_received);
4500    fflush(where);
4501  }
4502
4503  xti_udp_rr_results->bytes_received = (trans_received *
4504				    (xti_udp_rr_request->request_size +
4505				     xti_udp_rr_request->response_size));
4506  xti_udp_rr_results->trans_received = trans_received;
4507  xti_udp_rr_results->elapsed_time	 = elapsed_time;
4508  xti_udp_rr_results->cpu_method     = cpu_method;
4509  if (xti_udp_rr_request->measure_cpu) {
4510    xti_udp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
4511  }
4512
4513  if (debug) {
4514    fprintf(where,
4515	    "recv_xti_udp_rr: test complete, sending results.\n");
4516    fflush(where);
4517  }
4518
4519  send_response();
4520
4521  /* we are done with the socket now */
4522  close(s_data);
4523
4524}
4525
4526 /* this routine implements the receive (netserver) side of a XTI_TCP_RR */
4527 /* test */
4528void
4529recv_xti_tcp_rr()
4530{
4531
4532  struct ring_elt *send_ring;
4533  struct ring_elt *recv_ring;
4534
4535  struct sockaddr_in  myaddr_in,  peeraddr_in;
4536  struct t_bind bind_req, bind_resp;
4537  struct t_call call_req;
4538
4539  SOCKET s_listen,s_data;
4540  int 	addrlen;
4541  char	*temp_message_ptr;
4542  int	trans_received;
4543  int	trans_remaining;
4544  int	bytes_sent;
4545  int	request_bytes_recvd;
4546  int	request_bytes_remaining;
4547  int	timed_out = 0;
4548  float	elapsed_time;
4549
4550  struct	xti_tcp_rr_request_struct	*xti_tcp_rr_request;
4551  struct	xti_tcp_rr_response_struct	*xti_tcp_rr_response;
4552  struct	xti_tcp_rr_results_struct	*xti_tcp_rr_results;
4553
4554  xti_tcp_rr_request =
4555    (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
4556  xti_tcp_rr_response =
4557    (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
4558  xti_tcp_rr_results =
4559    (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
4560
4561  if (debug) {
4562    fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n");
4563    fflush(where);
4564  }
4565
4566  /* We want to set-up the listen socket with all the desired */
4567  /* parameters and then let the initiator know that all is ready. If */
4568  /* socket size defaults are to be used, then the initiator will have */
4569  /* sent us 0's. If the socket sizes cannot be changed, then we will */
4570  /* send-back what they are. If that information cannot be determined, */
4571  /* then we send-back -1's for the sizes. If things go wrong for any */
4572  /* reason, we will drop back ten yards and punt. */
4573
4574  /* If anything goes wrong, we want the remote to know about it. It */
4575  /* would be best if the error that the remote reports to the user is */
4576  /* the actual error we encountered, rather than some bogus unexpected */
4577  /* response type message. */
4578
4579  if (debug) {
4580    fprintf(where,"recv_xti_tcp_rr: setting the response type...\n");
4581    fflush(where);
4582  }
4583
4584  netperf_response.content.response_type = XTI_TCP_RR_RESPONSE;
4585
4586  if (debug) {
4587    fprintf(where,"recv_xti_tcp_rr: the response type is set...\n");
4588    fflush(where);
4589  }
4590
4591  /* allocate the recv and send rings with the requested alignments */
4592  /* and offsets. raj 7/94 */
4593  if (debug) {
4594    fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n",
4595	    xti_tcp_rr_request->recv_alignment,
4596	    xti_tcp_rr_request->recv_offset);
4597    fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n",
4598	    xti_tcp_rr_request->send_alignment,
4599	    xti_tcp_rr_request->send_offset);
4600    fflush(where);
4601  }
4602
4603  /* at some point, these need to come to us from the remote system */
4604  if (send_width == 0) send_width = 1;
4605  if (recv_width == 0) recv_width = 1;
4606
4607  send_ring = allocate_buffer_ring(send_width,
4608				   xti_tcp_rr_request->response_size,
4609				   xti_tcp_rr_request->send_alignment,
4610				   xti_tcp_rr_request->send_offset);
4611
4612  recv_ring = allocate_buffer_ring(recv_width,
4613				   xti_tcp_rr_request->request_size,
4614				   xti_tcp_rr_request->recv_alignment,
4615				   xti_tcp_rr_request->recv_offset);
4616
4617
4618  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
4619  /* can put in OUR values !-) At some point, we may want to nail this */
4620  /* socket to a particular network-level address, but for now, */
4621  /* INADDR_ANY should be just fine. */
4622
4623  bzero((char *)&myaddr_in,
4624	sizeof(myaddr_in));
4625  myaddr_in.sin_family      = AF_INET;
4626  myaddr_in.sin_addr.s_addr = INADDR_ANY;
4627  myaddr_in.sin_port        = 0;
4628
4629  /* Grab a socket to listen on, and then listen on it. */
4630
4631  if (debug) {
4632    fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n");
4633    fflush(where);
4634  }
4635
4636  /* create_xti_endpoint expects to find some things in the global */
4637  /* variables, so set the globals based on the values in the request. */
4638  /* once the socket has been created, we will set the response values */
4639  /* based on the updated value of those globals. raj 7/94 */
4640  lss_size = xti_tcp_rr_request->send_buf_size;
4641  lsr_size = xti_tcp_rr_request->recv_buf_size;
4642  loc_nodelay = xti_tcp_rr_request->no_delay;
4643  loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid;
4644  loc_sndavoid = xti_tcp_rr_request->so_sndavoid;
4645
4646#ifdef __alpha
4647
4648  /* ok - even on a DEC box, strings are strings. I din't really want */
4649  /* to ntohl the words of a string. since I don't want to teach the */
4650  /* send_ and recv_ _request and _response routines about the types, */
4651  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
4652  /* solution would be to use XDR, but I am still leary of being able */
4653  /* to find XDR libs on all platforms I want running netperf. raj */
4654  {
4655    int *charword;
4656    int *initword;
4657    int *lastword;
4658
4659    initword = (int *) xti_tcp_rr_request->xti_device;
4660    lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4);
4661
4662    for (charword = initword;
4663	 charword < lastword;
4664	 charword++) {
4665
4666      *charword = htonl(*charword);
4667    }
4668  }
4669
4670#endif /* __alpha */
4671
4672  s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device);
4673
4674  if (s_listen == INVALID_SOCKET) {
4675    netperf_response.content.serv_errno = errno;
4676    send_response();
4677
4678    exit(1);
4679  }
4680
4681  /* Let's get an address assigned to this socket so we can tell the */
4682  /* initiator how to reach the data socket. There may be a desire to */
4683  /* nail this socket to a specific IP address in a multi-homed, */
4684  /* multi-connection situation, but for now, we'll ignore the issue */
4685  /* and concentrate on single connection testing. */
4686
4687  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
4688  bind_req.addr.len    = sizeof(struct sockaddr_in);
4689  bind_req.addr.buf    = (char *)&myaddr_in;
4690  bind_req.qlen        = 1;
4691
4692  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
4693  bind_resp.addr.len    = sizeof(struct sockaddr_in);
4694  bind_resp.addr.buf    = (char *)&myaddr_in;
4695  bind_resp.qlen        = 1;
4696
4697  if (t_bind(s_listen,
4698	     &bind_req,
4699	     &bind_resp) == SOCKET_ERROR) {
4700    netperf_response.content.serv_errno = t_errno;
4701    close(s_listen);
4702    send_response();
4703
4704    exit(1);
4705  }
4706
4707  if (debug) {
4708    fprintf(where,
4709	    "recv_xti_tcp_rr: t_bind complete port %d\n",
4710	    ntohs(myaddr_in.sin_port));
4711    fflush(where);
4712  }
4713
4714  /* Now myaddr_in contains the port and the internet address this is */
4715  /* returned to the sender also implicitly telling the sender that the */
4716  /* socket buffer sizing has been done. */
4717
4718  xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
4719  netperf_response.content.serv_errno   = 0;
4720
4721  /* But wait, there's more. If the initiator wanted cpu measurements, */
4722  /* then we must call the calibrate routine, which will return the max */
4723  /* rate back to the initiator. If the CPU was not to be measured, or */
4724  /* something went wrong with the calibration, we will return a 0.0 to */
4725  /* the initiator. */
4726
4727  xti_tcp_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
4728  xti_tcp_rr_response->measure_cpu = 0;
4729
4730  if (xti_tcp_rr_request->measure_cpu) {
4731    xti_tcp_rr_response->measure_cpu = 1;
4732    xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate);
4733  }
4734
4735
4736  /* before we send the response back to the initiator, pull some of */
4737  /* the socket parms from the globals */
4738  xti_tcp_rr_response->send_buf_size = lss_size;
4739  xti_tcp_rr_response->recv_buf_size = lsr_size;
4740  xti_tcp_rr_response->no_delay = loc_nodelay;
4741  xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid;
4742  xti_tcp_rr_response->so_sndavoid = loc_sndavoid;
4743  xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length;
4744  send_response();
4745
4746  /* Now, let's set-up the socket to listen for connections. for xti, */
4747  /* the t_listen call is blocking by default - this is different */
4748  /* semantics from BSD - probably has to do with being able to reject */
4749  /* a call before an accept */
4750  call_req.addr.maxlen = sizeof(struct sockaddr_in);
4751  call_req.addr.len    = sizeof(struct sockaddr_in);
4752  call_req.addr.buf    = (char *)&peeraddr_in;
4753  call_req.opt.maxlen  = 0;
4754  call_req.opt.len     = 0;
4755  call_req.opt.buf     = NULL;
4756  call_req.udata.maxlen= 0;
4757  call_req.udata.len   = 0;
4758  call_req.udata.buf   = 0;
4759
4760  if (t_listen(s_listen, &call_req) == -1) {
4761    fprintf(where,
4762	    "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n",
4763	    errno,
4764	    t_errno);
4765    fflush(where);
4766    netperf_response.content.serv_errno = t_errno;
4767    close(s_listen);
4768    send_response();
4769    exit(1);
4770  }
4771
4772  if (debug) {
4773    fprintf(where,
4774	    "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n",
4775	    t_look(s_listen));
4776    fflush(where);
4777  }
4778
4779  /* now just rubber stamp the thing. we want to use the same fd? so */
4780  /* we will just equate s_data with s_listen. this seems a little */
4781  /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
4782  s_data = s_listen;
4783  if (t_accept(s_listen,
4784	       s_data,
4785	       &call_req) == -1) {
4786    fprintf(where,
4787	    "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n",
4788	    errno,
4789	    t_errno);
4790    fflush(where);
4791    close(s_listen);
4792    exit(1);
4793  }
4794
4795  if (debug) {
4796    fprintf(where,
4797	    "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x",
4798	    t_look(s_data));
4799    fprintf(where,
4800	    " remote is %s port %d\n",
4801	    inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
4802	    ntohs(peeraddr_in.sin_port));
4803    fflush(where);
4804  }
4805
4806  /* Now it's time to start receiving data on the connection. We will */
4807  /* first grab the apropriate counters and then start grabbing. */
4808
4809  cpu_start(xti_tcp_rr_request->measure_cpu);
4810
4811  if (xti_tcp_rr_request->test_length > 0) {
4812    times_up = 0;
4813    trans_remaining = 0;
4814    start_timer(xti_tcp_rr_request->test_length + PAD_TIME);
4815  }
4816  else {
4817    times_up = 1;
4818    trans_remaining = xti_tcp_rr_request->test_length * -1;
4819  }
4820
4821  trans_received = 0;
4822
4823  while ((!times_up) || (trans_remaining > 0)) {
4824    temp_message_ptr = recv_ring->buffer_ptr;
4825    request_bytes_remaining	= xti_tcp_rr_request->request_size;
4826    while(request_bytes_remaining > 0) {
4827      if((request_bytes_recvd=t_rcv(s_data,
4828				    temp_message_ptr,
4829				    request_bytes_remaining,
4830				    &xti_flags)) == SOCKET_ERROR) {
4831	if (errno == EINTR) {
4832	  /* the timer popped */
4833	  timed_out = 1;
4834	  break;
4835	}
4836	fprintf(where,
4837		"recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4838		errno,
4839		t_errno,
4840		request_bytes_recvd);
4841	fprintf(where,
4842		" t_look 0x%x",
4843		t_look(s_data));
4844	fflush(where);
4845	netperf_response.content.serv_errno = t_errno;
4846	send_response();
4847	exit(1);
4848      }
4849      else {
4850	request_bytes_remaining -= request_bytes_recvd;
4851	temp_message_ptr  += request_bytes_recvd;
4852      }
4853    }
4854
4855    recv_ring = recv_ring->next;
4856
4857    if (timed_out) {
4858      /* we hit the end of the test based on time - lets */
4859      /* bail out of here now... */
4860      if (debug) {
4861	fprintf(where,"yo5\n");
4862	fflush(where);
4863      }
4864      break;
4865    }
4866
4867    /* Now, send the response to the remote */
4868    if((bytes_sent=t_snd(s_data,
4869			 send_ring->buffer_ptr,
4870			 xti_tcp_rr_request->response_size,
4871			 0)) == -1) {
4872      if (errno == EINTR) {
4873	/* the test timer has popped */
4874	timed_out = 1;
4875	if (debug) {
4876	  fprintf(where,"yo6\n");
4877	  fflush(where);
4878	}
4879	break;
4880      }
4881      fprintf(where,
4882	      "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
4883	      errno,
4884	      t_errno,
4885	      bytes_sent);
4886      fprintf(where,
4887	      " t_look 0x%x",
4888	      t_look(s_data));
4889      fflush(where);
4890      netperf_response.content.serv_errno = t_errno;
4891      send_response();
4892      exit(1);
4893    }
4894
4895    send_ring = send_ring->next;
4896
4897    trans_received++;
4898    if (trans_remaining) {
4899      trans_remaining--;
4900    }
4901  }
4902
4903
4904  /* The loop now exits due to timeout or transaction count being */
4905  /* reached */
4906
4907  cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time);
4908
4909  stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */
4910
4911  if (timed_out) {
4912    /* we ended the test by time, which was at least 2 seconds */
4913    /* longer than we wanted to run. so, we want to subtract */
4914    /* PAD_TIME from the elapsed_time. */
4915    elapsed_time -= PAD_TIME;
4916  }
4917
4918  /* send the results to the sender			*/
4919
4920  if (debug) {
4921    fprintf(where,
4922	    "recv_xti_tcp_rr: got %d transactions\n",
4923	    trans_received);
4924    fflush(where);
4925  }
4926
4927  xti_tcp_rr_results->bytes_received = (trans_received *
4928					(xti_tcp_rr_request->request_size +
4929					 xti_tcp_rr_request->response_size));
4930  xti_tcp_rr_results->trans_received = trans_received;
4931  xti_tcp_rr_results->elapsed_time   = elapsed_time;
4932  xti_tcp_rr_results->cpu_method     = cpu_method;
4933  if (xti_tcp_rr_request->measure_cpu) {
4934    xti_tcp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
4935  }
4936
4937  if (debug) {
4938    fprintf(where,
4939	    "recv_xti_tcp_rr: test complete, sending results.\n");
4940    fflush(where);
4941  }
4942
4943  /* we are done with the socket, free it */
4944  t_close(s_data);
4945
4946  send_response();
4947
4948}
4949
4950
4951
4952 /* this test is intended to test the performance of establishing a */
4953 /* connection, exchanging a request/response pair, and repeating. it */
4954 /* is expected that this would be a good starting-point for */
4955 /* comparision of T/TCP with classic TCP for transactional workloads. */
4956 /* it will also look (can look) much like the communication pattern */
4957 /* of http for www access. */
4958
4959void
4960send_xti_tcp_conn_rr(char remote_host[])
4961{
4962
4963  char *tput_title = "\
4964Local /Remote\n\
4965Socket Size   Request  Resp.   Elapsed  Trans.\n\
4966Send   Recv   Size     Size    Time     Rate         \n\
4967bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
4968
4969  char *tput_fmt_0 =
4970    "%7.2f\n";
4971
4972  char *tput_fmt_1_line_1 = "\
4973%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
4974  char *tput_fmt_1_line_2 = "\
4975%-6d %-6d\n";
4976
4977  char *cpu_title = "\
4978Local /Remote\n\
4979Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
4980Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
4981bytes  bytes  bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
4982
4983  char *cpu_fmt_0 =
4984    "%6.3f\n";
4985
4986  char *cpu_fmt_1_line_1 = "\
4987%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
4988
4989  char *cpu_fmt_1_line_2 = "\
4990%-6d %-6d\n";
4991
4992  char *ksink_fmt = "\
4993Alignment      Offset\n\
4994Local  Remote  Local  Remote\n\
4995Send   Recv    Send   Recv\n\
4996%5d  %5d   %5d  %5d\n";
4997
4998
4999  int 			one = 1;
5000  int			timed_out = 0;
5001  float			elapsed_time;
5002
5003  int	len;
5004  struct ring_elt *send_ring;
5005  struct ring_elt *recv_ring;
5006  char	*temp_message_ptr;
5007  int	nummessages;
5008  SOCKET send_socket;
5009  int	trans_remaining;
5010  double	bytes_xferd;
5011  int	sock_opt_len = sizeof(int);
5012  int	rsp_bytes_left;
5013  int	rsp_bytes_recvd;
5014
5015  float	local_cpu_utilization;
5016  float	local_service_demand;
5017  float	remote_cpu_utilization;
5018  float	remote_service_demand;
5019  double	thruput;
5020
5021  struct	hostent	        *hp;
5022  struct	sockaddr_in	server;
5023  struct        sockaddr_in     *myaddr;
5024  unsigned      int             addr;
5025  int                           myport;
5026
5027  struct	xti_tcp_conn_rr_request_struct	*xti_tcp_conn_rr_request;
5028  struct	xti_tcp_conn_rr_response_struct	*xti_tcp_conn_rr_response;
5029  struct	xti_tcp_conn_rr_results_struct	*xti_tcp_conn_rr_result;
5030
5031  xti_tcp_conn_rr_request =
5032    (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5033  xti_tcp_conn_rr_response =
5034    (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5035  xti_tcp_conn_rr_result =
5036    (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5037
5038  /* since we are now disconnected from the code that established the */
5039  /* control socket, and since we want to be able to use different */
5040  /* protocols and such, we are passed the name of the remote host and */
5041  /* must turn that into the test specific addressing information. */
5042
5043  myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
5044  if (myaddr == NULL) {
5045    printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in));
5046    exit(1);
5047  }
5048
5049  bzero((char *)&server,
5050	sizeof(server));
5051  bzero((char *)myaddr,
5052	sizeof(struct sockaddr_in));
5053  myaddr->sin_family = AF_INET;
5054
5055  /* it would seem that while HP-UX will allow an IP address (as a */
5056  /* string) in a call to gethostbyname, other, less enlightened */
5057  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */
5058  /* order changed to check for IP address first. raj 7/96 */
5059
5060  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
5061    /* it was not an IP address, try it as a name */
5062    if ((hp = gethostbyname(remote_host)) == NULL) {
5063      /* we have no idea what it is */
5064      fprintf(where,
5065	      "establish_control: could not resolve the destination %s\n",
5066	      remote_host);
5067      fflush(where);
5068      exit(1);
5069    }
5070    else {
5071      /* it was a valid remote_host */
5072      bcopy(hp->h_addr,
5073	    (char *)&server.sin_addr,
5074	    hp->h_length);
5075      server.sin_family = hp->h_addrtype;
5076    }
5077  }
5078  else {
5079    /* it was a valid IP address */
5080    server.sin_addr.s_addr = addr;
5081    server.sin_family = AF_INET;
5082  }
5083
5084  if ( print_headers ) {
5085    fprintf(where,"TCP Connect/Request/Response Test\n");
5086    if (local_cpu_usage || remote_cpu_usage)
5087      fprintf(where,cpu_title,format_units());
5088    else
5089      fprintf(where,tput_title,format_units());
5090  }
5091
5092  /* initialize a few counters */
5093
5094  nummessages	=	0;
5095  bytes_xferd	=	0.0;
5096  times_up 	= 	0;
5097
5098  /* set-up the data buffers with the requested alignment and offset */
5099  if (send_width == 0) send_width = 1;
5100  if (recv_width == 0) recv_width = 1;
5101
5102  send_ring = allocate_buffer_ring(send_width,
5103				   req_size,
5104				   local_send_align,
5105				   local_send_offset);
5106
5107  recv_ring = allocate_buffer_ring(recv_width,
5108				   rsp_size,
5109				   local_recv_align,
5110				   local_recv_offset);
5111
5112
5113  if (debug) {
5114    fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n");
5115  }
5116
5117  /* If the user has requested cpu utilization measurements, we must */
5118  /* calibrate the cpu(s). We will perform this task within the tests */
5119  /* themselves. If the user has specified the cpu rate, then */
5120  /* calibrate_local_cpu will return rather quickly as it will have */
5121  /* nothing to do. If local_cpu_rate is zero, then we will go through */
5122  /* all the "normal" calibration stuff and return the rate back.*/
5123
5124  if (local_cpu_usage) {
5125    local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
5126  }
5127
5128  /* Tell the remote end to do a listen. The server alters the socket */
5129  /* paramters on the other side at this point, hence the reason for */
5130  /* all the values being passed in the setup message. If the user did */
5131  /* not specify any of the parameters, they will be passed as 0, which */
5132  /* will indicate to the remote that no changes beyond the system's */
5133  /* default should be used. Alignment is the exception, it will */
5134  /* default to 8, which will be no alignment alterations. */
5135
5136  netperf_request.content.request_type	        =	DO_XTI_TCP_CRR;
5137  xti_tcp_conn_rr_request->recv_buf_size	=	rsr_size;
5138  xti_tcp_conn_rr_request->send_buf_size	=	rss_size;
5139  xti_tcp_conn_rr_request->recv_alignment	=	remote_recv_align;
5140  xti_tcp_conn_rr_request->recv_offset	=	remote_recv_offset;
5141  xti_tcp_conn_rr_request->send_alignment	=	remote_send_align;
5142  xti_tcp_conn_rr_request->send_offset	=	remote_send_offset;
5143  xti_tcp_conn_rr_request->request_size	=	req_size;
5144  xti_tcp_conn_rr_request->response_size	=	rsp_size;
5145  xti_tcp_conn_rr_request->no_delay	        =	rem_nodelay;
5146  xti_tcp_conn_rr_request->measure_cpu	=	remote_cpu_usage;
5147  xti_tcp_conn_rr_request->cpu_rate	        =	remote_cpu_rate;
5148  xti_tcp_conn_rr_request->so_rcvavoid	=	rem_rcvavoid;
5149  xti_tcp_conn_rr_request->so_sndavoid	=	rem_sndavoid;
5150  if (test_time) {
5151    xti_tcp_conn_rr_request->test_length	=	test_time;
5152  }
5153  else {
5154    xti_tcp_conn_rr_request->test_length	=	test_trans * -1;
5155  }
5156
5157  if (debug > 1) {
5158    fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n");
5159  }
5160
5161  send_request();
5162
5163  /* The response from the remote will contain all of the relevant 	*/
5164  /* socket parameters for this test type. We will put them back into 	*/
5165  /* the variables here so they can be displayed if desired.  The	*/
5166  /* remote will have calibrated CPU if necessary, and will have done	*/
5167  /* all the needed set-up we will have calibrated the cpu locally	*/
5168  /* before sending the request, and will grab the counter value right	*/
5169  /* after the connect returns. The remote will grab the counter right	*/
5170  /* after the accept call. This saves the hassle of extra messages	*/
5171  /* being sent for the TCP tests.					*/
5172
5173  recv_response();
5174
5175  if (!netperf_response.content.serv_errno) {
5176    rsr_size	=	xti_tcp_conn_rr_response->recv_buf_size;
5177    rss_size	=	xti_tcp_conn_rr_response->send_buf_size;
5178    rem_nodelay	=	xti_tcp_conn_rr_response->no_delay;
5179    remote_cpu_usage=	xti_tcp_conn_rr_response->measure_cpu;
5180    remote_cpu_rate = 	xti_tcp_conn_rr_response->cpu_rate;
5181    /* make sure that port numbers are in network order */
5182    server.sin_port	=	(short)xti_tcp_conn_rr_response->data_port_number;
5183    server.sin_port =	htons(server.sin_port);
5184    if (debug) {
5185      fprintf(where,"remote listen done.\n");
5186      fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
5187      fflush(where);
5188    }
5189  }
5190  else {
5191    Set_errno(netperf_response.content.serv_errno);
5192    perror("netperf: remote error");
5193
5194    exit(1);
5195  }
5196
5197  /* Set-up the test end conditions. For a request/response test, they */
5198  /* can be either time or transaction based. */
5199
5200  if (test_time) {
5201    /* The user wanted to end the test after a period of time. */
5202    times_up = 0;
5203    trans_remaining = 0;
5204    start_timer(test_time);
5205  }
5206  else {
5207    /* The tester wanted to send a number of bytes. */
5208    trans_remaining = test_bytes;
5209    times_up = 1;
5210  }
5211
5212  /* The cpu_start routine will grab the current time and possibly */
5213  /* value of the idle counter for later use in measuring cpu */
5214  /* utilization and/or service demand and thruput. */
5215
5216  cpu_start(local_cpu_usage);
5217
5218  /* We use an "OR" to control test execution. When the test is */
5219  /* controlled by time, the byte count check will always return false. */
5220  /* When the test is controlled by byte count, the time test will */
5221  /* always return false. When the test is finished, the whole */
5222  /* expression will go false and we will stop sending data. I think I */
5223  /* just arbitrarily decrement trans_remaining for the timed test, but */
5224  /* will not do that just yet... One other question is whether or not */
5225  /* the send buffer and the receive buffer should be the same buffer. */
5226
5227  /* just for grins, start the port numbers at 65530. this should */
5228  /* quickly flush-out those broken implementations of TCP which treat */
5229  /* the port number as a signed 16 bit quantity. */
5230  myport = 65530;
5231  myaddr->sin_port = htons(myport);
5232
5233  while ((!times_up) || (trans_remaining > 0)) {
5234
5235    /* set up the data socket */
5236    send_socket = create_xti_endpoint(loc_xti_device);
5237
5238    if (send_socket == INVALID_SOCKET) {
5239      perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket");
5240      exit(1);
5241    }
5242
5243    /* we set SO_REUSEADDR on the premis that no unreserved port */
5244    /* number on the local system is going to be already connected to */
5245    /* the remote netserver's port number. we might still have a */
5246    /* problem if there is a port in the unconnected state. In that */
5247    /* case, we might want to throw-in a goto to the point where we */
5248    /* increment the port number by one and try again. of course, this */
5249    /* could lead to a big load of spinning. one thing that I might */
5250    /* try later is to have the remote actually allocate a couple of */
5251    /* port numbers and cycle through those as well. depends on if we */
5252    /* can get through all the unreserved port numbers in less than */
5253    /* the length of the TIME_WAIT state raj 8/94 */
5254    one = 1;
5255    if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
5256		  (char *)&one, sock_opt_len) == SOCKET_ERROR) {
5257      perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr");
5258      exit(1);
5259    }
5260
5261    /* we want to bind our socket to a particular port number. */
5262    if (bind(send_socket,
5263	     (struct sockaddr *)myaddr,
5264	     sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
5265      printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n",
5266	     ntohs(myaddr->sin_port));
5267      perror("netperf: send_xti_tcp_conn_rr: bind");
5268      exit(1);
5269    }
5270
5271    /* Connect up to the remote port on the data socket  */
5272    if (connect(send_socket,
5273		(struct sockaddr *)&server,
5274		sizeof(server)) == INVALID_SOCKET){
5275      if (errno == EINTR) {
5276	/* we hit the end of a */
5277	/* timed test. */
5278	timed_out = 1;
5279	break;
5280      }
5281      perror("netperf: data socket connect failed");
5282      printf("\tattempted to connect on socket %d to port %d",
5283	     send_socket,
5284	     ntohs(server.sin_port));
5285      printf(" from port %d \n",ntohs(myaddr->sin_port));
5286      exit(1);
5287    }
5288
5289    /* send the request */
5290    if((len=send(send_socket,
5291		 send_ring->buffer_ptr,
5292		 req_size,
5293		 0)) != req_size) {
5294      if (errno == EINTR) {
5295	/* we hit the end of a */
5296	/* timed test. */
5297	timed_out = 1;
5298	break;
5299      }
5300      perror("send_xti_tcp_conn_rr: data send error");
5301      exit(1);
5302    }
5303    send_ring = send_ring->next;
5304
5305    /* receive the response */
5306    rsp_bytes_left = rsp_size;
5307    temp_message_ptr  = recv_ring->buffer_ptr;
5308    while(rsp_bytes_left > 0) {
5309      if((rsp_bytes_recvd=recv(send_socket,
5310			       temp_message_ptr,
5311			       rsp_bytes_left,
5312			       0)) == SOCKET_ERROR) {
5313	if (errno == EINTR) {
5314	  /* We hit the end of a timed test. */
5315	  timed_out = 1;
5316	  break;
5317	}
5318	perror("send_xti_tcp_conn_rr: data recv error");
5319	exit(1);
5320      }
5321      rsp_bytes_left -= rsp_bytes_recvd;
5322      temp_message_ptr  += rsp_bytes_recvd;
5323    }
5324    recv_ring = recv_ring->next;
5325
5326    if (timed_out) {
5327      /* we may have been in a nested while loop - we need */
5328      /* another call to break. */
5329      break;
5330    }
5331
5332    close(send_socket);
5333
5334    nummessages++;
5335    if (trans_remaining) {
5336      trans_remaining--;
5337    }
5338
5339    if (debug > 3) {
5340      fprintf(where,
5341	      "Transaction %d completed on local port %d\n",
5342	      nummessages,
5343	      ntohs(myaddr->sin_port));
5344      fflush(where);
5345    }
5346
5347newport:
5348    /* pick a new port number */
5349    myport = ntohs(myaddr->sin_port);
5350    myport++;
5351    /* we do not want to use the port number that the server is */
5352    /* sitting at - this would cause us to fail in a loopback test */
5353
5354    if (myport == ntohs(server.sin_port)) myport++;
5355
5356    /* wrap the port number when we get to 65535. NOTE, some broken */
5357    /* TCP's might treat the port number as a signed 16 bit quantity. */
5358    /* we aren't interested in testing such broekn implementations :) */
5359    /* raj 8/94  */
5360    if (myport == 65535) {
5361      myport = 5000;
5362    }
5363    myaddr->sin_port = htons(myport);
5364
5365    if (debug) {
5366      if ((myport % 1000) == 0) {
5367	printf("port %d\n",myport);
5368      }
5369    }
5370
5371  }
5372
5373  /* this call will always give us the elapsed time for the test, and */
5374  /* will also store-away the necessaries for cpu utilization */
5375
5376  cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being measured? */
5377  /* how long did we really run? */
5378
5379  /* Get the statistics from the remote end. The remote will have */
5380  /* calculated service demand and all those interesting things. If it */
5381  /* wasn't supposed to care, it will return obvious values. */
5382
5383  recv_response();
5384  if (!netperf_response.content.serv_errno) {
5385    if (debug)
5386      fprintf(where,"remote results obtained\n");
5387  }
5388  else {
5389    Set_errno(netperf_response.content.serv_errno);
5390    perror("netperf: remote error");
5391
5392    exit(1);
5393  }
5394
5395  /* We now calculate what our thruput was for the test. In the future, */
5396  /* we may want to include a calculation of the thruput measured by */
5397  /* the remote, but it should be the case that for a TCP stream test, */
5398  /* that the two numbers should be *very* close... We calculate */
5399  /* bytes_sent regardless of the way the test length was controlled. */
5400  /* If it was time, we needed to, and if it was by bytes, the user may */
5401  /* have specified a number of bytes that wasn't a multiple of the */
5402  /* send_size, so we really didn't send what he asked for ;-) We use */
5403  /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
5404  /* 1024. A future enhancement *might* be to choose from a couple of */
5405  /* unit selections. */
5406
5407  bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
5408  thruput	= calc_thruput(bytes_xferd);
5409
5410  if (local_cpu_usage || remote_cpu_usage) {
5411    /* We must now do a little math for service demand and cpu */
5412    /* utilization for the system(s) */
5413    /* Of course, some of the information might be bogus because */
5414    /* there was no idle counter in the kernel(s). We need to make */
5415    /* a note of this for the user's benefit...*/
5416    if (local_cpu_usage) {
5417      if (local_cpu_rate == 0.0) {
5418	fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
5419	fprintf(where,"Local CPU usage numbers based on process information only!\n");
5420	fflush(where);
5421      }
5422      local_cpu_utilization = calc_cpu_util(0.0);
5423      /* since calc_service demand is doing ms/Kunit we will */
5424      /* multiply the number of transaction by 1024 to get */
5425      /* "good" numbers */
5426      local_service_demand  = calc_service_demand((double) nummessages*1024,
5427						  0.0,
5428						  0.0,
5429						  0);
5430    }
5431    else {
5432      local_cpu_utilization	= -1.0;
5433      local_service_demand	= -1.0;
5434    }
5435
5436    if (remote_cpu_usage) {
5437      if (remote_cpu_rate == 0.0) {
5438	fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
5439	fprintf(where,"Remote CPU usage numbers based on process information only!\n");
5440	fflush(where);
5441      }
5442      remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util;
5443      /* since calc_service demand is doing ms/Kunit we will */
5444      /* multiply the number of transaction by 1024 to get */
5445      /* "good" numbers */
5446      remote_service_demand = calc_service_demand((double) nummessages*1024,
5447						  0.0,
5448						  remote_cpu_utilization,
5449						  xti_tcp_conn_rr_result->num_cpus);
5450    }
5451    else {
5452      remote_cpu_utilization = -1.0;
5453      remote_service_demand  = -1.0;
5454    }
5455
5456    /* We are now ready to print all the information. If the user */
5457    /* has specified zero-level verbosity, we will just print the */
5458    /* local service demand, or the remote service demand. If the */
5459    /* user has requested verbosity level 1, he will get the basic */
5460    /* "streamperf" numbers. If the user has specified a verbosity */
5461    /* of greater than 1, we will display a veritable plethora of */
5462    /* background information from outside of this block as it it */
5463    /* not cpu_measurement specific...  */
5464
5465    switch (verbosity) {
5466    case 0:
5467      if (local_cpu_usage) {
5468	fprintf(where,
5469		cpu_fmt_0,
5470		local_service_demand);
5471      }
5472      else {
5473	fprintf(where,
5474		cpu_fmt_0,
5475		remote_service_demand);
5476      }
5477      break;
5478    case 1:
5479      fprintf(where,
5480	      cpu_fmt_1_line_1,		/* the format string */
5481	      lss_size,		/* local sendbuf size */
5482	      lsr_size,
5483	      req_size,		/* how large were the requests */
5484	      rsp_size,		/* guess */
5485	      elapsed_time,		/* how long was the test */
5486	      nummessages/elapsed_time,
5487	      local_cpu_utilization,	/* local cpu */
5488	      remote_cpu_utilization,	/* remote cpu */
5489	      local_service_demand,	/* local service demand */
5490	      remote_service_demand);	/* remote service demand */
5491      fprintf(where,
5492	      cpu_fmt_1_line_2,
5493	      rss_size,
5494	      rsr_size);
5495      break;
5496    }
5497  }
5498  else {
5499    /* The tester did not wish to measure service demand. */
5500    switch (verbosity) {
5501    case 0:
5502      fprintf(where,
5503	      tput_fmt_0,
5504	      nummessages/elapsed_time);
5505      break;
5506    case 1:
5507      fprintf(where,
5508	      tput_fmt_1_line_1,	/* the format string */
5509	      lss_size,
5510	      lsr_size,
5511	      req_size,		/* how large were the requests */
5512	      rsp_size,		/* how large were the responses */
5513	      elapsed_time, 		/* how long did it take */
5514	      nummessages/elapsed_time);
5515      fprintf(where,
5516	      tput_fmt_1_line_2,
5517	      rss_size, 		/* remote recvbuf size */
5518	      rsr_size);
5519
5520      break;
5521    }
5522  }
5523
5524  /* it would be a good thing to include information about some of the */
5525  /* other parameters that may have been set for this test, but at the */
5526  /* moment, I do not wish to figure-out all the  formatting, so I will */
5527  /* just put this comment here to help remind me that it is something */
5528  /* that should be done at a later time. */
5529
5530  if (verbosity > 1) {
5531    /* The user wanted to know it all, so we will give it to him. */
5532    /* This information will include as much as we can find about */
5533    /* TCP statistics, the alignments of the sends and receives */
5534    /* and all that sort of rot... */
5535
5536    fprintf(where,
5537	    ksink_fmt);
5538  }
5539
5540}
5541
5542
5543void
5544recv_xti_tcp_conn_rr()
5545{
5546
5547  char  *message;
5548  struct	sockaddr_in        myaddr_in,
5549  peeraddr_in;
5550  SOCKET s_listen,s_data;
5551  int 	addrlen;
5552  char	*recv_message_ptr;
5553  char	*send_message_ptr;
5554  char	*temp_message_ptr;
5555  int	trans_received;
5556  int	trans_remaining;
5557  int	bytes_sent;
5558  int	request_bytes_recvd;
5559  int	request_bytes_remaining;
5560  int	timed_out = 0;
5561  float	elapsed_time;
5562
5563  struct	xti_tcp_conn_rr_request_struct	*xti_tcp_conn_rr_request;
5564  struct	xti_tcp_conn_rr_response_struct	*xti_tcp_conn_rr_response;
5565  struct	xti_tcp_conn_rr_results_struct	*xti_tcp_conn_rr_results;
5566
5567  xti_tcp_conn_rr_request =
5568    (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
5569  xti_tcp_conn_rr_response =
5570    (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
5571  xti_tcp_conn_rr_results =
5572    (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
5573
5574  if (debug) {
5575    fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n");
5576    fflush(where);
5577  }
5578
5579  /* We want to set-up the listen socket with all the desired */
5580  /* parameters and then let the initiator know that all is ready. If */
5581  /* socket size defaults are to be used, then the initiator will have */
5582  /* sent us 0's. If the socket sizes cannot be changed, then we will */
5583  /* send-back what they are. If that information cannot be determined, */
5584  /* then we send-back -1's for the sizes. If things go wrong for any */
5585  /* reason, we will drop back ten yards and punt. */
5586
5587  /* If anything goes wrong, we want the remote to know about it. It */
5588  /* would be best if the error that the remote reports to the user is */
5589  /* the actual error we encountered, rather than some bogus unexpected */
5590  /* response type message. */
5591
5592  if (debug) {
5593    fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n");
5594    fflush(where);
5595  }
5596
5597  netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE;
5598
5599  if (debug) {
5600    fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n");
5601    fflush(where);
5602  }
5603
5604  /* set-up the data buffer with the requested alignment and offset */
5605  message = (char *)malloc(DATABUFFERLEN);
5606  if (message == NULL) {
5607    printf("malloc(%d) failed!\n", DATABUFFERLEN);
5608    exit(1);
5609  }
5610
5611  /* We now alter the message_ptr variables to be at the desired */
5612  /* alignments with the desired offsets. */
5613
5614  if (debug) {
5615    fprintf(where,
5616	    "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n",
5617	    xti_tcp_conn_rr_request->recv_alignment,
5618	    xti_tcp_conn_rr_request->recv_offset);
5619    fprintf(where,
5620	    "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n",
5621	    xti_tcp_conn_rr_request->send_alignment,
5622	    xti_tcp_conn_rr_request->send_offset);
5623    fflush(where);
5624  }
5625
5626  recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset);
5627
5628  send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset);
5629
5630  if (debug) {
5631    fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n");
5632    fflush(where);
5633  }
5634
5635  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
5636  /* can put in OUR values !-) At some point, we may want to nail this */
5637  /* socket to a particular network-level address, but for now, */
5638  /* INADDR_ANY should be just fine. */
5639
5640  bzero((char *)&myaddr_in,
5641	sizeof(myaddr_in));
5642  myaddr_in.sin_family      = AF_INET;
5643  myaddr_in.sin_addr.s_addr = INADDR_ANY;
5644  myaddr_in.sin_port        = 0;
5645
5646  /* Grab a socket to listen on, and then listen on it. */
5647
5648  if (debug) {
5649    fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n");
5650    fflush(where);
5651  }
5652
5653  /* create_xti_endpoint expects to find some things in the global */
5654  /* variables, so set the globals based on the values in the request. */
5655  /* once the socket has been created, we will set the response values */
5656  /* based on the updated value of those globals. raj 7/94 */
5657  lss_size = xti_tcp_conn_rr_request->send_buf_size;
5658  lsr_size = xti_tcp_conn_rr_request->recv_buf_size;
5659  loc_nodelay = xti_tcp_conn_rr_request->no_delay;
5660  loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid;
5661  loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid;
5662
5663  s_listen = create_xti_endpoint(loc_xti_device);
5664
5665  if (s_listen == INVALID_SOCKET) {
5666    netperf_response.content.serv_errno = errno;
5667    send_response();
5668    if (debug) {
5669      fprintf(where,"could not create data socket\n");
5670      fflush(where);
5671    }
5672    exit(1);
5673  }
5674
5675  /* Let's get an address assigned to this socket so we can tell the */
5676  /* initiator how to reach the data socket. There may be a desire to */
5677  /* nail this socket to a specific IP address in a multi-homed, */
5678  /* multi-connection situation, but for now, we'll ignore the issue */
5679  /* and concentrate on single connection testing. */
5680
5681  if (bind(s_listen,
5682	   (struct sockaddr *)&myaddr_in,
5683	   sizeof(myaddr_in)) == SOCKET_ERROR) {
5684    netperf_response.content.serv_errno = errno;
5685    close(s_listen);
5686    send_response();
5687    if (debug) {
5688      fprintf(where,"could not bind\n");
5689      fflush(where);
5690    }
5691    exit(1);
5692  }
5693
5694  /* Now, let's set-up the socket to listen for connections */
5695  if (listen(s_listen, 5) == SOCKET_ERROR) {
5696    netperf_response.content.serv_errno = errno;
5697    close(s_listen);
5698    send_response();
5699    if (debug) {
5700      fprintf(where,"could not listen\n");
5701      fflush(where);
5702    }
5703    exit(1);
5704  }
5705
5706  /* now get the port number assigned by the system  */
5707  addrlen = sizeof(myaddr_in);
5708  if (getsockname(s_listen,
5709		  (struct sockaddr *)&myaddr_in,
5710		  &addrlen) == SOCKET_ERROR){
5711    netperf_response.content.serv_errno = errno;
5712    close(s_listen);
5713    send_response();
5714    if (debug) {
5715      fprintf(where,"could not geetsockname\n");
5716      fflush(where);
5717    }
5718    exit(1);
5719  }
5720
5721  /* Now myaddr_in contains the port and the internet address this is */
5722  /* returned to the sender also implicitly telling the sender that the */
5723  /* socket buffer sizing has been done. */
5724
5725  xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
5726  if (debug) {
5727    fprintf(where,"telling the remote to call me at %d\n",
5728	    xti_tcp_conn_rr_response->data_port_number);
5729    fflush(where);
5730  }
5731  netperf_response.content.serv_errno   = 0;
5732
5733  /* But wait, there's more. If the initiator wanted cpu measurements, */
5734  /* then we must call the calibrate routine, which will return the max */
5735  /* rate back to the initiator. If the CPU was not to be measured, or */
5736  /* something went wrong with the calibration, we will return a 0.0 to */
5737  /* the initiator. */
5738
5739  xti_tcp_conn_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
5740  if (xti_tcp_conn_rr_request->measure_cpu) {
5741    xti_tcp_conn_rr_response->measure_cpu = 1;
5742    xti_tcp_conn_rr_response->cpu_rate =
5743      calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate);
5744  }
5745
5746
5747
5748  /* before we send the response back to the initiator, pull some of */
5749  /* the socket parms from the globals */
5750  xti_tcp_conn_rr_response->send_buf_size = lss_size;
5751  xti_tcp_conn_rr_response->recv_buf_size = lsr_size;
5752  xti_tcp_conn_rr_response->no_delay = loc_nodelay;
5753  xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
5754  xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
5755
5756  send_response();
5757
5758  addrlen = sizeof(peeraddr_in);
5759
5760  /* Now it's time to start receiving data on the connection. We will */
5761  /* first grab the apropriate counters and then start grabbing. */
5762
5763  cpu_start(xti_tcp_conn_rr_request->measure_cpu);
5764
5765  /* The loop will exit when the sender does a shutdown, which will */
5766  /* return a length of zero   */
5767
5768  if (xti_tcp_conn_rr_request->test_length > 0) {
5769    times_up = 0;
5770    trans_remaining = 0;
5771    start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME);
5772  }
5773  else {
5774    times_up = 1;
5775    trans_remaining = xti_tcp_conn_rr_request->test_length * -1;
5776  }
5777
5778  trans_received = 0;
5779
5780  while ((!times_up) || (trans_remaining > 0)) {
5781
5782    /* accept a connection from the remote */
5783    if ((s_data=accept(s_listen,
5784		       (struct sockaddr *)&peeraddr_in,
5785		       &addrlen)) == INVALID_SOCKET) {
5786      if (errno == EINTR) {
5787	/* the timer popped */
5788	timed_out = 1;
5789	break;
5790      }
5791      fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno);
5792      fflush(where);
5793      close(s_listen);
5794
5795      exit(1);
5796    }
5797
5798    if (debug) {
5799      fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n");
5800      fflush(where);
5801    }
5802
5803    temp_message_ptr	= recv_message_ptr;
5804    request_bytes_remaining	= xti_tcp_conn_rr_request->request_size;
5805
5806    /* receive the request from the other side */
5807    while(request_bytes_remaining > 0) {
5808      if((request_bytes_recvd=recv(s_data,
5809				   temp_message_ptr,
5810				   request_bytes_remaining,
5811				   0)) == SOCKET_ERROR) {
5812	if (errno == EINTR) {
5813	  /* the timer popped */
5814	  timed_out = 1;
5815	  break;
5816	}
5817	netperf_response.content.serv_errno = errno;
5818	send_response();
5819	exit(1);
5820      }
5821      else {
5822	request_bytes_remaining -= request_bytes_recvd;
5823	temp_message_ptr  += request_bytes_recvd;
5824      }
5825    }
5826
5827    if (timed_out) {
5828      /* we hit the end of the test based on time - lets */
5829      /* bail out of here now... */
5830      fprintf(where,"yo5\n");
5831      fflush(where);
5832      break;
5833    }
5834
5835    /* Now, send the response to the remote */
5836    if((bytes_sent=send(s_data,
5837			send_message_ptr,
5838			xti_tcp_conn_rr_request->response_size,
5839			0)) == SOCKET_ERROR) {
5840      if (errno == EINTR) {
5841	/* the test timer has popped */
5842	timed_out = 1;
5843	fprintf(where,"yo6\n");
5844	fflush(where);
5845	break;
5846      }
5847      netperf_response.content.serv_errno = 99;
5848      send_response();
5849      exit(1);
5850    }
5851
5852    trans_received++;
5853    if (trans_remaining) {
5854      trans_remaining--;
5855    }
5856
5857    if (debug) {
5858      fprintf(where,
5859	      "recv_xti_tcp_conn_rr: Transaction %d complete\n",
5860	      trans_received);
5861      fflush(where);
5862    }
5863
5864    /* close the connection */
5865    close(s_data);
5866
5867  }
5868
5869
5870  /* The loop now exits due to timeout or transaction count being */
5871  /* reached */
5872
5873  cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time);
5874
5875  if (timed_out) {
5876    /* we ended the test by time, which was at least 2 seconds */
5877    /* longer than we wanted to run. so, we want to subtract */
5878    /* PAD_TIME from the elapsed_time. */
5879    elapsed_time -= PAD_TIME;
5880  }
5881  /* send the results to the sender			*/
5882
5883  if (debug) {
5884    fprintf(where,
5885	    "recv_xti_tcp_conn_rr: got %d transactions\n",
5886	    trans_received);
5887    fflush(where);
5888  }
5889
5890  xti_tcp_conn_rr_results->bytes_received	= (trans_received *
5891					   (xti_tcp_conn_rr_request->request_size +
5892					    xti_tcp_conn_rr_request->response_size));
5893  xti_tcp_conn_rr_results->trans_received	= trans_received;
5894  xti_tcp_conn_rr_results->elapsed_time	= elapsed_time;
5895  if (xti_tcp_conn_rr_request->measure_cpu) {
5896    xti_tcp_conn_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
5897  }
5898
5899  if (debug) {
5900    fprintf(where,
5901	    "recv_xti_tcp_conn_rr: test complete, sending results.\n");
5902    fflush(where);
5903  }
5904
5905  send_response();
5906
5907}
5908
5909void
5910print_xti_usage()
5911{
5912
5913  fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout);
5914  exit(1);
5915
5916}
5917
5918void
5919scan_xti_args(int argc, char *argv[])
5920{
5921#define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:"
5922  extern int	optind, opterrs;  /* index of first unused arg 	*/
5923  extern char	*optarg;	  /* pointer to option string	*/
5924
5925  int		c;
5926
5927  char
5928    arg1[BUFSIZ],  /* argument holders		*/
5929    arg2[BUFSIZ];
5930
5931  if (no_control) {
5932    fprintf(where,
5933	    "The XTI tests do not know how to run with no control connection\n");
5934    exit(-1);
5935  }
5936
5937  /* Go through all the command line arguments and break them */
5938  /* out. For those options that take two parms, specifying only */
5939  /* the first will set both to that value. Specifying only the */
5940  /* second will leave the first untouched. To change only the */
5941  /* first, use the form "first," (see the routine break_args.. */
5942
5943  while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) {
5944    switch (c) {
5945    case '?':
5946    case 'h':
5947      print_xti_usage();
5948      exit(1);
5949    case 'D':
5950      /* set the TCP nodelay flag */
5951      loc_nodelay = 1;
5952      rem_nodelay = 1;
5953      break;
5954    case 's':
5955      /* set local socket sizes */
5956      break_args(optarg,arg1,arg2);
5957      if (arg1[0])
5958	lss_size = convert(arg1);
5959      if (arg2[0])
5960	lsr_size = convert(arg2);
5961      break;
5962    case 'S':
5963      /* set remote socket sizes */
5964      break_args(optarg,arg1,arg2);
5965      if (arg1[0])
5966	rss_size = convert(arg1);
5967      if (arg2[0])
5968	rsr_size = convert(arg2);
5969      break;
5970    case 'r':
5971      /* set the request/response sizes */
5972      break_args(optarg,arg1,arg2);
5973      if (arg1[0])
5974	req_size = convert(arg1);
5975      if (arg2[0])
5976	rsp_size = convert(arg2);
5977      break;
5978    case 'm':
5979      /* set the send size */
5980      send_size = convert(optarg);
5981      break;
5982    case 'M':
5983      /* set the recv size */
5984      recv_size = convert(optarg);
5985      break;
5986    case 'W':
5987      /* set the "width" of the user space data */
5988      /* buffer. This will be the number of */
5989      /* send_size buffers malloc'd in the */
5990      /* *_STREAM test. It may be enhanced to set */
5991      /* both send and receive "widths" but for now */
5992      /* it is just the sending *_STREAM. */
5993      send_width = convert(optarg);
5994      break;
5995    case 'V' :
5996      /* we want to do copy avoidance and will set */
5997      /* it for everything, everywhere, if we really */
5998      /* can. of course, we don't know anything */
5999      /* about the remote... */
6000#ifdef SO_SND_COPYAVOID
6001      loc_sndavoid = 1;
6002#else
6003      loc_sndavoid = 0;
6004      printf("Local send copy avoidance not available.\n");
6005#endif
6006#ifdef SO_RCV_COPYAVOID
6007      loc_rcvavoid = 1;
6008#else
6009      loc_rcvavoid = 0;
6010      printf("Local recv copy avoidance not available.\n");
6011#endif
6012      rem_sndavoid = 1;
6013      rem_rcvavoid = 1;
6014      break;
6015    case 'X':
6016      /* set the xti device file name(s) */
6017      break_args(optarg,arg1,arg2);
6018      if (arg1[0])
6019	strcpy(loc_xti_device,arg1);
6020      if (arg2[0])
6021	strcpy(rem_xti_device,arg2);
6022      break;
6023    };
6024  }
6025}
6026#endif /* WANT_XTI */
6027