auto import from //depot/cupcake/@135843
diff --git a/nettest_xti.c b/nettest_xti.c
new file mode 100644
index 0000000..9d27f25
--- /dev/null
+++ b/nettest_xti.c
@@ -0,0 +1,6026 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WANT_XTI
+#ifndef lint
+char	nettest_xti_id[]="\
+@(#)nettest_xti.c (c) Copyright 1995-2007 Hewlett-Packard Co. Version 2.4.3";
+#else
+#define DIRTY
+#define WANT_HISTOGRAM
+#define WANT_INTERVALS
+#endif /* lint */
+/****************************************************************/
+/*								*/
+/*	nettest_xti.c						*/
+/*								*/
+/*      the XTI args parsing routine...                         */
+/*                                                              */
+/*      scan_xti_args()                                         */
+/*                                                              */
+/*	the actual test routines...				*/
+/*								*/
+/*	send_xti_tcp_stream()	perform a tcp stream test	*/
+/*	recv_xti_tcp_stream()					*/
+/*	send_xti_tcp_rr()	perform a tcp request/response	*/
+/*	recv_xti_tcp_rr()					*/
+/*      send_xti_tcp_conn_rr()  an RR test including connect    */
+/*      recv_xti_tcp_conn_rr()                                  */
+/*	send_xti_udp_stream()	perform a udp stream test	*/
+/*	recv_xti_udp_stream()					*/
+/*	send_xti_udp_rr()	perform a udp request/response	*/
+/*	recv_xti_udp_rr()					*/
+/*								*/
+/****************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif 
+
+#include <sys/types.h>
+#include <fcntl.h>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <signal.h>
+#else /* WIN32 */
+#include <process.h>
+#include <winsock2.h>
+#include <windows.h>
+#endif /* WIN32 */
+#include <stdio.h>
+#include <time.h>
+#include <malloc.h>
+ /* xti.h should be included *after* in.h because there are name */
+ /* conflicts!( Silly standards people... raj 2/95 fortuenately, the */
+ /* confilcts are on IP_TOP and IP_TTL, whcih netperf does not yet use */
+#include <xti.h>
+
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_xti.h"
+
+#ifdef WANT_HISTOGRAM
+#ifdef __sgi
+#include <sys/time.h>
+#endif /* __sgi */
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+
+
+
+ /* these variables are specific to the XTI sockets tests. declare */
+ /* them static to make them global only to this file. */
+
+static int	
+  rss_size,		/* remote socket send buffer size	*/
+  rsr_size,		/* remote socket recv buffer size	*/
+  lss_size,		/* local  socket send buffer size 	*/
+  lsr_size,		/* local  socket recv buffer size 	*/
+  req_size = 1,		/* request size                   	*/
+  rsp_size = 1,		/* response size			*/
+  send_size,		/* how big are individual sends		*/
+  recv_size;		/* how big are individual receives	*/
+
+static  int   confidence_iteration;
+static  char  local_cpu_method;
+static  char  remote_cpu_method;
+
+ /* different options for the xti				*/
+
+static int
+  loc_nodelay,		/* don't/do use NODELAY	locally		*/
+  rem_nodelay,		/* don't/do use NODELAY remotely	*/
+  loc_sndavoid,		/* avoid send copies locally		*/
+  loc_rcvavoid,		/* avoid recv copies locally		*/
+  rem_sndavoid,		/* avoid send copies remotely		*/
+  rem_rcvavoid;		/* avoid recv_copies remotely		*/
+
+static struct t_info info_struct;
+
+#ifdef WANT_HISTOGRAM
+#ifdef HAVE_GETHRTIME
+hrtime_t time_one;
+hrtime_t time_two;
+#else
+static struct timeval time_one;
+static struct timeval time_two;
+#endif /* HAVE_GETHRTIME */
+static HIST time_hist;
+#endif /* WANT_HISTOGRAM */
+
+static char loc_xti_device[32] = "/dev/tcp";
+static char rem_xti_device[32] = "/dev/tcp";
+
+static int  xti_flags = 0;
+
+char xti_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+TCP/UDP XTI API Test Options:\n\
+    -D [L][,R]        Set XTI_TCP_NODELAY locally and/or remotely (XTI_TCP_*)\n\
+    -h                Display this text\n\
+    -m bytes          Set the send size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
+    -M bytes          Set the recv size (XTI_TCP_STREAM, XTI_UDP_STREAM)\n\
+    -r bytes          Set request size (XTI_TCP_RR, XTI_UDP_RR)\n\
+    -R bytes          Set response size (XTI_TCP_RR, XTI_UDP_RR)\n\
+    -s send[,recv]    Set local socket send/recv buffer sizes\n\
+    -S send[,recv]    Set remote socket send/recv buffer sizes\n\
+    -X dev[,dev]      Set the local/remote XTI device file name\n\
+\n\
+For those options taking two parms, at least one must be specified;\n\
+specifying one value without a comma will set both parms to that\n\
+value, specifying a value with a leading comma will set just the second\n\
+parm, a value with a trailing comma will set just the first. To set\n\
+each parm to unique values, specify both and separate them with a\n\
+comma.\n"; 
+     
+
+ /* This routine is intended to retrieve interesting aspects of tcp */
+ /* for the data connection. at first, it attempts to retrieve the */
+ /* maximum segment size. later, it might be modified to retrieve */
+ /* other information, but it must be information that can be */
+ /* retrieved quickly as it is called during the timing of the test. */
+ /* for that reason, a second routine may be created that can be */
+ /* called outside of the timing loop */
+void
+get_xti_info(socket, info_struct)
+     int socket;
+     struct t_info *info_struct;
+{
+
+}
+
+
+ /* This routine will create a data (listen) socket with the apropriate */
+ /* options set and return it to the caller. this replaces all the */
+ /* duplicate code in each of the test routines and should help make */
+ /* things a little easier to understand. since this routine can be */
+ /* called by either the netperf or netserver programs, all output */
+ /* should be directed towards "where." family is generally AF_INET, */
+ /* and type will be either SOCK_STREAM or SOCK_DGRAM */
+SOCKET
+create_xti_endpoint(char *name)
+{
+
+  SOCKET temp_socket;
+
+  struct t_optmgmt *opt_req;  /* we request an option */
+  struct t_optmgmt *opt_ret;  /* it tells us what we got */
+
+  /* we use this to pass-in BSD-like socket options through t_optmgmt. */
+  /* it ends up being about as clear as mud. raj 2/95 */
+  struct sock_option {
+    struct t_opthdr myopthdr;
+    long value;
+  } *sock_option;
+
+  if (debug) {
+    fprintf(where,"create_xti_endpoint: attempting to open %s\n",
+	    name);
+    fflush(where);
+  }
+
+  /*set up the data socket                        */
+  temp_socket = t_open(name,O_RDWR,NULL);
+  
+  if (temp_socket == INVALID_SOCKET){
+    fprintf(where,
+	    "netperf: create_xti_endpoint: t_open %s: errno %d t_errno %d\n",
+	    name,
+	    errno,
+	    t_errno);
+    fflush(where);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"create_xti_endpoint: socket %d obtained...\n",temp_socket);
+    fflush(where);
+  }
+  
+  /* allocate what we need for option mgmt */
+  if ((opt_req = (struct t_optmgmt *)t_alloc(temp_socket,T_OPTMGMT,T_ALL)) == 
+      NULL) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: t_alloc: opt_req errno %d\n",
+	    errno);
+    fflush(where);
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,
+	    "create_xti_endpoint: opt_req->opt.buf %x maxlen %d len %d\n",
+	    opt_req->opt.buf,
+	    opt_req->opt.maxlen,
+	    opt_req->opt.len);
+    
+    fflush(where);
+  }
+
+  if ((opt_ret = (struct t_optmgmt *) t_alloc(temp_socket,T_OPTMGMT,T_ALL)) ==
+      NULL) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: t_alloc: opt_ret errno %d\n",
+	    errno);
+    fflush(where);
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,
+	    "create_xti_endpoint: opt_ret->opt.buf %x maxlen %d len %d\n",
+	    opt_ret->opt.buf,
+	    opt_ret->opt.maxlen,
+	    opt_ret->opt.len);
+    fflush(where);
+  }
+
+  /* Modify the local socket size. The reason we alter the send buffer */
+  /* size here rather than when the connection is made is to take care */
+  /* of decreases in buffer size. Decreasing the window size after */
+  /* connection establishment is a TCP no-no. Also, by setting the */
+  /* buffer (window) size before the connection is established, we can */
+  /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
+  /* the minimum receive buffer size at each half of the connection. */
+  /* This is why we are altering the receive buffer size on the sending */
+  /* size of a unidirectional transfer. If the user has not requested */
+  /* that the socket buffers be altered, we will try to find-out what */
+  /* their values are. If we cannot touch the socket buffer in any way, */
+  /* we will set the values to -1 to indicate that.  */
+
+#ifdef XTI_SNDBUF
+  if (lss_size > 0) {
+    /* we want to "negotiate" the option */
+    opt_req->flags = T_NEGOTIATE;
+  }
+  else {
+    /* we want to accept the default, and know what it is. I assume */
+    /* that when nothing has been changed, that T_CURRENT will return */
+    /* the same as T_DEFAULT raj 3/95 */
+    opt_req->flags = T_CURRENT;
+  }
+
+  /* the first part is for the netbuf that holds the option we want */
+  /* to negotiate or check */
+  /* the buffer of the netbuf points at the socket options structure */
+  
+  /* we assume that the t_alloc call allocated a buffer that started */
+  /* on a proper alignment */
+  sock_option = (struct sock_option *)opt_req->opt.buf;
+  
+  /* and next, set the fields in the sock_option structure */
+  sock_option->myopthdr.level = XTI_GENERIC;
+  sock_option->myopthdr.name  = XTI_SNDBUF;
+  sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
+  sock_option->value        = lss_size;
+  
+  opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
+  
+  /* now, set-up the stuff to return the value in the end */
+  /* we assume that the t_alloc call allocated a buffer that started */
+  /* on a proper alignment */
+  sock_option = (struct sock_option *)opt_ret->opt.buf;
+  
+  /* finally, call t_optmgmt. clear as mud. */
+  if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: XTI_SNDBUF option: t_errno %d\n",
+	    t_errno);
+    fflush(where);
+    exit(1);
+  }
+
+  if (sock_option->myopthdr.status == T_SUCCESS) {
+    lss_size = sock_option->value;
+  }
+  else {
+    fprintf(where,"create_xti_endpoint: XTI_SNDBUF option status 0x%.4x",
+	    sock_option->myopthdr.status);
+    fprintf(where," value %d\n",
+	    sock_option->value);
+    fflush(where);
+    lss_size = -1;
+  }
+
+  if (lsr_size > 0) {
+    /* we want to "negotiate" the option */
+    opt_req->flags = T_NEGOTIATE;
+  }
+  else {
+    /* we want to accept the default, and know what it is. I assume */
+    /* that when nothing has been changed, that T_CURRENT will return */
+    /* the same as T_DEFAULT raj 3/95 */
+    opt_req->flags = T_CURRENT;
+  }
+  
+  /* the first part is for the netbuf that holds the option we want */
+  /* to negotiate or check */
+  /* the buffer of the netbuf points at the socket options structure */
+  
+  /* we assume that the t_alloc call allocated a buffer that started */
+  /* on a proper alignment */
+  sock_option = (struct sock_option *)opt_req->opt.buf;
+  
+  /* and next, set the fields in the sock_option structure */
+  sock_option->myopthdr.level = XTI_GENERIC;
+  sock_option->myopthdr.name  = XTI_RCVBUF;
+  sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
+  sock_option->value        = lsr_size;
+  
+  opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
+  
+  /* now, set-up the stuff to return the value in the end */
+  /* we assume that the t_alloc call allocated a buffer that started */
+  /* on a proper alignment */
+  sock_option = (struct sock_option *)opt_ret->opt.buf;
+  
+  /* finally, call t_optmgmt. clear as mud. */
+  if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: XTI_RCVBUF option: t_errno %d\n",
+	    t_errno);
+    fflush(where);
+    exit(1);
+  }
+  lsr_size = sock_option->value;
+
+  /* this needs code */
+
+  if (debug) {
+    fprintf(where,"netperf: create_xti_endpoint: socket sizes determined...\n");
+    fprintf(where,"                       send: %d recv: %d\n",
+	    lss_size,lsr_size);
+    fflush(where);
+  }
+  
+#else /* XTI_SNDBUF */
+  
+  lss_size = -1;
+  lsr_size = -1;
+  
+#endif /* XTI_SNDBUF */
+
+  /* now, we may wish to enable the copy avoidance features on the */
+  /* local system. of course, this may not be possible... */
+  
+  if (loc_rcvavoid) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: Could not enable receive copy avoidance");
+    fflush(where);
+    loc_rcvavoid = 0;
+  }
+
+  if (loc_sndavoid) {
+    fprintf(where,
+	    "netperf: create_xti_endpoint: Could not enable send copy avoidance");
+    fflush(where);
+    loc_sndavoid = 0;
+  }
+  
+  /* Now, we will see about setting the TCP_NODELAY flag on the local */
+  /* socket. We will only do this for those systems that actually */
+  /* support the option. If it fails, note the fact, but keep going. */
+  /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
+  /* will cause an error to be displayed */
+  
+#ifdef TCP_NODELAY
+  if ((strcmp(test_name,"XTI_TCP_STREAM") == 0) ||
+      (strcmp(test_name,"XTI_TCP_RR") == 0) ||
+      (strcmp(test_name,"XTI_TCP_CRR") == 0)) {
+    if (loc_nodelay) {
+      /* we want to "negotiate" the option */
+      opt_req->flags = T_NEGOTIATE;
+    }
+    else {
+      /* we want to accept the default, and know what it is. I assume */
+      /* that when nothing has been changed, that T_CURRENT will return */
+      /* the same as T_DEFAULT raj 3/95 */
+      opt_req->flags = T_CURRENT;
+    }
+    
+    /* the first part is for the netbuf that holds the option we want */
+    /* to negotiate or check the buffer of the netbuf points at the */
+    /* socket options structure */ 
+    
+    /* we assume that the t_alloc call allocated a buffer that started */
+    /* on a proper alignment */
+    sock_option = (struct sock_option *)opt_req->opt.buf;
+    
+    /* and next, set the fields in the sock_option structure */
+    sock_option->myopthdr.level = INET_TCP;
+    sock_option->myopthdr.name  = TCP_NODELAY;
+    sock_option->myopthdr.len   = sizeof(struct t_opthdr) + sizeof(long);
+    sock_option->value          = T_YES;
+    
+    opt_req->opt.len          = sizeof(struct t_opthdr) + sizeof(long);
+    
+    /* now, set-up the stuff to return the value in the end */
+    /* we assume that the t_alloc call allocated a buffer that started */
+    /* on a proper alignment */
+    sock_option = (struct sock_option *)opt_ret->opt.buf;
+    
+    /* finally, call t_optmgmt. clear as mud. */
+    if (t_optmgmt(temp_socket,opt_req,opt_ret) == -1) {
+      fprintf(where,
+	      "create_xti_endpoint: TCP_NODELAY option: errno %d t_errno %d\n",
+	      errno,
+	      t_errno);
+      fflush(where);
+      exit(1);
+    }
+    loc_nodelay = sock_option->value;
+  }
+#else /* TCP_NODELAY */
+  
+  loc_nodelay = 0;
+  
+#endif /* TCP_NODELAY */
+
+  return(temp_socket);
+
+}
+
+
+/* This routine implements the TCP unidirectional data transfer test */
+/* (a.k.a. stream) for the xti interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_xti_tcp_stream(char remote_host[])
+{
+  
+  char *tput_title = "\
+Recv   Send    Send                          \n\
+Socket Socket  Message  Elapsed              \n\
+Size   Size    Size     Time     Throughput  \n\
+bytes  bytes   bytes    secs.    %s/sec  \n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1 =
+    "%6d %6d %6d    %-6.2f   %7.2f   \n";
+  
+  char *cpu_title = "\
+Recv   Send    Send                          Utilization       Service Demand\n\
+Socket Socket  Message  Elapsed              Send     Recv     Send    Recv\n\
+Size   Size    Size     Time     Throughput  local    remote   local   remote\n\
+bytes  bytes   bytes    secs.    %-8.8s/s  %% %c      %% %c      us/KB   us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f %c\n";
+
+  char *cpu_fmt_1 =
+    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f\n";
+  
+  char *ksink_fmt = "\n\
+Alignment      Offset         %-8.8s %-8.8s    Sends   %-8.8s Recvs\n\
+Local  Remote  Local  Remote  Xfered   Per                 Per\n\
+Send   Recv    Send   Recv             Send (avg)          Recv (avg)\n\
+%5d   %5d  %5d   %5d %6.4g  %6.2f    %6d   %6.2f %6d\n";
+
+  char *ksink_fmt2 = "\n\
+Maximum\n\
+Segment\n\
+Size (bytes)\n\
+%6d\n";
+  
+  
+  float			elapsed_time;
+  
+#ifdef WANT_INTERVALS
+  int interval_count;
+  sigset_t signal_set;
+#endif
+  
+  /* what we want is to have a buffer space that is at least one */
+  /* send-size greater than our send window. this will insure that we */
+  /* are never trying to re-use a buffer that may still be in the hands */
+  /* of the transport. This buffer will be malloc'd after we have found */
+  /* the size of the local senc socket buffer. We will want to deal */
+  /* with alignment and offset concerns as well. */
+  
+  int	*message_int_ptr;
+
+  struct ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages;
+  SOCKET send_socket;
+  int bytes_remaining;
+  int tcp_mss = -1;  /* possibly uninitialized on printf far below */
+
+  /* with links like fddi, one can send > 32 bits worth of bytes */
+  /* during a test... ;-) at some point, this should probably become a */
+  /* 64bit integral type, but those are not entirely common yet */
+
+  double	bytes_sent;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  /* some addressing information */
+  struct	hostent	        *hp;
+  struct	sockaddr_in	server;
+  unsigned      int             addr;
+
+  struct t_call server_call;
+  
+  struct	xti_tcp_stream_request_struct	*xti_tcp_stream_request;
+  struct	xti_tcp_stream_response_struct	*xti_tcp_stream_response;
+  struct	xti_tcp_stream_results_struct	*xti_tcp_stream_result;
+  
+  xti_tcp_stream_request  = 
+    (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_stream_response =
+    (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_stream_result   = 
+    (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  time_hist = HIST_new();
+#endif /* WANT_HISTOGRAM */
+  /* since we are now disconnected from the code that established the */
+  /* control socket, and since we want to be able to use different */
+  /* protocols and such, we are passed the name of the remote host and */
+  /* must turn that into the test specific addressing information. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  
+  /* it would seem that while HP-UX will allow an IP address (as a */
+  /* string) in a call to gethostbyname, other, less enlightened */
+  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
+  /* order changed to check for IP address first. raj 7/96 */
+
+  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
+    /* it was not an IP address, try it as a name */
+    if ((hp = gethostbyname(remote_host)) == NULL) {
+      /* we have no idea what it is */
+      fprintf(where,
+	      "establish_control: could not resolve the destination %s\n",
+	      remote_host);
+      fflush(where);
+      exit(1);
+    }
+    else {
+      /* it was a valid remote_host */
+      bcopy(hp->h_addr,
+	    (char *)&server.sin_addr,
+	    hp->h_length);
+      server.sin_family = hp->h_addrtype;
+    }
+  }
+  else {
+    /* it was a valid IP address */
+    server.sin_addr.s_addr = addr;
+    server.sin_family = AF_INET;
+  }    
+  
+  if ( print_headers ) {
+    /* we want to have some additional, interesting information in */
+    /* the headers. we know some of it here, but not all, so we will */
+    /* only print the test title here and will print the results */
+    /* titles after the test is finished */
+    fprintf(where,"XTI TCP STREAM TEST");
+    fprintf(where," to %s", remote_host);
+    if (iteration_max > 1) {
+      fprintf(where,
+	      " : +/-%3.1f%% @ %2d%% conf.",
+	      interval/0.02,
+	      confidence_level);
+      }
+    if (loc_nodelay || rem_nodelay) {
+      fprintf(where," : nodelay");
+    }
+    if (loc_sndavoid || 
+	loc_rcvavoid ||
+	rem_sndavoid ||
+	rem_rcvavoid) {
+      fprintf(where," : copy avoidance");
+    }
+#ifdef WANT_HISTOGRAM
+    fprintf(where," : histogram");
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS
+    fprintf(where," : interval");
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY 
+    fprintf(where," : dirty data");
+#endif /* DIRTY */
+    fprintf(where,"\n");
+  }
+
+  send_ring = NULL;
+  confidence_iteration = 1;
+  init_stat();
+
+  /* we have a great-big while loop which controls the number of times */
+  /* we run a particular test. this is for the calculation of a */
+  /* confidence interval (I really should have stayed awake during */
+  /* probstats :). If the user did not request confidence measurement */
+  /* (no confidence is the default) then we will only go though the */
+  /* loop once. the confidence stuff originates from the folks at IBM */
+
+  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
+	 (confidence_iteration <= iteration_min)) {
+
+    /* initialize a few counters. we have to remember that we might be */
+    /* going through the loop more than once. */
+    
+    nummessages    =	0;
+    bytes_sent     =	0.0;
+    times_up       = 	0;
+    
+    /*set up the data socket                        */
+    send_socket = create_xti_endpoint(loc_xti_device);
+    
+    if (send_socket == INVALID_SOCKET) {
+      perror("netperf: send_xti_tcp_stream: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_xti_tcp_stream: send_socket obtained...\n");
+    }
+    
+    /* it would seem that with XTI, there is no implicit bind on a */
+    /* connect, so we have to make a call to t_bind. this is not */
+    /* terribly convenient, but I suppose that "standard is better */
+    /* than better" :) raj 2/95 */
+
+    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
+      t_error("send_xti_tcp_stream: t_bind");
+      exit(1);
+    }
+      
+    /* at this point, we have either retrieved the socket buffer sizes, */
+    /* or have tried to set them, so now, we may want to set the send */
+    /* size based on that (because the user either did not use a -m */
+    /* option, or used one with an argument of 0). If the socket buffer */
+    /* size is not available, we will set the send size to 4KB - no */
+    /* particular reason, just arbitrary... */
+    if (send_size == 0) {
+      if (lss_size > 0) {
+	send_size = lss_size;
+      }
+      else {
+	send_size = 4096;
+      }
+    }
+    
+    /* set-up the data buffer ring with the requested alignment and offset. */
+    /* note also that we have allocated a quantity */
+    /* of memory that is at least one send-size greater than our socket */
+    /* buffer size. We want to be sure that there are at least two */
+    /* buffers allocated - this can be a bit of a problem when the */
+    /* send_size is bigger than the socket size, so we must check... the */
+    /* user may have wanted to explicitly set the "width" of our send */
+    /* buffers, we should respect that wish... */
+
+    if (send_width == 0) {
+      send_width = (lss_size/send_size) + 1;
+      if (send_width == 1) send_width++;
+    }
+    
+    if (send_ring == NULL) {
+      /* only allocate the send ring once. this is a networking test, */
+      /* not a memory allocation test. this way, we do not need a */
+      /* deallocate_buffer_ring() routine, and I don't feel like */
+      /* writing one anyway :) raj 11/94 */
+      send_ring = allocate_buffer_ring(send_width,
+				       send_size,
+				       local_send_align,
+				       local_send_offset);
+    }
+
+    /* If the user has requested cpu utilization measurements, we must */
+    /* calibrate the cpu(s). We will perform this task within the tests */
+    /* themselves. If the user has specified the cpu rate, then */
+    /* calibrate_local_cpu will return rather quickly as it will have */
+    /* nothing to do. If local_cpu_rate is zero, then we will go through */
+    /* all the "normal" calibration stuff and return the rate back. */
+    
+    if (local_cpu_usage) {
+      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+    }
+    
+    /* Tell the remote end to do a listen. The server alters the socket */
+    /* paramters on the other side at this point, hence the reason for */
+    /* all the values being passed in the setup message. If the user did */
+    /* not specify any of the parameters, they will be passed as 0, which */
+    /* will indicate to the remote that no changes beyond the system's */
+    /* default should be used. Alignment is the exception, it will */
+    /* default to 1, which will be no alignment alterations. */
+    
+    netperf_request.content.request_type          = DO_XTI_TCP_STREAM;
+    xti_tcp_stream_request->send_buf_size  = rss_size;
+    xti_tcp_stream_request->recv_buf_size  = rsr_size;
+    xti_tcp_stream_request->receive_size   = recv_size;
+    xti_tcp_stream_request->no_delay       = rem_nodelay;
+    xti_tcp_stream_request->recv_alignment = remote_recv_align;
+    xti_tcp_stream_request->recv_offset    = remote_recv_offset;
+    xti_tcp_stream_request->measure_cpu    = remote_cpu_usage;
+    xti_tcp_stream_request->cpu_rate       = remote_cpu_rate;
+    if (test_time) {
+      xti_tcp_stream_request->test_length  = test_time;
+    }
+    else {
+      xti_tcp_stream_request->test_length  = test_bytes;
+    }
+    xti_tcp_stream_request->so_rcvavoid    = rem_rcvavoid;
+    xti_tcp_stream_request->so_sndavoid    = rem_sndavoid;
+
+    strcpy(xti_tcp_stream_request->xti_device, rem_xti_device);
+  
+#ifdef __alpha
+  
+    /* ok - even on a DEC box, strings are strings. I didn't really want */
+    /* to ntohl the words of a string. since I don't want to teach the */
+    /* send_ and recv_ _request and _response routines about the types, */
+    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+    /* solution would be to use XDR, but I am still leary of being able */
+    /* to find XDR libs on all platforms I want running netperf. raj */
+    {
+      int *charword;
+      int *initword;
+      int *lastword;
+      
+      initword = (int *) xti_tcp_stream_request->xti_device;
+      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
+      
+      for (charword = initword;
+	   charword < lastword;
+	   charword++) {
+	
+	*charword = ntohl(*charword);
+      }
+    }
+#endif /* __alpha */
+    
+#ifdef DIRTY
+    xti_tcp_stream_request->dirty_count         = rem_dirty_count;
+    xti_tcp_stream_request->clean_count         = rem_clean_count;
+#endif /* DIRTY */
+    
+    
+    if (debug > 1) {
+      fprintf(where,
+              "netperf: send_xti_tcp_stream: requesting TCP stream test\n");
+    }
+    
+    send_request();
+    
+    /* The response from the remote will contain all of the relevant    */
+    /* socket parameters for this test type. We will put them back into */
+    /* the variables here so they can be displayed if desired.  The     */
+    /* remote will have calibrated CPU if necessary, and will have done */
+    /* all the needed set-up we will have calibrated the cpu locally    */
+    /* before sending the request, and will grab the counter value right*/
+    /* after the connect returns. The remote will grab the counter right*/
+    /* after the accept call. This saves the hassle of extra messages   */
+    /* being sent for the TCP tests.                                    */
+    
+    recv_response();
+    
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+        fprintf(where,"remote listen done.\n");
+      rsr_size         = xti_tcp_stream_response->recv_buf_size;
+      rss_size         = xti_tcp_stream_response->send_buf_size;
+      rem_nodelay      = xti_tcp_stream_response->no_delay;
+      remote_cpu_usage = xti_tcp_stream_response->measure_cpu;
+      remote_cpu_rate  = xti_tcp_stream_response->cpu_rate;
+
+      /* we have to make sure that the server port number is in */
+      /* network order */
+      server.sin_port   = (short)xti_tcp_stream_response->data_port_number;
+      server.sin_port   = htons(server.sin_port); 
+      rem_rcvavoid      = xti_tcp_stream_response->so_rcvavoid;
+      rem_sndavoid      = xti_tcp_stream_response->so_sndavoid;
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /*Connect up to the remote port on the data socket  */
+    memset (&server_call, 0, sizeof(server_call));
+    server_call.addr.maxlen = sizeof(struct sockaddr_in);
+    server_call.addr.len    = sizeof(struct sockaddr_in);
+    server_call.addr.buf    = (char *)&server;
+
+    if (t_connect(send_socket, 
+		  &server_call,
+		  NULL) == INVALID_SOCKET){
+      t_error("netperf: send_xti_tcp_stream: data socket connect failed");
+      printf(" port: %d\n",ntohs(server.sin_port));
+      exit(1);
+    }
+    
+    /* Data Socket set-up is finished. If there were problems, either */
+    /* the connect would have failed, or the previous response would */
+    /* have indicated a problem. I failed to see the value of the */
+    /* extra  message after the accept on the remote. If it failed, */
+    /* we'll see it here. If it didn't, we might as well start pumping */
+    /* data. */ 
+    
+    /* Set-up the test end conditions. For a stream test, they can be */
+    /* either time or byte-count based. */
+    
+    if (test_time) {
+      /* The user wanted to end the test after a period of time. */
+      times_up = 0;
+      bytes_remaining = 0;
+      /* in previous revisions, we had the same code repeated throught */
+      /* all the test suites. this was unnecessary, and meant more */
+      /* work for me when I wanted to switch to POSIX signals, so I */
+      /* have abstracted this out into a routine in netlib.c. if you */
+      /* are experiencing signal problems, you might want to look */
+      /* there. raj 11/94 */
+      start_timer(test_time);
+    }
+    else {
+      /* The tester wanted to send a number of bytes. */
+      bytes_remaining = test_bytes;
+      times_up = 1;
+    }
+    
+    /* The cpu_start routine will grab the current time and possibly */
+    /* value of the idle counter for later use in measuring cpu */
+    /* utilization and/or service demand and thruput. */
+    
+    cpu_start(local_cpu_usage);
+    
+#ifdef WANT_INTERVALS
+    if ((interval_burst) || (demo_mode)) {
+      /* zero means that we never pause, so we never should need the */
+      /* interval timer, unless we are in demo_mode */
+      start_itimer(interval_wate);
+    }
+    interval_count = interval_burst;
+    /* get the signal set for the call to sigsuspend */
+    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
+      fprintf(where,
+              "send_xti_tcp_stream: unable to get sigmask errno %d\n",
+              errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+
+    /* before we start, initialize a few variables */
+
+    /* We use an "OR" to control test execution. When the test is */
+    /* controlled by time, the byte count check will always return false. */
+    /* When the test is controlled by byte count, the time test will */
+    /* always return false. When the test is finished, the whole */
+    /* expression will go false and we will stop sending data. */
+    
+    while ((!times_up) || (bytes_remaining > 0)) {
+      
+#ifdef DIRTY
+      /* we want to dirty some number of consecutive integers in the buffer */
+      /* we are about to send. we may also want to bring some number of */
+      /* them cleanly into the cache. The clean ones will follow any dirty */
+      /* ones into the cache. at some point, we might want to replace */
+      /* the rand() call with something from a table to reduce our call */
+      /* overhead during the test, but it is not a high priority item. */
+      access_buffer(send_ring->buffer_ptr,
+		    send_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+#endif /* DIRTY */
+      
+#ifdef WANT_HISTOGRAM
+      /* timestamp just before we go into send and then again just after */
+      /* we come out raj 8/94 */
+      HIST_timestamp(&time_one);
+#endif /* WANT_HISTOGRAM */
+      
+      if((len=t_snd(send_socket,
+		    send_ring->buffer_ptr,
+		    send_size,
+		    0)) != send_size) {
+        if ((len >=0) || (errno == EINTR)) {
+          /* the test was interrupted, must be the end of test */
+          break;
+        }
+        fprintf(where,
+		"send_xti_tcp_stream: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
+		errno,
+		t_errno,
+		t_look(send_socket));
+	fflush(where);
+        exit(1);
+      }
+
+#ifdef WANT_HISTOGRAM
+      /* timestamp the exit from the send call and update the histogram */
+      HIST_timestamp(&time_two);
+      HIST_add(time_hist,delta_micro(&time_one,&time_two));
+#endif /* WANT_HISTOGRAM */      
+
+#ifdef WANT_INTERVALS      
+      if (demo_mode) {
+        units_this_tick += send_size;
+      }
+      /* in this case, the interval count is the count-down couter */
+      /* to decide to sleep for a little bit */
+      if ((interval_burst) && (--interval_count == 0)) {
+        /* call sigsuspend and wait for the interval timer to get us */
+        /* out */
+        if (debug) {
+          fprintf(where,"about to suspend\n");
+          fflush(where);
+        }
+        if (sigsuspend(&signal_set) == EFAULT) {
+          fprintf(where,
+                  "send_xti_tcp_stream: fault with signal set!\n");
+          fflush(where);
+          exit(1);
+        }
+        interval_count = interval_burst;
+      }
+#endif /* WANT_INTERVALS */
+      
+      /* now we want to move our pointer to the next position in the */
+      /* data buffer...we may also want to wrap back to the "beginning" */
+      /* of the bufferspace, so we will mod the number of messages sent */
+      /* by the send width, and use that to calculate the offset to add */
+      /* to the base pointer. */
+      nummessages++;          
+      send_ring = send_ring->next;
+      if (bytes_remaining) {
+        bytes_remaining -= send_size;
+      }
+    }
+
+    /* The test is over. Flush the buffers to the remote end. We do a */
+    /* graceful release to insure that all data has been taken by the */
+    /* remote. */ 
+
+    /* but first, if the verbosity is greater than 1, find-out what */
+    /* the TCP maximum segment_size was (if possible) */
+    if (verbosity > 1) {
+      tcp_mss = -1;
+      get_xti_info(send_socket,info_struct);
+    }
+    
+    if (t_sndrel(send_socket) == -1) {
+      t_error("netperf: cannot shutdown tcp stream socket");
+      exit(1);
+    }
+    
+    /* hang a t_rcvrel() off the socket to block until the remote has */
+    /* brought all the data up into the application. it will do a */
+    /* t_sedrel to cause a FIN to be sent our way. We will assume that */
+    /* any exit from the t_rcvrel() call is good... raj 2/95 */
+    
+    if (debug > 1) {
+      fprintf(where,"about to hang a receive for graceful release.\n");
+      fflush(where);
+    }
+
+    t_rcvrel(send_socket);
+    
+    /* this call will always give us the elapsed time for the test, and */
+    /* will also store-away the necessaries for cpu utilization */
+    
+    cpu_stop(local_cpu_usage,&elapsed_time);    /* was cpu being */
+                                                /* measured and how */
+                                                /* long did we really */
+                                                /* run? */
+    
+    /* Get the statistics from the remote end. The remote will have */
+    /* calculated service demand and all those interesting things. If it */
+    /* wasn't supposed to care, it will return obvious values. */
+    
+    recv_response();
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+        fprintf(where,"remote results obtained\n");
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /* We now calculate what our thruput was for the test. In the future, */
+    /* we may want to include a calculation of the thruput measured by */
+    /* the remote, but it should be the case that for a TCP stream test, */
+    /* that the two numbers should be *very* close... We calculate */
+    /* bytes_sent regardless of the way the test length was controlled. */
+    /* If it was time, we needed to, and if it was by bytes, the user may */
+    /* have specified a number of bytes that wasn't a multiple of the */
+    /* send_size, so we really didn't send what he asked for ;-) */
+    
+    bytes_sent  = xti_tcp_stream_result->bytes_received;
+
+    thruput     = calc_thruput(bytes_sent);
+    
+    if (local_cpu_usage || remote_cpu_usage) {
+      /* We must now do a little math for service demand and cpu */
+      /* utilization for the system(s) */
+      /* Of course, some of the information might be bogus because */
+      /* there was no idle counter in the kernel(s). We need to make */
+      /* a note of this for the user's benefit...*/
+      if (local_cpu_usage) {
+        
+        local_cpu_utilization   = calc_cpu_util(0.0);
+        local_service_demand    = calc_service_demand(bytes_sent,
+                                                      0.0,
+                                                      0.0,
+						      0);
+      }
+      else {
+        local_cpu_utilization   = -1.0;
+        local_service_demand    = -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+        
+        remote_cpu_utilization  = xti_tcp_stream_result->cpu_util;
+        remote_service_demand   = calc_service_demand(bytes_sent,
+                                                      0.0,
+                                                      remote_cpu_utilization,
+						      xti_tcp_stream_result->num_cpus);
+      }
+      else {
+        remote_cpu_utilization = -1.0;
+        remote_service_demand  = -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization  = -1.0;
+      local_service_demand   = -1.0;
+      remote_cpu_utilization = -1.0;
+      remote_service_demand  = -1.0;
+    }
+
+    /* at this point, we want to calculate the confidence information. */
+    /* if debugging is on, calculate_confidence will print-out the */
+    /* parameters we pass it */
+    
+    calculate_confidence(confidence_iteration,
+                         elapsed_time,
+                         thruput,
+                         local_cpu_utilization,
+                         remote_cpu_utilization,
+                         local_service_demand,
+                         remote_service_demand);
+    
+    
+    confidence_iteration++;
+  }
+
+  /* at this point, we have finished making all the runs that we */
+  /* will be making. so, we should extract what the calcuated values */
+  /* are for all the confidence stuff. we could make the values */
+  /* global, but that seemed a little messy, and it did not seem worth */
+  /* all the mucking with header files. so, we create a routine much */
+  /* like calcualte_confidence, which just returns the mean values. */
+  /* raj 11/94 */
+
+  retrieve_confident_values(&elapsed_time,
+                            &thruput,
+                            &local_cpu_utilization,
+                            &remote_cpu_utilization,
+                            &local_service_demand,
+                            &remote_service_demand);
+
+  /* We are now ready to print all the information. If the user */
+  /* has specified zero-level verbosity, we will just print the */
+  /* local service demand, or the remote service demand. If the */
+  /* user has requested verbosity level 1, he will get the basic */
+  /* "streamperf" numbers. If the user has specified a verbosity */
+  /* of greater than 1, we will display a veritable plethora of */
+  /* background information from outside of this block as it it */
+  /* not cpu_measurement specific...  */
+
+  if (confidence < 0) {
+    /* we did not hit confidence, but were we asked to look for it? */
+    if (iteration_max > 1) {
+      display_confidence();
+    }
+  }
+
+  if (local_cpu_usage || remote_cpu_usage) {
+    local_cpu_method = format_cpu_method(cpu_method);
+    remote_cpu_method = format_cpu_method(xti_tcp_stream_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+        fprintf(where,
+                cpu_fmt_0,
+                local_service_demand,
+		local_cpu_method);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method);
+      }
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,
+		cpu_title,
+		format_units(),
+		local_cpu_method,
+		remote_cpu_method);
+      }
+    
+      fprintf(where,
+	      cpu_fmt_1,		/* the format string */
+	      rsr_size,		        /* remote recvbuf size */
+	      lss_size,		        /* local sendbuf size */
+	      send_size,		/* how large were the sends */
+	      elapsed_time,		/* how long was the test */
+	      thruput, 		        /* what was the xfer rate */
+	      local_cpu_utilization,	/* local cpu */
+	      remote_cpu_utilization,	/* remote cpu */
+	      local_service_demand,	/* local service demand */
+	      remote_service_demand);	/* remote service demand */
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      rsr_size, 		/* remote recvbuf size */
+	      lss_size, 		/* local sendbuf size */
+	      send_size,		/* how large were the sends */
+	      elapsed_time, 		/* how long did it take */
+	      thruput);/* how fast did it go */
+      break;
+    }
+  }
+  
+  /* it would be a good thing to include information about some of the */
+  /* other parameters that may have been set for this test, but at the */
+  /* moment, I do not wish to figure-out all the  formatting, so I will */
+  /* just put this comment here to help remind me that it is something */
+  /* that should be done at a later time. */
+  
+  if (verbosity > 1) {
+    /* The user wanted to know it all, so we will give it to him. */
+    /* This information will include as much as we can find about */
+    /* TCP statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+   
+    /* this stuff needs to be worked-out in the presence of confidence */
+    /* intervals and multiple iterations of the test... raj 11/94 */
+ 
+    fprintf(where,
+	    ksink_fmt,
+	    "Bytes",
+	    "Bytes",
+	    "Bytes",
+	    local_send_align,
+	    remote_recv_align,
+	    local_send_offset,
+	    remote_recv_offset,
+	    bytes_sent,
+	    bytes_sent / (double)nummessages,
+	    nummessages,
+	    bytes_sent / (double)xti_tcp_stream_result->recv_calls,
+	    xti_tcp_stream_result->recv_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    tcp_mss);
+    fflush(where);
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\n\nHistogram of time spent in send() call.\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+  }
+  
+}
+
+
+/* This is the server-side routine for the tcp stream test. It is */
+/* implemented as one routine. I could break things-out somewhat, but */
+/* didn't feel it was necessary. */
+
+void 
+recv_xti_tcp_stream()
+{
+  
+  struct sockaddr_in myaddr_in, peeraddr_in;
+  struct t_bind      bind_req, bind_resp;
+  struct t_call      call_req;
+
+  SOCKET       s_listen,s_data;
+  int           addrlen;
+  int	        len;
+  unsigned int	receive_calls;
+  float	        elapsed_time;
+  double        bytes_received;
+  
+  struct ring_elt *recv_ring;
+
+  int   *message_int_ptr;
+  int   i;
+  
+  struct xti_tcp_stream_request_struct	*xti_tcp_stream_request;
+  struct xti_tcp_stream_response_struct	*xti_tcp_stream_response;
+  struct xti_tcp_stream_results_struct	*xti_tcp_stream_results;
+  
+  xti_tcp_stream_request	= 
+    (struct xti_tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_stream_response	= 
+    (struct xti_tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_stream_results	= 
+    (struct xti_tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_xti_tcp_stream: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen socket with all the desired */
+  /* parameters and then let the initiator know that all is ready. If */
+  /* socket size defaults are to be used, then the initiator will have */
+  /* sent us 0's. If the socket sizes cannot be changed, then we will */
+  /* send-back what they are. If that information cannot be determined, */
+  /* then we send-back -1's for the sizes. If things go wrong for any */
+  /* reason, we will drop back ten yards and punt. */
+  
+  /* If anything goes wrong, we want the remote to know about it. It */
+  /* would be best if the error that the remote reports to the user is */
+  /* the actual error we encountered, rather than some bogus unexpected */
+  /* response type message. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = XTI_TCP_STREAM_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_stream: the response type is set...\n");
+    fflush(where);
+  }
+  
+  /* We now alter the message_ptr variable to be at the desired */
+  /* alignment with the desired offset. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_stream: requested alignment of %d\n",
+	    xti_tcp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
+  /* can put in OUR values !-) At some point, we may want to nail this */
+  /* socket to a particular network-level address, but for now, */
+  /* INADDR_ANY should be just fine. */
+  
+  bzero((char *)&myaddr_in,
+	sizeof(myaddr_in));
+  myaddr_in.sin_family      = AF_INET;
+  myaddr_in.sin_addr.s_addr = INADDR_ANY;
+  myaddr_in.sin_port        = 0;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_stream: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  /* create_xti_endpoint expects to find some things in the global */
+  /* variables, so set the globals based on the values in the request. */
+  /* once the socket has been created, we will set the response values */
+  /* based on the updated value of those globals. raj 7/94 */
+  lss_size = xti_tcp_stream_request->send_buf_size;
+  lsr_size = xti_tcp_stream_request->recv_buf_size;
+  loc_nodelay = xti_tcp_stream_request->no_delay;
+  loc_rcvavoid = xti_tcp_stream_request->so_rcvavoid;
+  loc_sndavoid = xti_tcp_stream_request->so_sndavoid;
+
+#ifdef __alpha
+  
+  /* ok - even on a DEC box, strings are strings. I din't really want */
+  /* to ntohl the words of a string. since I don't want to teach the */
+  /* send_ and recv_ _request and _response routines about the types, */
+  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+  /* solution would be to use XDR, but I am still leary of being able */
+  /* to find XDR libs on all platforms I want running netperf. raj */
+  {
+    int *charword;
+    int *initword;
+    int *lastword;
+    
+    initword = (int *) xti_tcp_stream_request->xti_device;
+    lastword = initword + ((xti_tcp_stream_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+  
+#endif /* __alpha */
+
+  s_listen = create_xti_endpoint(xti_tcp_stream_request->xti_device);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* Let's get an address assigned to this socket so we can tell the */
+  /* initiator how to reach the data socket. There may be a desire to */
+  /* nail this socket to a specific IP address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+  
+  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_req.addr.len    = sizeof(struct sockaddr_in);
+  bind_req.addr.buf    = (char *)&myaddr_in;
+  bind_req.qlen        = 1;
+
+  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_resp.addr.len    = sizeof(struct sockaddr_in);
+  bind_resp.addr.buf    = (char *)&myaddr_in;
+  bind_resp.qlen        = 1;
+
+  if (t_bind(s_listen,
+	     &bind_req,
+	     &bind_resp) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = t_errno;
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_bind complete port %d\n",
+	    ntohs(myaddr_in.sin_port));
+    fflush(where);
+  }
+  
+  /* what sort of sizes did we end-up with? */
+  if (xti_tcp_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = xti_tcp_stream_request->receive_size;
+  }
+  
+  /* we want to set-up our recv_ring in a manner analagous to what we */
+  /* do on the sending side. this is more for the sake of symmetry */
+  /* than for the needs of say copy avoidance, but it might also be */
+  /* more realistic - this way one could conceivably go with a */
+  /* double-buffering scheme when taking the data an putting it into */
+  /* the filesystem or something like that. raj 7/94 */
+
+  if (recv_width == 0) {
+    recv_width = (lsr_size/recv_size) + 1;
+    if (recv_width == 1) recv_width++;
+  }
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   recv_size,
+				   xti_tcp_stream_request->recv_alignment,
+				   xti_tcp_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_stream: recv alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Now myaddr_in contains the port and the internet address this is */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  
+  xti_tcp_stream_response->data_port_number = 
+    (int) ntohs(myaddr_in.sin_port);
+  netperf_response.content.serv_errno   = 0;
+  
+  /* But wait, there's more. If the initiator wanted cpu measurements, */
+  /* then we must call the calibrate routine, which will return the max */
+  /* rate back to the initiator. If the CPU was not to be measured, or */
+  /* something went wrong with the calibration, we will return a -1 to */
+  /* the initiator. */
+  
+  xti_tcp_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (xti_tcp_stream_request->measure_cpu) {
+    xti_tcp_stream_response->measure_cpu = 1;
+    xti_tcp_stream_response->cpu_rate = 
+      calibrate_local_cpu(xti_tcp_stream_request->cpu_rate);
+  }
+  else {
+    xti_tcp_stream_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  xti_tcp_stream_response->send_buf_size = lss_size;
+  xti_tcp_stream_response->recv_buf_size = lsr_size;
+  xti_tcp_stream_response->no_delay = loc_nodelay;
+  xti_tcp_stream_response->so_rcvavoid = loc_rcvavoid;
+  xti_tcp_stream_response->so_sndavoid = loc_sndavoid;
+  xti_tcp_stream_response->receive_size = recv_size;
+
+  send_response();
+  
+  /* Now, let's set-up the socket to listen for connections. for xti, */
+  /* the t_listen call is blocking by default - this is different */
+  /* semantics from BSD - probably has to do with being able to reject */
+  /* a call before an accept */
+  call_req.addr.maxlen = sizeof(struct sockaddr_in);
+  call_req.addr.len    = sizeof(struct sockaddr_in);
+  call_req.addr.buf    = (char *)&peeraddr_in;
+  call_req.opt.maxlen  = 0;
+  call_req.opt.len     = 0;
+  call_req.opt.buf     = NULL;
+  call_req.udata.maxlen= 0;
+  call_req.udata.len   = 0;
+  call_req.udata.buf   = 0;
+
+  if (t_listen(s_listen, &call_req) == -1) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_listen: errno %d t_errno %d\n",
+	    errno,
+	    t_errno);
+    fflush(where);
+    netperf_response.content.serv_errno = t_errno;
+    close(s_listen);
+    send_response();
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_listen complete t_look 0x%.4x\n",
+	    t_look(s_listen));
+    fflush(where);
+  }
+  
+  /* now just rubber stamp the thing. we want to use the same fd? so */
+  /* we will just equate s_data with s_listen. this seems a little */
+  /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
+  s_data = s_listen;
+  if (t_accept(s_listen,
+	       s_data,
+	       &call_req) == -1) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_accept: errno %d t_errno %d\n",
+	    errno,
+	    t_errno);
+    fflush(where);
+    close(s_listen);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_accept complete t_look 0x%.4x\n",
+	    t_look(s_data));
+    fprintf(where,
+	    "                     remote is %s port %d\n",
+	    inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
+	    ntohs(peeraddr_in.sin_port));
+    fflush(where);
+  }
+
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(xti_tcp_stream_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a t_sndrel, which will */
+  /* return T_LOOK error from the t_recv */
+  
+#ifdef DIRTY
+    /* we want to dirty some number of consecutive integers in the buffer */
+    /* we are about to recv. we may also want to bring some number of */
+    /* them cleanly into the cache. The clean ones will follow any dirty */
+    /* ones into the cache. */
+
+  access_buffer(recv_ring->buffer_ptr,
+		recv_size,
+		xti_tcp_stream_request->dirty_count,
+		xti_tcp_stream_request->clean_count);
+
+#endif /* DIRTY */
+
+  bytes_received = 0;
+  receive_calls  = 0;
+
+  while ((len = t_rcv(s_data,
+		      recv_ring->buffer_ptr,
+		      recv_size,
+		      &xti_flags)) != -1) {
+    bytes_received += len;
+    receive_calls++;
+    
+    /* more to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+    
+#ifdef DIRTY
+
+  access_buffer(recv_ring->buffer_ptr,
+		recv_size,
+		xti_tcp_stream_request->dirty_count,
+		xti_tcp_stream_request->clean_count);
+
+#endif /* DIRTY */
+  }
+  
+  if (t_look(s_data) == T_ORDREL) {
+    /* this is a normal exit path */
+    if (debug) {
+      fprintf(where,
+	      "recv_xti_tcp_stream: t_rcv T_ORDREL indicated\n");
+      fflush(where);
+    }
+  }
+  else {
+    /* something went wrong */
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_rcv: errno %d t_errno %d len %d",
+	    errno,
+	    t_errno,
+	    len);
+    fprintf(where,
+	    " t_look 0x%.4x",
+	    t_look(s_data));
+    fflush(where);
+    netperf_response.content.serv_errno = t_errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* receive the release and let the initiator know that we have */
+  /* received all the data. raj 3/95 */
+
+  if (t_rcvrel(s_data) == -1) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }    
+
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_rcvrel complete\n");
+    fflush(where);
+  }
+
+  if (t_sndrel(s_data) == -1) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: t_sndrel complete\n");
+    fflush(where);
+  }
+
+  cpu_stop(xti_tcp_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: got %g bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_xti_tcp_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  xti_tcp_stream_results->bytes_received	= bytes_received;
+  xti_tcp_stream_results->elapsed_time	= elapsed_time;
+  xti_tcp_stream_results->recv_calls	= receive_calls;
+  
+  if (xti_tcp_stream_request->measure_cpu) {
+    xti_tcp_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_stream: test complete, sending results.\n");
+    fprintf(where,
+	    "                 bytes_received %g receive_calls %d\n",
+	    bytes_received,
+	    receive_calls);
+    fprintf(where,
+	    "                 len %d\n",
+	    len);
+    fflush(where);
+  }
+  
+  xti_tcp_stream_results->cpu_method = cpu_method;
+  send_response();
+
+  /* we are now done with the socket */
+  t_close(s_data);
+
+}
+
+
+ /* this routine implements the sending (netperf) side of the XTI_TCP_RR */
+ /* test. */
+
+void 
+send_xti_tcp_rr(char remote_host[])
+{
+  
+  char *tput_title = "\
+Local /Remote\n\
+Socket Size   Request  Resp.   Elapsed  Trans.\n\
+Send   Recv   Size     Size    Time     Rate         \n\
+bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
+  char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *cpu_title = "\
+Local /Remote\n\
+Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
+Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
+bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f %c\n";
+  
+  char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f\n";
+  
+  char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *ksink_fmt = "\
+Alignment      Offset\n\
+Local  Remote  Local  Remote\n\
+Send   Recv    Send   Recv\n\
+%5d  %5d   %5d  %5d\n";
+  
+  
+  int			timed_out = 0;
+  float			elapsed_time;
+  
+  int	len;
+  char	*temp_message_ptr;
+  int	nummessages;
+  SOCKET send_socket;
+  int	trans_remaining;
+  double	bytes_xferd;
+
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+  
+  int	rsp_bytes_left;
+  int	rsp_bytes_recvd;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct	hostent	        *hp;
+  struct	sockaddr_in	server;
+  unsigned      int             addr;
+  
+  struct t_call server_call;
+
+  struct	xti_tcp_rr_request_struct	*xti_tcp_rr_request;
+  struct	xti_tcp_rr_response_struct	*xti_tcp_rr_response;
+  struct	xti_tcp_rr_results_struct	*xti_tcp_rr_result;
+  
+#ifdef WANT_INTERVALS
+  int	interval_count;
+  sigset_t signal_set;
+#endif /* WANT_INTERVALS */
+
+  xti_tcp_rr_request = 
+    (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_rr_response=
+    (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_rr_result	=
+    (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  time_hist = HIST_new();
+#endif /* WANT_HISTOGRAM */
+
+  /* since we are now disconnected from the code that established the */
+  /* control socket, and since we want to be able to use different */
+  /* protocols and such, we are passed the name of the remote host and */
+  /* must turn that into the test specific addressing information. */
+
+  bzero((char *)&server,
+	sizeof(server));
+  
+  /* it would seem that while HP-UX will allow an IP address (as a */
+  /* string) in a call to gethostbyname, other, less enlightened */
+  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
+  /* order changed to check for IP address first. raj 7/96 */
+
+  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
+    /* it was not an IP address, try it as a name */
+    if ((hp = gethostbyname(remote_host)) == NULL) {
+      /* we have no idea what it is */
+      fprintf(where,
+	      "establish_control: could not resolve the destination %s\n",
+	      remote_host);
+      fflush(where);
+      exit(1);
+    }
+    else {
+      /* it was a valid remote_host */
+      bcopy(hp->h_addr,
+	    (char *)&server.sin_addr,
+	    hp->h_length);
+      server.sin_family = hp->h_addrtype;
+    }
+  }
+  else {
+    /* it was a valid IP address */
+    server.sin_addr.s_addr = addr;
+    server.sin_family = AF_INET;
+  }    
+  
+  if ( print_headers ) {
+    fprintf(where,"XTI TCP REQUEST/RESPONSE TEST");
+    fprintf(where," to %s", remote_host);
+    if (iteration_max > 1) {
+      fprintf(where,
+	      " : +/-%3.1f%% @ %2d%% conf.",
+	      interval/0.02,
+	      confidence_level);
+      }
+    if (loc_nodelay || rem_nodelay) {
+      fprintf(where," : nodelay");
+    }
+    if (loc_sndavoid || 
+	loc_rcvavoid ||
+	rem_sndavoid ||
+	rem_rcvavoid) {
+      fprintf(where," : copy avoidance");
+    }
+#ifdef WANT_HISTOGRAM
+    fprintf(where," : histogram");
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS
+    fprintf(where," : interval");
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY 
+    fprintf(where," : dirty data");
+#endif /* DIRTY */
+    fprintf(where,"\n");
+  }
+  
+  /* initialize a few counters */
+  
+  send_ring = NULL;
+  recv_ring = NULL;
+  confidence_iteration = 1;
+  init_stat();
+
+  /* we have a great-big while loop which controls the number of times */
+  /* we run a particular test. this is for the calculation of a */
+  /* confidence interval (I really should have stayed awake during */
+  /* probstats :). If the user did not request confidence measurement */
+  /* (no confidence is the default) then we will only go though the */
+  /* loop once. the confidence stuff originates from the folks at IBM */
+
+  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
+	 (confidence_iteration <= iteration_min)) {
+
+    /* initialize a few counters. we have to remember that we might be */
+    /* going through the loop more than once. */
+
+    nummessages     = 0;
+    bytes_xferd     = 0.0;
+    times_up        = 0;
+    timed_out       = 0;
+    trans_remaining = 0;
+
+    /* set-up the data buffers with the requested alignment and offset. */
+    /* since this is a request/response test, default the send_width and */
+    /* recv_width to 1 and not two raj 7/94 */
+
+    if (send_width == 0) send_width = 1;
+    if (recv_width == 0) recv_width = 1;
+  
+    if (send_ring == NULL) {
+      send_ring = allocate_buffer_ring(send_width,
+				       req_size,
+				       local_send_align,
+				       local_send_offset);
+    }
+
+    if (recv_ring == NULL) {
+      recv_ring = allocate_buffer_ring(recv_width,
+				       rsp_size,
+				       local_recv_align,
+				       local_recv_offset);
+    }
+    
+    /*set up the data socket                        */
+    send_socket = create_xti_endpoint(loc_xti_device);
+  
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_xti_tcp_rr: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_xti_tcp_rr: send_socket obtained...\n");
+    }
+
+    /* it would seem that with XTI, there is no implicit bind on a */
+    /* connect, so we have to make a call to t_bind. this is not */
+    /* terribly convenient, but I suppose that "standard is better */
+    /* than better" :) raj 2/95 */
+
+    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
+      t_error("send_xti_tcp_stream: t_bind");
+      exit(1);
+    }
+  
+    /* If the user has requested cpu utilization measurements, we must */
+    /* calibrate the cpu(s). We will perform this task within the tests */
+    /* themselves. If the user has specified the cpu rate, then */
+    /* calibrate_local_cpu will return rather quickly as it will have */
+    /* nothing to do. If local_cpu_rate is zero, then we will go through */
+    /* all the "normal" calibration stuff and return the rate back.*/
+    
+    if (local_cpu_usage) {
+      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+    }
+    
+    /* Tell the remote end to do a listen. The server alters the socket */
+    /* paramters on the other side at this point, hence the reason for */
+    /* all the values being passed in the setup message. If the user did */
+    /* not specify any of the parameters, they will be passed as 0, which */
+    /* will indicate to the remote that no changes beyond the system's */
+    /* default should be used. Alignment is the exception, it will */
+    /* default to 8, which will be no alignment alterations. */
+    
+    netperf_request.content.request_type	=	DO_XTI_TCP_RR;
+    xti_tcp_rr_request->recv_buf_size	=	rsr_size;
+    xti_tcp_rr_request->send_buf_size	=	rss_size;
+    xti_tcp_rr_request->recv_alignment  =	remote_recv_align;
+    xti_tcp_rr_request->recv_offset	=	remote_recv_offset;
+    xti_tcp_rr_request->send_alignment  =	remote_send_align;
+    xti_tcp_rr_request->send_offset	=	remote_send_offset;
+    xti_tcp_rr_request->request_size	=	req_size;
+    xti_tcp_rr_request->response_size	=	rsp_size;
+    xti_tcp_rr_request->no_delay	=	rem_nodelay;
+    xti_tcp_rr_request->measure_cpu	=	remote_cpu_usage;
+    xti_tcp_rr_request->cpu_rate	=	remote_cpu_rate;
+    xti_tcp_rr_request->so_rcvavoid	=	rem_rcvavoid;
+    xti_tcp_rr_request->so_sndavoid	=	rem_sndavoid;
+    if (test_time) {
+      xti_tcp_rr_request->test_length	=	test_time;
+    }
+    else {
+      xti_tcp_rr_request->test_length	=	test_trans * -1;
+    }
+
+    strcpy(xti_tcp_rr_request->xti_device, rem_xti_device);
+  
+#ifdef __alpha
+  
+    /* ok - even on a DEC box, strings are strings. I didn't really want */
+    /* to ntohl the words of a string. since I don't want to teach the */
+    /* send_ and recv_ _request and _response routines about the types, */
+    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+    /* solution would be to use XDR, but I am still leary of being able */
+    /* to find XDR libs on all platforms I want running netperf. raj */
+    {
+      int *charword;
+      int *initword;
+      int *lastword;
+      
+      initword = (int *) xti_tcp_rr_request->xti_device;
+      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
+      
+      for (charword = initword;
+	   charword < lastword;
+	   charword++) {
+	
+	*charword = ntohl(*charword);
+      }
+    }
+#endif /* __alpha */
+    
+    if (debug > 1) {
+      fprintf(where,"netperf: send_xti_tcp_rr: requesting TCP rr test\n");
+    }
+    
+    send_request();
+    
+    /* The response from the remote will contain all of the relevant 	*/
+    /* socket parameters for this test type. We will put them back into */
+    /* the variables here so they can be displayed if desired.  The	*/
+    /* remote will have calibrated CPU if necessary, and will have done	*/
+    /* all the needed set-up we will have calibrated the cpu locally	*/
+    /* before sending the request, and will grab the counter value right*/
+    /* after the connect returns. The remote will grab the counter right*/
+    /* after the accept call. This saves the hassle of extra messages	*/
+    /* being sent for the TCP tests.					*/
+  
+    recv_response();
+  
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote listen done.\n");
+      rsr_size          = xti_tcp_rr_response->recv_buf_size;
+      rss_size          = xti_tcp_rr_response->send_buf_size;
+      rem_nodelay       = xti_tcp_rr_response->no_delay;
+      remote_cpu_usage  = xti_tcp_rr_response->measure_cpu;
+      remote_cpu_rate   = xti_tcp_rr_response->cpu_rate;
+      /* make sure that port numbers are in network order */
+      server.sin_port   = (short)xti_tcp_rr_response->data_port_number;
+      server.sin_port   = htons(server.sin_port);
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /*Connect up to the remote port on the data socket  */
+    memset (&server_call, 0, sizeof(server_call));
+    server_call.addr.maxlen = sizeof(struct sockaddr_in);
+    server_call.addr.len    = sizeof(struct sockaddr_in);
+    server_call.addr.buf    = (char *)&server;
+
+    if (t_connect(send_socket, 
+		  &server_call,
+		  NULL) == INVALID_SOCKET){
+      t_error("netperf: send_xti_tcp_rr: data socket connect failed");
+      printf(" port: %d\n",ntohs(server.sin_port));
+      exit(1);
+    }
+
+    /* Data Socket set-up is finished. If there were problems, either the */
+    /* connect would have failed, or the previous response would have */
+    /* indicated a problem. I failed to see the value of the extra */
+    /* message after the accept on the remote. If it failed, we'll see it */
+    /* here. If it didn't, we might as well start pumping data. */
+    
+    /* Set-up the test end conditions. For a request/response test, they */
+    /* can be either time or transaction based. */
+    
+    if (test_time) {
+      /* The user wanted to end the test after a period of time. */
+      times_up = 0;
+      trans_remaining = 0;
+      start_timer(test_time);
+    }
+    else {
+      /* The tester wanted to send a number of bytes. */
+      trans_remaining = test_bytes;
+      times_up = 1;
+    }
+    
+    /* The cpu_start routine will grab the current time and possibly */
+    /* value of the idle counter for later use in measuring cpu */
+    /* utilization and/or service demand and thruput. */
+    
+    cpu_start(local_cpu_usage);
+
+#ifdef WANT_INTERVALS
+    if ((interval_burst) || (demo_mode)) {
+      /* zero means that we never pause, so we never should need the */
+      /* interval timer, unless we are in demo_mode */
+      start_itimer(interval_wate);
+    }
+    interval_count = interval_burst;
+    /* get the signal set for the call to sigsuspend */
+    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
+      fprintf(where,
+	      "send_xti_tcp_rr: unable to get sigmask errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+    
+    /* We use an "OR" to control test execution. When the test is */
+    /* controlled by time, the byte count check will always return false. */
+    /* When the test is controlled by byte count, the time test will */
+    /* always return false. When the test is finished, the whole */
+    /* expression will go false and we will stop sending data. I think I */
+    /* just arbitrarily decrement trans_remaining for the timed test, but */
+    /* will not do that just yet... One other question is whether or not */
+    /* the send buffer and the receive buffer should be the same buffer. */
+
+    while ((!times_up) || (trans_remaining > 0)) {
+      /* send the request. we assume that if we use a blocking socket, */
+      /* the request will be sent at one shot. */
+      
+#ifdef WANT_HISTOGRAM
+      /* timestamp just before our call to send, and then again just */
+      /* after the receive raj 8/94 */
+      HIST_timestamp(&time_one);
+#endif /* WANT_HISTOGRAM */
+      
+      if((len=t_snd(send_socket,
+		    send_ring->buffer_ptr,
+		    req_size,
+		    0)) != req_size) {
+	if ((errno == EINTR) || (errno == 0)) {
+	  /* we hit the end of a */
+	  /* timed test. */
+	  timed_out = 1;
+	  break;
+	}
+        fprintf(where,
+		"send_xti_tcp_rr: t_snd: errno %d t_errno %d t_look 0x%.4x\n",
+		errno,
+		t_errno,
+		t_look(send_socket));
+	fflush(where);
+        exit(1);
+      }
+      send_ring = send_ring->next;
+      
+      /* receive the response */
+      rsp_bytes_left = rsp_size;
+      temp_message_ptr  = recv_ring->buffer_ptr;
+      while(rsp_bytes_left > 0) {
+	if((rsp_bytes_recvd=t_rcv(send_socket,
+				  temp_message_ptr,
+				  rsp_bytes_left,
+				  &xti_flags)) == SOCKET_ERROR) {
+	  if (errno == EINTR) {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+	  fprintf(where,
+		  "send_xti_tcp_rr: t_rcv: errno %d t_errno %d t_look 0x%x\n",
+		  errno,
+		  t_errno,
+		  t_look(send_socket));
+	  fflush(where);
+	  exit(1);
+	}
+	rsp_bytes_left -= rsp_bytes_recvd;
+	temp_message_ptr  += rsp_bytes_recvd;
+      }	
+      recv_ring = recv_ring->next;
+      
+      if (timed_out) {
+	/* we may have been in a nested while loop - we need */
+	/* another call to break. */
+	break;
+      }
+      
+#ifdef WANT_HISTOGRAM
+      HIST_timestamp(&time_two);
+      HIST_add(time_hist,delta_micro(&time_one,&time_two));
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS      
+      if (demo_mode) {
+	units_this_tick += 1;
+      }
+      /* in this case, the interval count is the count-down couter */
+      /* to decide to sleep for a little bit */
+      if ((interval_burst) && (--interval_count == 0)) {
+	/* call sigsuspend and wait for the interval timer to get us */
+	/* out */
+	if (debug) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_xti_udp_rr: fault with signal set!\n");
+	  fflush(where);
+	  exit(1);
+	}
+	interval_count = interval_burst;
+      }
+#endif /* WANT_INTERVALS */
+      
+      nummessages++;          
+      if (trans_remaining) {
+	trans_remaining--;
+      }
+      
+      if (debug > 3) {
+	if ((nummessages % 100) == 0) {
+	  fprintf(where,
+		  "Transaction %d completed\n",
+		  nummessages);
+	  fflush(where);
+	}
+      }
+    }
+
+    
+    /* this call will always give us the elapsed time for the test, and */
+    /* will also store-away the necessaries for cpu utilization */
+    
+    cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being */
+						/* measured? how long */
+						/* did we really run? */
+    
+    /* Get the statistics from the remote end. The remote will have */
+    /* calculated service demand and all those interesting things. If it */
+    /* wasn't supposed to care, it will return obvious values. */
+    
+    recv_response();
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote results obtained\n");
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /* We now calculate what our thruput was for the test. */
+  
+    bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
+    thruput	= nummessages/elapsed_time;
+  
+    if (local_cpu_usage || remote_cpu_usage) {
+      /* We must now do a little math for service demand and cpu */
+      /* utilization for the system(s) */
+      /* Of course, some of the information might be bogus because */
+      /* there was no idle counter in the kernel(s). We need to make */
+      /* a note of this for the user's benefit...*/
+      if (local_cpu_usage) {
+	local_cpu_utilization = calc_cpu_util(0.0);
+	/* since calc_service demand is doing ms/Kunit we will */
+	/* multiply the number of transaction by 1024 to get */
+	/* "good" numbers */
+	local_service_demand  = calc_service_demand((double) nummessages*1024,
+						    0.0,
+						    0.0,
+						    0);
+      }
+      else {
+	local_cpu_utilization	= -1.0;
+	local_service_demand	= -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = xti_tcp_rr_result->cpu_util;
+	/* since calc_service demand is doing ms/Kunit we will */
+	/* multiply the number of transaction by 1024 to get */
+	/* "good" numbers */
+	remote_service_demand = calc_service_demand((double) nummessages*1024,
+						    0.0,
+						    remote_cpu_utilization,
+						    xti_tcp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = -1.0;
+	remote_service_demand  = -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= -1.0;
+      local_service_demand	= -1.0;
+      remote_cpu_utilization = -1.0;
+      remote_service_demand  = -1.0;
+    }
+
+    /* at this point, we want to calculate the confidence information. */
+    /* if debugging is on, calculate_confidence will print-out the */
+    /* parameters we pass it */
+    
+    calculate_confidence(confidence_iteration,
+			 elapsed_time,
+			 thruput,
+			 local_cpu_utilization,
+			 remote_cpu_utilization,
+			 local_service_demand,
+			 remote_service_demand);
+    
+    
+    confidence_iteration++;
+
+    /* we are now done with the socket, so close it */
+    t_close(send_socket);
+
+  }
+
+  retrieve_confident_values(&elapsed_time,
+			    &thruput,
+			    &local_cpu_utilization,
+			    &remote_cpu_utilization,
+			    &local_service_demand,
+			    &remote_service_demand);
+
+  /* We are now ready to print all the information. If the user */
+  /* has specified zero-level verbosity, we will just print the */
+  /* local service demand, or the remote service demand. If the */
+  /* user has requested verbosity level 1, he will get the basic */
+  /* "streamperf" numbers. If the user has specified a verbosity */
+  /* of greater than 1, we will display a veritable plethora of */
+  /* background information from outside of this block as it it */
+  /* not cpu_measurement specific...  */
+
+  if (confidence < 0) {
+    /* we did not hit confidence, but were we asked to look for it? */
+    if (iteration_max > 1) {
+      display_confidence();
+    }
+  }
+
+  if (local_cpu_usage || remote_cpu_usage) {
+    local_cpu_method = format_cpu_method(cpu_method);
+    remote_cpu_method = format_cpu_method(xti_tcp_rr_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method);
+      }
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,
+		cpu_title,
+		local_cpu_method,
+		remote_cpu_method);
+      }
+
+      fprintf(where,
+	      cpu_fmt_1_line_1,		/* the format string */
+	      lss_size,		/* local sendbuf size */
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* guess */
+	      elapsed_time,		/* how long was the test */
+	      thruput,
+	      local_cpu_utilization,	/* local cpu */
+	      remote_cpu_utilization,	/* remote cpu */
+	      local_service_demand,	/* local service demand */
+	      remote_service_demand);	/* remote service demand */
+      fprintf(where,
+	      cpu_fmt_1_line_2,
+	      rss_size,
+	      rsr_size);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+
+      fprintf(where,
+	      tput_fmt_1_line_1,	/* the format string */
+	      lss_size,
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* how large were the responses */
+	      elapsed_time, 		/* how long did it take */
+	      thruput);
+      fprintf(where,
+	      tput_fmt_1_line_2,
+	      rss_size, 		/* remote recvbuf size */
+	      rsr_size);
+      
+      break;
+    }
+  }
+  
+  /* it would be a good thing to include information about some of the */
+  /* other parameters that may have been set for this test, but at the */
+  /* moment, I do not wish to figure-out all the  formatting, so I will */
+  /* just put this comment here to help remind me that it is something */
+  /* that should be done at a later time. */
+  
+  /* how to handle the verbose information in the presence of */
+  /* confidence intervals is yet to be determined... raj 11/94 */
+  if (verbosity > 1) {
+    /* The user wanted to know it all, so we will give it to him. */
+    /* This information will include as much as we can find about */
+    /* TCP statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+    fprintf(where,
+	    ksink_fmt,
+	    local_send_align,
+	    remote_recv_offset,
+	    local_send_offset,
+	    remote_recv_offset);
+
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\nHistogram of request/response times\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+
+  }
+  
+}
+
+void
+send_xti_udp_stream(char remote_host[])
+{
+  /**********************************************************************/
+  /*									*/
+  /*               	UDP Unidirectional Send Test                    */
+  /*									*/
+  /**********************************************************************/
+  char *tput_title = "\
+Socket  Message  Elapsed      Messages                \n\
+Size    Size     Time         Okay Errors   Throughput\n\
+bytes   bytes    secs            #      #   %s/sec\n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1 = "\
+%6d  %6d   %-7.2f   %7d %6d    %7.2f\n\
+%6d           %-7.2f   %7d           %7.2f\n\n";
+  
+  
+  char *cpu_title = "\
+Socket  Message  Elapsed      Messages                   CPU      Service\n\
+Size    Size     Time         Okay Errors   Throughput   Util     Demand\n\
+bytes   bytes    secs            #      #   %s/sec %% %c%c     us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.2f %c\n";
+  
+  char *cpu_fmt_1 = "\
+%6d  %6d   %-7.2f   %7d %6d    %7.1f     %-6.2f   %-6.3f\n\
+%6d           %-7.2f   %7d           %7.1f     %-6.2f   %-6.3f\n\n";
+  
+  unsigned int	messages_recvd;
+  unsigned int 	messages_sent;
+  unsigned int	failed_sends;
+
+  float	elapsed_time,  
+        recv_elapsed,
+        local_cpu_utilization,
+        remote_cpu_utilization;
+  
+  float	 local_service_demand, remote_service_demand;
+  double local_thruput, remote_thruput;
+  double bytes_sent;
+  double bytes_recvd;
+  
+  
+  int	len;
+  int	*message_int_ptr;
+  struct ring_elt *send_ring;
+  SOCKET data_socket;
+  
+  unsigned int sum_messages_sent;
+  unsigned int sum_messages_recvd;
+  unsigned int sum_failed_sends;
+  double sum_local_thruput;
+
+#ifdef WANT_INTERVALS
+  int	interval_count;
+  sigset_t signal_set;
+#endif /* WANT_INTERVALS */
+  
+  struct   hostent     *hp;
+  struct   sockaddr_in server;
+  unsigned int         addr;
+  
+  struct t_unitdata unitdata;
+   
+  struct xti_udp_stream_request_struct	*xti_udp_stream_request;
+  struct xti_udp_stream_response_struct	*xti_udp_stream_response;
+  struct xti_udp_stream_results_struct	*xti_udp_stream_results;
+  
+  xti_udp_stream_request  = 
+    (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
+  xti_udp_stream_response = 
+    (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
+  xti_udp_stream_results  = 
+    (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  time_hist = HIST_new();
+#endif /* WANT_HISTOGRAM */
+
+  /* since we are now disconnected from the code that established the */
+  /* control socket, and since we want to be able to use different */
+  /* protocols and such, we are passed the name of the remote host and */
+  /* must turn that into the test specific addressing information. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  
+  /* it would seem that while HP-UX will allow an IP address (as a */
+  /* string) in a call to gethostbyname, other, less enlightened */
+  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
+  /* order changed to check for IP address first. raj 7/96 */
+
+  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
+    /* it was not an IP address, try it as a name */
+    if ((hp = gethostbyname(remote_host)) == NULL) {
+      /* we have no idea what it is */
+      fprintf(where,
+	      "establish_control: could not resolve the destination %s\n",
+	      remote_host);
+      fflush(where);
+      exit(1);
+    }
+    else {
+      /* it was a valid remote_host */
+      bcopy(hp->h_addr,
+	    (char *)&server.sin_addr,
+	    hp->h_length);
+      server.sin_family = hp->h_addrtype;
+    }
+  }
+  else {
+    /* it was a valid IP address */
+    server.sin_addr.s_addr = addr;
+    server.sin_family = AF_INET;
+  }    
+  
+  if ( print_headers ) {
+    fprintf(where,"UDP UNIDIRECTIONAL SEND TEST");
+    fprintf(where," to %s", remote_host);
+    if (iteration_max > 1) {
+      fprintf(where,
+	      " : +/-%3.1f%% @ %2d%% conf.",
+	      interval/0.02,
+	      confidence_level);
+      }
+    if (loc_sndavoid || 
+	loc_rcvavoid ||
+	rem_sndavoid ||
+	rem_rcvavoid) {
+      fprintf(where," : copy avoidance");
+    }
+#ifdef WANT_HISTOGRAM
+    fprintf(where," : histogram");
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS
+    fprintf(where," : interval");
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY 
+    fprintf(where," : dirty data");
+#endif /* DIRTY */
+    fprintf(where,"\n");
+  }	
+  
+  send_ring            = NULL;
+  confidence_iteration = 1;
+  init_stat();
+  sum_messages_sent    = 0;
+  sum_messages_recvd   = 0;
+  sum_failed_sends     = 0;
+  sum_local_thruput    = 0.0;
+
+  /* we have a great-big while loop which controls the number of times */
+  /* we run a particular test. this is for the calculation of a */
+  /* confidence interval (I really should have stayed awake during */
+  /* probstats :). If the user did not request confidence measurement */
+  /* (no confidence is the default) then we will only go though the */
+  /* loop once. the confidence stuff originates from the folks at IBM */
+
+  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
+	 (confidence_iteration <= iteration_min)) {
+    
+    /* initialize a few counters. we have to remember that we might be */
+    /* going through the loop more than once. */
+    messages_sent  = 0;
+    messages_recvd = 0;
+    failed_sends   = 0;
+    times_up       = 0;
+    
+    /*set up the data socket			*/
+    data_socket = create_xti_endpoint(loc_xti_device);
+    
+    if (data_socket == INVALID_SOCKET) {
+      perror("send_xti_udp_stream: create_xti_endpoint");
+      exit(1);
+    }
+
+    if (t_bind(data_socket, NULL, NULL) == SOCKET_ERROR) {
+      t_error("send_xti_udp_stream: t_bind");
+      exit(1);
+    }
+
+    /* now, we want to see if we need to set the send_size */
+    if (send_size == 0) {
+      if (lss_size > 0) {
+	send_size = lss_size;
+      }
+      else {
+	send_size = 4096;
+      }
+    }
+    
+    /* set-up the data buffer with the requested alignment and offset, */
+    /* most of the numbers here are just a hack to pick something nice */
+    /* and big in an attempt to never try to send a buffer a second time */
+    /* before it leaves the node...unless the user set the width */
+    /* explicitly. */
+    if (send_width == 0) send_width = 32;
+    
+    if (send_ring == NULL ) {
+      send_ring = allocate_buffer_ring(send_width,
+				       send_size,
+				       local_send_align,
+				       local_send_offset);
+    }
+    
+    
+    /* if the user supplied a cpu rate, this call will complete rather */
+    /* quickly, otherwise, the cpu rate will be retured to us for */
+    /* possible display. The Library will keep it's own copy of this data */
+    /* for use elsewhere. We will only display it. (Does that make it */
+    /* "opaque" to us?) */
+    
+    if (local_cpu_usage)
+      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+    
+    /* Tell the remote end to set up the data connection. The server */
+    /* sends back the port number and alters the socket parameters there. */
+    /* Of course this is a datagram service so no connection is actually */
+    /* set up, the server just sets up the socket and binds it. */
+    
+    netperf_request.content.request_type      = DO_XTI_UDP_STREAM;
+    xti_udp_stream_request->recv_buf_size  = rsr_size;
+    xti_udp_stream_request->message_size   = send_size;
+    xti_udp_stream_request->recv_alignment = remote_recv_align;
+    xti_udp_stream_request->recv_offset    = remote_recv_offset;
+    xti_udp_stream_request->measure_cpu    = remote_cpu_usage;
+    xti_udp_stream_request->cpu_rate       = remote_cpu_rate;
+    xti_udp_stream_request->test_length    = test_time;
+    xti_udp_stream_request->so_rcvavoid    = rem_rcvavoid;
+    xti_udp_stream_request->so_sndavoid    = rem_sndavoid;
+    
+    strcpy(xti_udp_stream_request->xti_device, rem_xti_device);
+  
+#ifdef __alpha
+  
+    /* ok - even on a DEC box, strings are strings. I didn't really want */
+    /* to ntohl the words of a string. since I don't want to teach the */
+    /* send_ and recv_ _request and _response routines about the types, */
+    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+    /* solution would be to use XDR, but I am still leary of being able */
+    /* to find XDR libs on all platforms I want running netperf. raj */
+    {
+      int *charword;
+      int *initword;
+      int *lastword;
+      
+      initword = (int *) xti_udp_stream_request->xti_device;
+      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
+      
+      for (charword = initword;
+	   charword < lastword;
+	   charword++) {
+	
+	*charword = ntohl(*charword);
+      }
+    }
+#endif /* __alpha */
+
+    send_request();
+    
+    recv_response();
+    
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"send_xti_udp_stream: remote data connection done.\n");
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("send_xti_udp_stream: error on remote");
+      exit(1);
+    }
+    
+    /* Place the port number returned by the remote into the sockaddr */
+    /* structure so our sends can be sent to the correct place. Also get */
+    /* some of the returned socket buffer information for user display. */
+    
+    /* make sure that port numbers are in the proper order */
+    server.sin_port = (short)xti_udp_stream_response->data_port_number;
+    server.sin_port = htons(server.sin_port);
+    rsr_size        = xti_udp_stream_response->recv_buf_size;
+    rss_size        = xti_udp_stream_response->send_buf_size;
+    remote_cpu_rate = xti_udp_stream_response->cpu_rate;
+    
+    /* it would seem that XTI does not allow the expedient of */
+    /* "connecting" a UDP end-point the way BSD does. so, we will do */
+    /* everything with t_sndudata and t_rcvudata. Our "virtual" */
+    /* connect here will be to assign the destination portion of the */
+    /* t_unitdata struct here, where we would have otherwise called */
+    /* t_connect() raj 3/95 */
+    
+    memset (&unitdata, 0, sizeof(unitdata));
+    unitdata.addr.maxlen = sizeof(struct sockaddr_in);
+    unitdata.addr.len    = sizeof(struct sockaddr_in);
+    unitdata.addr.buf    = (char *)&server;
+
+    /* we don't use any options, so might as well set that part here */
+    /* too */
+
+    unitdata.opt.maxlen = 0;
+    unitdata.opt.len    = 0;
+    unitdata.opt.buf    = NULL;
+
+    /* we need to initialize the send buffer for the first time as */
+    /* well since we move to the next pointer after the send call. */
+
+    unitdata.udata.maxlen = send_size;
+    unitdata.udata.len    = send_size;
+    unitdata.udata.buf    = send_ring->buffer_ptr;
+
+    /* set up the timer to call us after test_time. one of these days, */
+    /* it might be nice to figure-out a nice reliable way to have the */
+    /* test controlled by a byte count as well, but since UDP is not */
+    /* reliable, that could prove difficult. so, in the meantime, we */
+    /* only allow a XTI_UDP_STREAM test to be a timed test. */
+    
+    if (test_time) {
+      times_up = 0;
+      start_timer(test_time);
+    }
+    else {
+      fprintf(where,"Sorry, XTI_UDP_STREAM tests must be timed.\n");
+      fflush(where);
+      exit(1);
+    }
+    
+    /* Get the start count for the idle counter and the start time */
+    
+    cpu_start(local_cpu_usage);
+    
+#ifdef WANT_INTERVALS
+    if ((interval_burst) || (demo_mode)) {
+      /* zero means that we never pause, so we never should need the */
+      /* interval timer, unless we are in demo_mode */
+      start_itimer(interval_wate);
+    }
+    interval_count = interval_burst;
+    /* get the signal set for the call to sigsuspend */
+    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
+      fprintf(where,
+	      "send_xti_udp_stream: unable to get sigmask errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+    
+    /* Send datagrams like there was no tomorrow. at somepoint it might */
+    /* be nice to set this up so that a quantity of bytes could be sent, */
+    /* but we still need some sort of end of test trigger on the receive */
+    /* side. that could be a select with a one second timeout, but then */
+    /* if there is a test where none of the data arrives for awile and */
+    /* then starts again, we would end the test too soon. something to */
+    /* think about... */
+    while (!times_up) {
+      
+#ifdef DIRTY
+      /* we want to dirty some number of consecutive integers in the buffer */
+      /* we are about to send. we may also want to bring some number of */
+      /* them cleanly into the cache. The clean ones will follow any dirty */
+      /* ones into the cache. */
+
+      access_buffer(send_ring->buffer_ptr,
+		    send_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+
+#endif /* DIRTY */
+      
+#ifdef WANT_HISTOGRAM
+      HIST_timestamp(&time_one);
+#endif /* WANT_HISTOGRAM */
+      
+      if ((t_sndudata(data_socket,
+		      &unitdata))  != 0) {
+	if (errno == EINTR)
+	  break;
+	if (errno == ENOBUFS) {
+	  failed_sends++;
+	  continue;
+	}
+	perror("xti_udp_send: data send error");
+	t_error("xti_udp_send: data send error");
+	exit(1);
+      }
+      messages_sent++;          
+      
+      /* now we want to move our pointer to the next position in the */
+      /* data buffer...and update the unitdata structure */
+      
+      send_ring          = send_ring->next;
+      unitdata.udata.buf = send_ring->buffer_ptr;
+      
+#ifdef WANT_HISTOGRAM
+      /* get the second timestamp */
+      HIST_timestamp(&time_two);
+      HIST_add(time_hist,delta_micro(&time_one,&time_two));
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS      
+      if (demo_mode) {
+	units_this_tick += send_size;
+      }
+      /* in this case, the interval count is the count-down couter */
+      /* to decide to sleep for a little bit */
+      if ((interval_burst) && (--interval_count == 0)) {
+	/* call sigsuspend and wait for the interval timer to get us */
+	/* out */
+	if (debug) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_xti_udp_stream: fault with signal set!\n");
+	  fflush(where);
+	  exit(1);
+	}
+	interval_count = interval_burst;
+      }
+#endif /* WANT_INTERVALS */
+      
+    }
+    
+    /* This is a timed test, so the remote will be returning to us after */
+    /* a time. We should not need to send any "strange" messages to tell */
+    /* the remote that the test is completed, unless we decide to add a */
+    /* number of messages to the test. */
+    
+    /* the test is over, so get stats and stuff */
+    cpu_stop(local_cpu_usage,	
+	     &elapsed_time);
+    
+    /* Get the statistics from the remote end	*/
+    recv_response();
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"send_xti_udp_stream: remote results obtained\n");
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("send_xti_udp_stream: error on remote");
+      exit(1);
+    }
+    
+    bytes_sent    = (double) send_size * (double) messages_sent;
+    local_thruput = calc_thruput(bytes_sent);
+    
+    messages_recvd = xti_udp_stream_results->messages_recvd;
+    bytes_recvd    = (double) send_size * (double) messages_recvd;
+    
+    /* we asume that the remote ran for as long as we did */
+    
+    remote_thruput = calc_thruput(bytes_recvd);
+    
+    /* print the results for this socket and message size */
+    
+    if (local_cpu_usage || remote_cpu_usage) {
+      /* We must now do a little math for service demand and cpu */
+      /* utilization for the system(s) We pass zeros for the local */
+      /* cpu utilization and elapsed time to tell the routine to use */
+      /* the libraries own values for those. */
+      if (local_cpu_usage) {
+	local_cpu_utilization	= calc_cpu_util(0.0);
+	/* shouldn't this really be based on bytes_recvd, since that is */
+	/* the effective throughput of the test? I think that it should, */
+	/* so will make the change raj 11/94 */
+	local_service_demand	= calc_service_demand(bytes_recvd,
+						      0.0,
+						      0.0,
+						      0);
+      }
+      else {
+	local_cpu_utilization	= -1.0;
+	local_service_demand	= -1.0;
+      }
+      
+      /* The local calculations could use variables being kept by */
+      /* the local netlib routines. The remote calcuations need to */
+      /* have a few things passed to them. */
+      if (remote_cpu_usage) {
+	remote_cpu_utilization	= xti_udp_stream_results->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_recvd,
+						      0.0,
+						      remote_cpu_utilization,
+						      xti_udp_stream_results->num_cpus);
+      }
+      else {
+	remote_cpu_utilization	= -1.0;
+	remote_service_demand	= -1.0;
+      }
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization  = -1.0;
+      local_service_demand   = -1.0;
+      remote_cpu_utilization = -1.0;
+      remote_service_demand  = -1.0;
+    }
+    
+    /* at this point, we want to calculate the confidence information. */
+    /* if debugging is on, calculate_confidence will print-out the */
+    /* parameters we pass it */
+    
+    calculate_confidence(confidence_iteration,
+			 elapsed_time,
+			 remote_thruput,
+			 local_cpu_utilization,
+			 remote_cpu_utilization,
+			 local_service_demand,
+			 remote_service_demand);
+    
+    /* since the routine calculate_confidence is rather generic, and */
+    /* we have a few other parms of interest, we will do a little work */
+    /* here to caclulate their average. */
+    sum_messages_sent  += messages_sent;
+    sum_messages_recvd += messages_recvd;
+    sum_failed_sends   += failed_sends;
+    sum_local_thruput  += local_thruput;
+    
+    confidence_iteration++;
+
+    /* this datapoint is done, so we don't need the socket any longer */
+    close(data_socket);
+
+  }
+
+  /* we should reach this point once the test is finished */
+
+  retrieve_confident_values(&elapsed_time,
+			    &remote_thruput,
+			    &local_cpu_utilization,
+			    &remote_cpu_utilization,
+			    &local_service_demand,
+			    &remote_service_demand);
+
+  /* some of the interesting values aren't covered by the generic */
+  /* confidence routine */
+  messages_sent    = sum_messages_sent / (confidence_iteration -1);
+  messages_recvd   = sum_messages_recvd / (confidence_iteration -1);
+  failed_sends     = sum_failed_sends / (confidence_iteration -1);
+  local_thruput    = sum_local_thruput / (confidence_iteration -1);
+
+  /* We are now ready to print all the information. If the user */
+  /* has specified zero-level verbosity, we will just print the */
+  /* local service demand, or the remote service demand. If the */
+  /* user has requested verbosity level 1, he will get the basic */
+  /* "streamperf" numbers. If the user has specified a verbosity */
+  /* of greater than 1, we will display a veritable plethora of */
+  /* background information from outside of this block as it it */
+  /* not cpu_measurement specific...  */
+    
+  
+  if (confidence < 0) {
+    /* we did not hit confidence, but were we asked to look for it? */
+    if (iteration_max > 1) {
+      display_confidence();
+    }
+  }
+
+  if (local_cpu_usage || remote_cpu_usage) {
+    local_cpu_method = format_cpu_method(cpu_method);
+    remote_cpu_method = format_cpu_method(xti_udp_stream_results->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		local_cpu_method);
+      }
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,
+		cpu_title,
+		format_units(),
+		local_cpu_method,
+		remote_cpu_method);
+      }
+
+      fprintf(where,
+	      cpu_fmt_1,		/* the format string */
+	      lss_size,		        /* local sendbuf size */
+	      send_size,		/* how large were the sends */
+	      elapsed_time,		/* how long was the test */
+	      messages_sent,
+	      failed_sends,
+	      local_thruput, 		/* what was the xfer rate */
+	      local_cpu_utilization,	/* local cpu */
+	      local_service_demand,	/* local service demand */
+	      rsr_size,
+	      elapsed_time,
+	      messages_recvd,
+	      remote_thruput,
+	      remote_cpu_utilization,	/* remote cpu */
+	      remote_service_demand);	/* remote service demand */
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      local_thruput);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      lss_size, 		/* local sendbuf size */
+	      send_size,		/* how large were the sends */
+	      elapsed_time, 		/* how long did it take */
+	      messages_sent,
+	      failed_sends,
+	      local_thruput,
+	      rsr_size, 		/* remote recvbuf size */
+	      elapsed_time,
+	      messages_recvd,
+	      remote_thruput);
+      break;
+    }
+  }
+
+  fflush(where);
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    fprintf(where,"\nHistogram of time spent in send() call\n");
+    fflush(where);
+    HIST_report(time_hist);
+  }
+#endif /* WANT_HISTOGRAM */
+
+}
+
+
+ /* this routine implements the receive side (netserver) of the */
+ /* XTI_UDP_STREAM performance test. */
+
+void
+recv_xti_udp_stream()
+{
+  struct ring_elt *recv_ring;
+
+  struct t_bind bind_req, bind_resp;
+  struct t_unitdata unitdata;
+  int	            flags = 0;
+
+  struct sockaddr_in myaddr_in;
+  struct sockaddr_in fromaddr_in;
+
+  SOCKET s_data;
+  int 	addrlen;
+  unsigned int	bytes_received = 0;
+  float	elapsed_time;
+  
+  unsigned int	message_size;
+  unsigned int	messages_recvd = 0;
+  
+  struct xti_udp_stream_request_struct	*xti_udp_stream_request;
+  struct xti_udp_stream_response_struct	*xti_udp_stream_response;
+  struct xti_udp_stream_results_struct	*xti_udp_stream_results;
+  
+  xti_udp_stream_request  = 
+    (struct xti_udp_stream_request_struct *)netperf_request.content.test_specific_data;
+  xti_udp_stream_response = 
+    (struct xti_udp_stream_response_struct *)netperf_response.content.test_specific_data;
+  xti_udp_stream_results  = 
+    (struct xti_udp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_xti_udp_stream: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen socket with all the desired */
+  /* parameters and then let the initiator know that all is ready. If */
+  /* socket size defaults are to be used, then the initiator will have */
+  /* sent us 0's. If the socket sizes cannot be changed, then we will */
+  /* send-back what they are. If that information cannot be determined, */
+  /* then we send-back -1's for the sizes. If things go wrong for any */
+  /* reason, we will drop back ten yards and punt. */
+  
+  /* If anything goes wrong, we want the remote to know about it. It */
+  /* would be best if the error that the remote reports to the user is */
+  /* the actual error we encountered, rather than some bogus unexpected */
+  /* response type message. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_xti_udp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = XTI_UDP_STREAM_RESPONSE;
+  
+  if (debug > 2) {
+    fprintf(where,"recv_xti_udp_stream: the response type is set...\n");
+    fflush(where);
+  }
+  
+  /* We now alter the message_ptr variable to be at the desired */
+  /* alignment with the desired offset. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_xti_udp_stream: requested alignment of %d\n",
+	    xti_udp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  if (recv_width == 0) recv_width = 1;
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   xti_udp_stream_request->message_size,
+				   xti_udp_stream_request->recv_alignment,
+				   xti_udp_stream_request->recv_offset);
+
+  if (debug > 1) {
+    fprintf(where,"recv_xti_udp_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
+  /* can put in OUR values !-) At some point, we may want to nail this */
+  /* socket to a particular network-level address, but for now, */
+  /* INADDR_ANY should be just fine. */
+  
+  bzero((char *)&myaddr_in,
+	sizeof(myaddr_in));
+  myaddr_in.sin_family      = AF_INET;
+  myaddr_in.sin_addr.s_addr = INADDR_ANY;
+  myaddr_in.sin_port        = 0;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_xti_udp_stream: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_xti_endpoint expects to find some things in the global */
+  /* variables, so set the globals based on the values in the request. */
+  /* once the socket has been created, we will set the response values */
+  /* based on the updated value of those globals. raj 7/94 */
+  lsr_size = xti_udp_stream_request->recv_buf_size;
+  loc_rcvavoid = xti_udp_stream_request->so_rcvavoid;
+  loc_sndavoid = xti_udp_stream_request->so_sndavoid;
+
+#ifdef __alpha
+  
+  /* ok - even on a DEC box, strings are strings. I din't really want */
+  /* to ntohl the words of a string. since I don't want to teach the */
+  /* send_ and recv_ _request and _response routines about the types, */
+  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+  /* solution would be to use XDR, but I am still leary of being able */
+  /* to find XDR libs on all platforms I want running netperf. raj */
+  {
+    int *charword;
+    int *initword;
+    int *lastword;
+    
+    initword = (int *) xti_udp_stream_request->xti_device;
+    lastword = initword + ((xti_udp_stream_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+  
+#endif /* __alpha */
+    
+  s_data = create_xti_endpoint(xti_udp_stream_request->xti_device);
+  
+  if (s_data == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* Let's get an address assigned to this socket so we can tell the */
+  /* initiator how to reach the data socket. There may be a desire to */
+  /* nail this socket to a specific IP address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+
+  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_req.addr.len    = sizeof(struct sockaddr_in);
+  bind_req.addr.buf    = (char *)&myaddr_in;
+  bind_req.qlen        = 1;
+
+  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_resp.addr.len    = sizeof(struct sockaddr_in);
+  bind_resp.addr.buf    = (char *)&myaddr_in;
+  bind_resp.qlen        = 1;
+
+  if (t_bind(s_data,
+	     &bind_req,
+	     &bind_resp) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = t_errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  xti_udp_stream_response->test_length = 
+    xti_udp_stream_request->test_length;
+  
+  /* Now myaddr_in contains the port and the internet address this is */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  
+  xti_udp_stream_response->data_port_number = 
+    (int) ntohs(myaddr_in.sin_port);
+  netperf_response.content.serv_errno   = 0;
+  
+  /* But wait, there's more. If the initiator wanted cpu measurements, */
+  /* then we must call the calibrate routine, which will return the max */
+  /* rate back to the initiator. If the CPU was not to be measured, or */
+  /* something went wrong with the calibration, we will return a -1 to */
+  /* the initiator. */
+  
+  xti_udp_stream_response->cpu_rate    = 0.0; /* assume no cpu */
+  xti_udp_stream_response->measure_cpu = 0;
+  if (xti_udp_stream_request->measure_cpu) {
+    /* We will pass the rate into the calibration routine. If the */
+    /* user did not specify one, it will be 0.0, and we will do a */
+    /* "real" calibration. Otherwise, all it will really do is */
+    /* store it away... */
+    xti_udp_stream_response->measure_cpu = 1;
+    xti_udp_stream_response->cpu_rate = 
+      calibrate_local_cpu(xti_udp_stream_request->cpu_rate);
+  }
+  
+  message_size	= xti_udp_stream_request->message_size;
+  test_time	= xti_udp_stream_request->test_length;
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  xti_udp_stream_response->send_buf_size = lss_size;
+  xti_udp_stream_response->recv_buf_size = lsr_size;
+  xti_udp_stream_response->so_rcvavoid = loc_rcvavoid;
+  xti_udp_stream_response->so_sndavoid = loc_sndavoid;
+
+  /* since we are going to call t_rcvudata() instead of t_rcv() we */
+  /* need to init the unitdata structure raj 3/95 */
+
+  unitdata.addr.maxlen = sizeof(fromaddr_in);
+  unitdata.addr.len    = sizeof(fromaddr_in);
+  unitdata.addr.buf    = (char *)&fromaddr_in;
+
+  unitdata.opt.maxlen = 0;
+  unitdata.opt.len    = 0;
+  unitdata.opt.buf    = NULL;
+
+  unitdata.udata.maxlen = xti_udp_stream_request->message_size;
+  unitdata.udata.len    = xti_udp_stream_request->message_size;
+  unitdata.udata.buf    = recv_ring->buffer_ptr;
+
+  send_response();
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(xti_udp_stream_request->measure_cpu);
+  
+  /* The loop will exit when the timer pops, or if we happen to recv a */
+  /* message of less than send_size bytes... */
+  
+  times_up = 0;
+  start_timer(test_time + PAD_TIME);
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_stream: about to enter inner sanctum.\n");
+    fflush(where);
+  }
+  
+  while (!times_up) {
+#ifdef RAJ_DEBUG
+    if (debug) {
+      fprintf(where,"t_rcvudata, errno %d, t_errno %d",
+	      errno,
+	      t_errno);
+      fprintf(where," after %d messages\n",messages_recvd);
+      fprintf(where,"addrmax %d addrlen %d addrbuf %x\n",
+	      unitdata.addr.maxlen,
+	      unitdata.addr.len,
+	      unitdata.addr.buf);
+      fprintf(where,"optmax %d optlen %d optbuf %x\n",
+	      unitdata.opt.maxlen,
+	      unitdata.opt.len,
+	      unitdata.opt.buf);
+      fprintf(where,"udatamax %d udatalen %d udatabuf %x\n",
+	      unitdata.udata.maxlen,
+	      unitdata.udata.len,
+	      unitdata.udata.buf);
+      fflush(where);
+    }
+#endif /* RAJ_DEBUG */
+    if (t_rcvudata(s_data, 
+		   &unitdata,
+		   &flags) != 0) {
+      if (errno == TNODATA) {
+	continue;
+      }
+      if (errno != EINTR) {
+	netperf_response.content.serv_errno = t_errno;
+	send_response();
+	exit(1);
+      }
+      break;
+    }
+    messages_recvd++;
+    recv_ring = recv_ring->next;
+    unitdata.udata.buf = recv_ring->buffer_ptr;
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_stream: got %d messages.\n",messages_recvd);
+    fflush(where);
+  }
+  
+  
+  /* The loop now exits due timer or < send_size bytes received. */
+  
+  cpu_stop(xti_udp_stream_request->measure_cpu,&elapsed_time);
+  
+  if (times_up) {
+    /* we ended on a timer, subtract the PAD_TIME */
+    elapsed_time -= (float)PAD_TIME;
+  }
+  else {
+    stop_timer();
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_stream: test ended in %f seconds.\n",elapsed_time);
+    fflush(where);
+  }
+  
+  bytes_received = (messages_recvd * message_size);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_udp_stream: got %d bytes\n",
+	    bytes_received);
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type	= XTI_UDP_STREAM_RESULTS;
+  xti_udp_stream_results->bytes_received	= bytes_received;
+  xti_udp_stream_results->messages_recvd	= messages_recvd;
+  xti_udp_stream_results->elapsed_time	= elapsed_time;
+  xti_udp_stream_results->cpu_method        = cpu_method;
+  if (xti_udp_stream_request->measure_cpu) {
+    xti_udp_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  else {
+    xti_udp_stream_results->cpu_util	= -1.0;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_xti_udp_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+void send_xti_udp_rr(char remote_host[])
+{
+  
+  char *tput_title = "\
+Local /Remote\n\
+Socket Size   Request  Resp.   Elapsed  Trans.\n\
+Send   Recv   Size     Size    Time     Rate         \n\
+bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
+  char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *cpu_title = "\
+Local /Remote\n\
+Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
+Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
+bytes  bytes  bytes   bytes  secs.   per sec  %% %c    %% %c    us/Tr   us/Tr\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f %c\n";
+  
+  char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
+  
+  char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *ksink_fmt = "\
+Alignment      Offset\n\
+Local  Remote  Local  Remote\n\
+Send   Recv    Send   Recv\n\
+%5d  %5d   %5d  %5d\n";
+  
+  
+  float			elapsed_time;
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct t_bind bind_req, bind_resp;
+  struct t_unitdata unitdata;
+  struct t_unitdata send_unitdata;
+  struct t_unitdata recv_unitdata;
+  int	            flags = 0;
+
+  int	len;
+  int	nummessages;
+  SOCKET send_socket;
+  int	trans_remaining;
+  int	bytes_xferd;
+  
+  int	rsp_bytes_recvd;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double thruput;
+  
+  struct	hostent	        *hp;
+  struct	sockaddr_in	server, myaddr_in;
+  unsigned      int             addr;
+  int	                        addrlen;
+  
+  struct	xti_udp_rr_request_struct	*xti_udp_rr_request;
+  struct	xti_udp_rr_response_struct	*xti_udp_rr_response;
+  struct	xti_udp_rr_results_struct	*xti_udp_rr_result;
+
+#ifdef WANT_INTERVALS
+  int	interval_count;
+  sigset_t signal_set;
+#endif /* WANT_INTERVALS */
+  
+  xti_udp_rr_request  =
+    (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_udp_rr_response =
+    (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_udp_rr_result	 =
+    (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  time_hist = HIST_new();
+#endif
+  
+  /* since we are now disconnected from the code that established the */
+  /* control socket, and since we want to be able to use different */
+  /* protocols and such, we are passed the name of the remote host and */
+  /* must turn that into the test specific addressing information. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  
+  /* it would seem that while HP-UX will allow an IP address (as a */
+  /* string) in a call to gethostbyname, other, less enlightened */
+  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
+  /* order changed to check for IP address first. raj 7/96 */
+
+  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
+    /* it was not an IP address, try it as a name */
+    if ((hp = gethostbyname(remote_host)) == NULL) {
+      /* we have no idea what it is */
+      fprintf(where,
+	      "establish_control: could not resolve the destination %s\n",
+	      remote_host);
+      fflush(where);
+      exit(1);
+    }
+    else {
+      /* it was a valid remote_host */
+      bcopy(hp->h_addr,
+	    (char *)&server.sin_addr,
+	    hp->h_length);
+      server.sin_family = hp->h_addrtype;
+    }
+  }
+  else {
+    /* it was a valid IP address */
+    server.sin_addr.s_addr = addr;
+    server.sin_family = AF_INET;
+  }    
+  
+  if ( print_headers ) {
+    fprintf(where,"XTI UDP REQUEST/RESPONSE TEST");
+        fprintf(where," to %s", remote_host);
+    if (iteration_max > 1) {
+      fprintf(where,
+	      " : +/-%3.1f%% @ %2d%% conf.",
+	      interval/0.02,
+	      confidence_level);
+      }
+    if (loc_sndavoid || 
+	loc_rcvavoid ||
+	rem_sndavoid ||
+	rem_rcvavoid) {
+      fprintf(where," : copy avoidance");
+    }
+#ifdef WANT_HISTOGRAM
+    fprintf(where," : histogram");
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS
+    fprintf(where," : interval");
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY 
+    fprintf(where," : dirty data");
+#endif /* DIRTY */
+    fprintf(where,"\n");
+  }
+  
+  /* initialize a few counters */
+  
+  send_ring     = NULL;
+  recv_ring     = NULL;
+  nummessages	= 0;
+  bytes_xferd	= 0;
+  times_up 	= 0;
+  confidence_iteration = 1;
+  init_stat();
+
+
+  /* we have a great-big while loop which controls the number of times */
+  /* we run a particular test. this is for the calculation of a */
+  /* confidence interval (I really should have stayed awake during */
+  /* probstats :). If the user did not request confidence measurement */
+  /* (no confidence is the default) then we will only go though the */
+  /* loop once. the confidence stuff originates from the folks at IBM */
+
+  while (((confidence < 0) && (confidence_iteration < iteration_max)) ||
+	 (confidence_iteration <= iteration_min)) {
+    
+    nummessages     = 0;
+    bytes_xferd     = 0.0;
+    times_up        = 0;
+    trans_remaining = 0;
+    
+    /* set-up the data buffers with the requested alignment and offset */
+    
+    if (send_width == 0) send_width = 1;
+    if (recv_width == 0) recv_width = 1;
+    
+    if (send_ring == NULL) {
+      send_ring = allocate_buffer_ring(send_width,
+				       req_size,
+				       local_send_align,
+				       local_send_offset);
+    }
+    
+    if (recv_ring == NULL) {
+      recv_ring = allocate_buffer_ring(recv_width,
+				       rsp_size,
+				       local_recv_align,
+				       local_recv_offset);
+    }
+    
+  /* since we are going to call t_rcvudata() instead of t_rcv() we */
+  /* need to init the unitdata structure raj 8/95 */
+
+    memset (&recv_unitdata, 0, sizeof(recv_unitdata));
+    recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
+    recv_unitdata.addr.len    = sizeof(struct sockaddr_in);
+    recv_unitdata.addr.buf    = (char *)&server;
+    
+    recv_unitdata.opt.maxlen = 0;
+    recv_unitdata.opt.len    = 0;
+    recv_unitdata.opt.buf    = NULL;
+    
+    recv_unitdata.udata.maxlen = rsp_size;
+    recv_unitdata.udata.len    = rsp_size;
+    recv_unitdata.udata.buf    = recv_ring->buffer_ptr;
+    
+    /* since we are going to call t_sndudata() instead of t_snd() we */
+    /* need to init the unitdata structure raj 8/95 */
+    
+    memset (&send_unitdata, 0, sizeof(send_unitdata));
+    send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
+    send_unitdata.addr.len    = sizeof(struct sockaddr_in);
+    send_unitdata.addr.buf    = (char *)&server;
+    
+    send_unitdata.opt.maxlen = 0;
+    send_unitdata.opt.len    = 0;
+    send_unitdata.opt.buf    = NULL;
+    
+    send_unitdata.udata.maxlen = req_size;
+    send_unitdata.udata.len    = req_size;
+    send_unitdata.udata.buf    = send_ring->buffer_ptr;
+
+    /*set up the data socket                        */
+    send_socket = create_xti_endpoint(loc_xti_device);
+    
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_xti_udp_rr: udp rr data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_xti_udp_rr: send_socket obtained...\n");
+    }
+    
+    /* it would seem that with XTI, there is no implicit bind  */
+    /* so we have to make a call to t_bind. this is not */
+    /* terribly convenient, but I suppose that "standard is better */
+    /* than better" :) raj 2/95 */
+
+    if (t_bind(send_socket, NULL, NULL) == SOCKET_ERROR) {
+      t_error("send_xti_tcp_stream: t_bind");
+      exit(1);
+    }
+
+    /* If the user has requested cpu utilization measurements, we must */
+    /* calibrate the cpu(s). We will perform this task within the tests */
+    /* themselves. If the user has specified the cpu rate, then */
+    /* calibrate_local_cpu will return rather quickly as it will have */
+    /* nothing to do. If local_cpu_rate is zero, then we will go through */
+    /* all the "normal" calibration stuff and return the rate back. If */
+    /* there is no idle counter in the kernel idle loop, the */
+    /* local_cpu_rate will be set to -1. */
+    
+    if (local_cpu_usage) {
+      local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+    }
+    
+    /* Tell the remote end to do a listen. The server alters the socket */
+    /* paramters on the other side at this point, hence the reason for */
+    /* all the values being passed in the setup message. If the user did */
+    /* not specify any of the parameters, they will be passed as 0, which */
+    /* will indicate to the remote that no changes beyond the system's */
+    /* default should be used. Alignment is the exception, it will */
+    /* default to 8, which will be no alignment alterations. */
+    
+    netperf_request.content.request_type	= DO_XTI_UDP_RR;
+    xti_udp_rr_request->recv_buf_size	= rsr_size;
+    xti_udp_rr_request->send_buf_size	= rss_size;
+    xti_udp_rr_request->recv_alignment  = remote_recv_align;
+    xti_udp_rr_request->recv_offset	= remote_recv_offset;
+    xti_udp_rr_request->send_alignment  = remote_send_align;
+    xti_udp_rr_request->send_offset	= remote_send_offset;
+    xti_udp_rr_request->request_size	= req_size;
+    xti_udp_rr_request->response_size	= rsp_size;
+    xti_udp_rr_request->measure_cpu	= remote_cpu_usage;
+    xti_udp_rr_request->cpu_rate	= remote_cpu_rate;
+    xti_udp_rr_request->so_rcvavoid	= rem_rcvavoid;
+    xti_udp_rr_request->so_sndavoid	= rem_sndavoid;
+    if (test_time) {
+      xti_udp_rr_request->test_length	= test_time;
+    }
+    else {
+      xti_udp_rr_request->test_length	= test_trans * -1;
+    }
+    
+    strcpy(xti_udp_rr_request->xti_device, rem_xti_device);
+  
+#ifdef __alpha
+  
+    /* ok - even on a DEC box, strings are strings. I didn't really want */
+    /* to ntohl the words of a string. since I don't want to teach the */
+    /* send_ and recv_ _request and _response routines about the types, */
+    /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+    /* solution would be to use XDR, but I am still leary of being able */
+    /* to find XDR libs on all platforms I want running netperf. raj */
+    {
+      int *charword;
+      int *initword;
+      int *lastword;
+      
+      initword = (int *) xti_udp_rr_request->xti_device;
+      lastword = initword + ((strlen(rem_xti_device) + 3) / 4);
+      
+      for (charword = initword;
+	   charword < lastword;
+	   charword++) {
+	
+	*charword = ntohl(*charword);
+      }
+    }
+#endif /* __alpha */
+
+    if (debug > 1) {
+      fprintf(where,"netperf: send_xti_udp_rr: requesting UDP r/r test\n");
+    }
+    
+    send_request();
+    
+    /* The response from the remote will contain all of the relevant 	*/
+    /* socket parameters for this test type. We will put them back into */
+    /* the variables here so they can be displayed if desired.  The	*/
+    /* remote will have calibrated CPU if necessary, and will have done	*/
+    /* all the needed set-up we will have calibrated the cpu locally	*/
+    /* before sending the request, and will grab the counter value right*/
+    /* after the connect returns. The remote will grab the counter right*/
+    /* after the accept call. This saves the hassle of extra messages	*/
+    /* being sent for the UDP tests.					*/
+    
+    recv_response();
+    
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote listen done.\n");
+      rsr_size	       =	xti_udp_rr_response->recv_buf_size;
+      rss_size	       =	xti_udp_rr_response->send_buf_size;
+      remote_cpu_usage =	xti_udp_rr_response->measure_cpu;
+      remote_cpu_rate  = 	xti_udp_rr_response->cpu_rate;
+      /* port numbers in proper order */
+      server.sin_port  =	(short)xti_udp_rr_response->data_port_number;
+      server.sin_port  = 	htons(server.sin_port);
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /* Data Socket set-up is finished. If there were problems, either the */
+    /* connect would have failed, or the previous response would have */
+    /* indicated a problem. I failed to see the value of the extra */
+    /* message after the accept on the remote. If it failed, we'll see it */
+    /* here. If it didn't, we might as well start pumping data. */
+    
+    /* Set-up the test end conditions. For a request/response test, they */
+    /* can be either time or transaction based. */
+    
+    if (test_time) {
+      /* The user wanted to end the test after a period of time. */
+      times_up = 0;
+      trans_remaining = 0;
+      start_timer(test_time);
+    }
+    else {
+      /* The tester wanted to send a number of bytes. */
+      trans_remaining = test_bytes;
+      times_up = 1;
+    }
+    
+    /* The cpu_start routine will grab the current time and possibly */
+    /* value of the idle counter for later use in measuring cpu */
+    /* utilization and/or service demand and thruput. */
+    
+    cpu_start(local_cpu_usage);
+
+#ifdef WANT_INTERVALS
+    if ((interval_burst) || (demo_mode)) {
+      /* zero means that we never pause, so we never should need the */
+      /* interval timer, unless we are in demo_mode */
+      start_itimer(interval_wate);
+    }
+    interval_count = interval_burst;
+    /* get the signal set for the call to sigsuspend */
+    if (sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &signal_set) != 0) {
+      fprintf(where,
+	      "send_xti_udp_rr: unable to get sigmask errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+    
+    /* We use an "OR" to control test execution. When the test is */
+    /* controlled by time, the byte count check will always return */
+    /* false. When the test is controlled by byte count, the time test */
+    /* will always return false. When the test is finished, the whole */
+    /* expression will go false and we will stop sending data. I think */
+    /* I just arbitrarily decrement trans_remaining for the timed */
+    /* test, but will not do that just yet... One other question is */
+    /* whether or not the send buffer and the receive buffer should be */
+    /* the same buffer. */
+
+    while ((!times_up) || (trans_remaining > 0)) {
+      /* send the request */
+#ifdef WANT_HISTOGRAM
+      HIST_timestamp(&time_one);
+#endif
+      if((t_sndudata(send_socket,
+		     &send_unitdata)) != 0) {
+	if (errno == EINTR) {
+	  /* We likely hit */
+	  /* test-end time. */
+	  break;
+	}
+        fprintf(where,
+		"send_xti_udp_rr: t_sndudata: errno %d t_errno %d t_look 0x%.4x\n",
+		errno,
+		t_errno,
+		t_look(send_socket));
+	fflush(where);
+	exit(1);
+      }
+      send_ring = send_ring->next;
+      
+      /* receive the response. with UDP we will get it all, or nothing */
+      
+      if((t_rcvudata(send_socket,
+		     &recv_unitdata,
+		     &flags)) != 0) {
+	if (errno == TNODATA) {
+	  continue;
+	}
+	if (errno == EINTR) {
+	  /* Again, we have likely hit test-end time */
+	  break;
+	}
+	fprintf(where,
+		"send_xti_udp_rr: t_rcvudata: errno %d t_errno %d t_look 0x%x\n",
+		errno,
+		t_errno,
+		t_look(send_socket));
+	fprintf(where,
+		"recv_unitdata.udata.buf %x\n",recv_unitdata.udata.buf);
+	fprintf(where,
+		"recv_unitdata.udata.maxlen %x\n",recv_unitdata.udata.maxlen);
+	fprintf(where,
+		"recv_unitdata.udata.len %x\n",recv_unitdata.udata.len);
+	fprintf(where,
+		"recv_unitdata.addr.buf %x\n",recv_unitdata.addr.buf);
+	fprintf(where,
+		"recv_unitdata.addr.maxlen %x\n",recv_unitdata.addr.maxlen);
+	fprintf(where,
+		"recv_unitdata.addr.len %x\n",recv_unitdata.addr.len);
+	fflush(where);
+	exit(1);
+      }
+      recv_ring = recv_ring->next;
+      
+#ifdef WANT_HISTOGRAM
+      HIST_timestamp(&time_two);
+      HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      
+      /* at this point, we may wish to sleep for some period of */
+      /* time, so we see how long that last transaction just took, */
+      /* and sleep for the difference of that and the interval. We */
+      /* will not sleep if the time would be less than a */
+      /* millisecond.  */
+#endif
+#ifdef WANT_INTERVALS      
+      if (demo_mode) {
+	units_this_tick += 1;
+      }
+      /* in this case, the interval count is the count-down couter */
+      /* to decide to sleep for a little bit */
+      if ((interval_burst) && (--interval_count == 0)) {
+	/* call sigsuspend and wait for the interval timer to get us */
+	/* out */
+	if (debug) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_xti_udp_rr: fault with signal set!\n");
+	  fflush(where);
+	  exit(1);
+	}
+	interval_count = interval_burst;
+      }
+#endif /* WANT_INTERVALS */
+      
+      nummessages++;          
+      if (trans_remaining) {
+	trans_remaining--;
+      }
+      
+      if (debug > 3) {
+	if ((nummessages % 100) == 0) {
+	  fprintf(where,"Transaction %d completed\n",nummessages);
+	  fflush(where);
+	}
+      }
+      
+    }
+    
+    /* this call will always give us the elapsed time for the test, and */
+    /* will also store-away the necessaries for cpu utilization */
+    
+    cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being */
+						/* measured? how long */
+						/* did we really run? */
+    
+    /* Get the statistics from the remote end. The remote will have */
+    /* calculated service demand and all those interesting things. If */
+    /* it wasn't supposed to care, it will return obvious values. */
+    
+    recv_response();
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote results obtained\n");
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      perror("netperf: remote error");
+      
+      exit(1);
+    }
+    
+    /* We now calculate what our thruput was for the test. In the */
+    /* future, we may want to include a calculation of the thruput */
+    /* measured by the remote, but it should be the case that for a */
+    /* UDP rr test, that the two numbers should be *very* close... */
+    /* We calculate bytes_sent regardless of the way the test length */
+    /* was controlled.  */
+    
+    bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
+    thruput	= nummessages / elapsed_time;
+    
+    if (local_cpu_usage || remote_cpu_usage) {
+
+      /* We must now do a little math for service demand and cpu */
+      /* utilization for the system(s) Of course, some of the */
+      /* information might be bogus because there was no idle counter */
+      /* in the kernel(s). We need to make a note of this for the */
+      /* user's benefit by placing a code for the metod used in the */
+      /* test banner */
+
+      if (local_cpu_usage) {
+	local_cpu_utilization = calc_cpu_util(0.0);
+	
+	/* since calc_service demand is doing ms/Kunit we will */
+	/* multiply the number of transaction by 1024 to get */
+	/* "good" numbers */
+	
+	local_service_demand  = calc_service_demand((double) nummessages*1024,
+						    0.0,
+						    0.0,
+						    0);
+      }
+      else {
+	local_cpu_utilization	= -1.0;
+	local_service_demand	= -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = xti_udp_rr_result->cpu_util;
+	
+	/* since calc_service demand is doing ms/Kunit we will */
+	/* multiply the number of transaction by 1024 to get */
+	/* "good" numbers */
+	
+	remote_service_demand  = calc_service_demand((double) nummessages*1024,
+						     0.0,
+						     remote_cpu_utilization,
+						     xti_udp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = -1.0;
+	remote_service_demand  = -1.0;
+      }
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= -1.0;
+      local_service_demand	= -1.0;
+      remote_cpu_utilization = -1.0;
+      remote_service_demand  = -1.0;
+    }
+    
+    /* at this point, we want to calculate the confidence information. */
+    /* if debugging is on, calculate_confidence will print-out the */
+    /* parameters we pass it */
+    
+    calculate_confidence(confidence_iteration,
+			 elapsed_time,
+			 thruput,
+			 local_cpu_utilization,
+			 remote_cpu_utilization,
+			 local_service_demand,
+			 remote_service_demand);
+    
+    
+    confidence_iteration++;
+    
+    /* we are done with the socket */
+    t_close(send_socket);
+  }
+
+  /* at this point, we have made all the iterations we are going to */
+  /* make. */
+  retrieve_confident_values(&elapsed_time,
+			    &thruput,
+			    &local_cpu_utilization,
+			    &remote_cpu_utilization,
+			    &local_service_demand,
+			    &remote_service_demand);
+  
+  /* We are now ready to print all the information. If the user */
+  /* has specified zero-level verbosity, we will just print the */
+  /* local service demand, or the remote service demand. If the */
+  /* user has requested verbosity level 1, he will get the basic */
+  /* "streamperf" numbers. If the user has specified a verbosity */
+  /* of greater than 1, we will display a veritable plethora of */
+  /* background information from outside of this block as it it */
+  /* not cpu_measurement specific...  */
+  
+  if (confidence < 0) {
+    /* we did not hit confidence, but were we asked to look for it? */
+    if (iteration_max > 1) {
+      display_confidence();
+    }
+  }
+  
+  if (local_cpu_usage || remote_cpu_usage) {
+    local_cpu_method = format_cpu_method(cpu_method);
+    remote_cpu_method = format_cpu_method(xti_udp_rr_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method);
+      }
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,
+		cpu_title,
+		local_cpu_method,
+		remote_cpu_method);
+      }
+    
+      fprintf(where,
+	      cpu_fmt_1_line_1,		/* the format string */
+	      lss_size,		/* local sendbuf size */
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* guess */
+	      elapsed_time,		/* how long was the test */
+	      nummessages/elapsed_time,
+	      local_cpu_utilization,	/* local cpu */
+	      remote_cpu_utilization,	/* remote cpu */
+	      local_service_demand,	/* local service demand */
+	      remote_service_demand);	/* remote service demand */
+      fprintf(where,
+	      cpu_fmt_1_line_2,
+	      rss_size,
+	      rsr_size);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      nummessages/elapsed_time);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+    
+      fprintf(where,
+	      tput_fmt_1_line_1,	/* the format string */
+	      lss_size,
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* how large were the responses */
+	      elapsed_time, 		/* how long did it take */
+	      nummessages/elapsed_time);
+      fprintf(where,
+	      tput_fmt_1_line_2,
+	      rss_size, 		/* remote recvbuf size */
+	      rsr_size);
+      
+      break;
+    }
+  }
+  fflush(where);
+
+  /* it would be a good thing to include information about some of the */
+  /* other parameters that may have been set for this test, but at the */
+  /* moment, I do not wish to figure-out all the  formatting, so I will */
+  /* just put this comment here to help remind me that it is something */
+  /* that should be done at a later time. */
+  
+  /* how to handle the verbose information in the presence of */
+  /* confidence intervals is yet to be determined... raj 11/94 */
+
+  if (verbosity > 1) {
+    /* The user wanted to know it all, so we will give it to him. */
+    /* This information will include as much as we can find about */
+    /* UDP statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\nHistogram of request/reponse times.\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+  }
+}
+
+ /* this routine implements the receive side (netserver) of a XTI_UDP_RR */
+ /* test. */
+void 
+  recv_xti_udp_rr()
+{
+  
+  struct ring_elt *recv_ring;
+  struct ring_elt *send_ring;
+
+  struct t_bind bind_req, bind_resp;
+  struct t_unitdata send_unitdata;
+  struct t_unitdata recv_unitdata;
+  int	            flags = 0;
+
+  struct sockaddr_in myaddr_in, peeraddr_in;
+  SOCKET s_data;
+  int 	addrlen;
+  int	trans_received;
+  int	trans_remaining;
+  float	elapsed_time;
+  
+  struct	xti_udp_rr_request_struct	*xti_udp_rr_request;
+  struct	xti_udp_rr_response_struct	*xti_udp_rr_response;
+  struct	xti_udp_rr_results_struct	*xti_udp_rr_results;
+  
+  
+  /* a little variable initialization */
+  memset (&myaddr_in, 0, sizeof(struct sockaddr_in));
+  myaddr_in.sin_family      = AF_INET;
+  myaddr_in.sin_addr.s_addr = INADDR_ANY;
+  myaddr_in.sin_port        = 0;
+  memset (&peeraddr_in, 0, sizeof(struct sockaddr_in));
+
+  /* and some not so paranoid :) */
+  xti_udp_rr_request  = 
+    (struct xti_udp_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_udp_rr_response = 
+    (struct xti_udp_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_udp_rr_results  = 
+    (struct xti_udp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_xti_udp_rr: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen socket with all the desired */
+  /* parameters and then let the initiator know that all is ready. If */
+  /* socket size defaults are to be used, then the initiator will have */
+  /* sent us 0's. If the socket sizes cannot be changed, then we will */
+  /* send-back what they are. If that information cannot be determined, */
+  /* then we send-back -1's for the sizes. If things go wrong for any */
+  /* reason, we will drop back ten yards and punt. */
+  
+  /* If anything goes wrong, we want the remote to know about it. It */
+  /* would be best if the error that the remote reports to the user is */
+  /* the actual error we encountered, rather than some bogus unexpected */
+  /* response type message. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = XTI_UDP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_rr: the response type is set...\n");
+    fflush(where);
+  }
+  
+  /* We now alter the message_ptr variables to be at the desired */
+  /* alignments with the desired offsets. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_udp_rr: requested recv alignment of %d offset %d\n",
+	    xti_udp_rr_request->recv_alignment,
+	    xti_udp_rr_request->recv_offset);
+    fprintf(where,"recv_xti_udp_rr: requested send alignment of %d offset %d\n",
+	    xti_udp_rr_request->send_alignment,
+	    xti_udp_rr_request->send_offset);
+    fflush(where);
+  }
+
+  if (send_width == 0) send_width = 1;
+  if (recv_width == 0) recv_width = 1;
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   xti_udp_rr_request->request_size,
+				   xti_udp_rr_request->recv_alignment,
+				   xti_udp_rr_request->recv_offset);
+
+  send_ring = allocate_buffer_ring(send_width,
+				   xti_udp_rr_request->response_size,
+				   xti_udp_rr_request->send_alignment,
+				   xti_udp_rr_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_xti_udp_rr: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* create_xti_endpoint expects to find some things in the global */
+  /* variables, so set the globals based on the values in the request. */
+  /* once the socket has been created, we will set the response values */
+  /* based on the updated value of those globals. raj 7/94 */
+  lss_size = xti_udp_rr_request->send_buf_size;
+  lsr_size = xti_udp_rr_request->recv_buf_size;
+  loc_rcvavoid = xti_udp_rr_request->so_rcvavoid;
+  loc_sndavoid = xti_udp_rr_request->so_sndavoid;
+
+#ifdef __alpha
+  
+  /* ok - even on a DEC box, strings are strings. I din't really want */
+  /* to ntohl the words of a string. since I don't want to teach the */
+  /* send_ and recv_ _request and _response routines about the types, */
+  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+  /* solution would be to use XDR, but I am still leary of being able */
+  /* to find XDR libs on all platforms I want running netperf. raj */
+  {
+    int *charword;
+    int *initword;
+    int *lastword;
+    
+    initword = (int *) xti_udp_rr_request->xti_device;
+    lastword = initword + ((xti_udp_rr_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+  
+#endif /* __alpha */
+    
+  s_data = create_xti_endpoint(xti_udp_rr_request->xti_device);
+  
+  if (s_data == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,"recv_xti_udp_rr: endpoint created...\n");
+    fflush(where);
+  }
+  
+  /* Let's get an address assigned to this socket so we can tell the */
+  /* initiator how to reach the data socket. There may be a desire to */
+  /* nail this socket to a specific IP address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+
+  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_req.addr.len    = sizeof(struct sockaddr_in);
+  bind_req.addr.buf    = (char *)&myaddr_in;
+  bind_req.qlen        = 1;
+
+  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_resp.addr.len    = sizeof(struct sockaddr_in);
+  bind_resp.addr.buf    = (char *)&myaddr_in;
+  bind_resp.qlen        = 1;
+
+  if (t_bind(s_data,
+	     &bind_req,
+	     &bind_resp) == SOCKET_ERROR) {
+    if (debug) {
+      fprintf(where,
+	      "recv_xti_udp_rr: t_bind failed, t_errno %d errno %d\n",
+	      t_errno,
+	      errno);
+      fflush(where);
+    }
+
+    netperf_response.content.serv_errno = t_errno;
+    send_response();
+    
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_udp_rr: endpoint bound to port %d...\n",
+	    ntohs(myaddr_in.sin_port));
+    fflush(where);
+  }
+
+  xti_udp_rr_response->test_length = 
+    xti_udp_rr_request->test_length;
+
+  
+  /* Now myaddr_in contains the port and the internet address this is */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  
+  xti_udp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
+  netperf_response.content.serv_errno   = 0;
+  
+  fprintf(where,"recv port number %d\n",myaddr_in.sin_port);
+  fflush(where);
+  
+  /* But wait, there's more. If the initiator wanted cpu measurements, */
+  /* then we must call the calibrate routine, which will return the max */
+  /* rate back to the initiator. If the CPU was not to be measured, or */
+  /* something went wrong with the calibration, we will return a 0.0 to */
+  /* the initiator. */
+  
+  xti_udp_rr_response->cpu_rate    = 0.0; 	/* assume no cpu */
+  xti_udp_rr_response->measure_cpu = 0;
+  if (xti_udp_rr_request->measure_cpu) {
+    xti_udp_rr_response->measure_cpu = 1;
+    xti_udp_rr_response->cpu_rate = 
+      calibrate_local_cpu(xti_udp_rr_request->cpu_rate);
+  }
+   
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  xti_udp_rr_response->send_buf_size = lss_size;
+  xti_udp_rr_response->recv_buf_size = lsr_size;
+  xti_udp_rr_response->so_rcvavoid   = loc_rcvavoid;
+  xti_udp_rr_response->so_sndavoid   = loc_sndavoid;
+ 
+  /* since we are going to call t_rcvudata() instead of t_rcv() we */
+  /* need to init the unitdata structure raj 3/95 */
+
+  memset (&recv_unitdata, 0, sizeof(recv_unitdata));
+  recv_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
+  recv_unitdata.addr.len    = sizeof(struct sockaddr_in);
+  recv_unitdata.addr.buf    = (char *)&peeraddr_in;
+
+  recv_unitdata.opt.maxlen = 0;
+  recv_unitdata.opt.len    = 0;
+  recv_unitdata.opt.buf    = NULL;
+
+  recv_unitdata.udata.maxlen = xti_udp_rr_request->request_size;
+  recv_unitdata.udata.len    = xti_udp_rr_request->request_size;
+  recv_unitdata.udata.buf    = recv_ring->buffer_ptr;
+
+  /* since we are going to call t_sndudata() instead of t_snd() we */
+  /* need to init the unitdata structure raj 8/95 */
+
+  memset (&send_unitdata, 0, sizeof(send_unitdata));
+  send_unitdata.addr.maxlen = sizeof(struct sockaddr_in);
+  send_unitdata.addr.len    = sizeof(struct sockaddr_in);
+  send_unitdata.addr.buf    = (char *)&peeraddr_in;
+
+  send_unitdata.opt.maxlen = 0;
+  send_unitdata.opt.len    = 0;
+  send_unitdata.opt.buf    = NULL;
+
+  send_unitdata.udata.maxlen = xti_udp_rr_request->response_size;
+  send_unitdata.udata.len    = xti_udp_rr_request->response_size;
+  send_unitdata.udata.buf    = send_ring->buffer_ptr;
+
+  send_response();
+  
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(xti_udp_rr_request->measure_cpu);
+  
+  if (xti_udp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(xti_udp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = xti_udp_rr_request->test_length * -1;
+  }
+  
+  addrlen = sizeof(peeraddr_in);
+  bzero((char *)&peeraddr_in, addrlen);
+  
+  trans_received = 0;
+
+  while ((!times_up) || (trans_remaining > 0)) {
+    
+    /* receive the request from the other side */
+    if (t_rcvudata(s_data,
+		   &recv_unitdata,
+		   &flags) != 0) {
+      if (errno == TNODATA) {
+	continue;
+      }
+      if (errno == EINTR) {
+	/* we must have hit the end of test time. */
+	break;
+      }
+      if (debug) {
+	fprintf(where,
+		"recv_xti_udp_rr: t_rcvudata failed, t_errno %d errno %d\n",
+		t_errno,
+		errno);
+	fflush(where);
+      }
+      netperf_response.content.serv_errno = t_errno;
+      send_response();
+      exit(1);
+    }
+    recv_ring = recv_ring->next;
+    recv_unitdata.udata.buf = recv_ring->buffer_ptr;
+
+    /* Now, send the response to the remote */
+    if (t_sndudata(s_data,
+		   &send_unitdata) != 0) {
+      if (errno == EINTR) {
+	/* we have hit end of test time. */
+	break;
+      }
+      if (debug) {
+	fprintf(where,
+		"recv_xti_udp_rr: t_sndudata failed, t_errno %d errno %d\n",
+		t_errno,
+		errno);
+	fflush(where);
+      }
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    send_ring = send_ring->next;
+    send_unitdata.udata.buf = send_ring->buffer_ptr;
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_xti_udp_rr: Transaction %d complete.\n",
+	      trans_received);
+      fflush(where);
+    }
+    
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(xti_udp_rr_request->measure_cpu,&elapsed_time);
+  
+  if (times_up) {
+    /* we ended the test by time, which was at least 2 seconds */
+    /* longer than we wanted to run. so, we want to subtract */
+    /* PAD_TIME from the elapsed_time. */
+    elapsed_time -= PAD_TIME;
+  }
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_udp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  xti_udp_rr_results->bytes_received = (trans_received * 
+				    (xti_udp_rr_request->request_size + 
+				     xti_udp_rr_request->response_size));
+  xti_udp_rr_results->trans_received = trans_received;
+  xti_udp_rr_results->elapsed_time	 = elapsed_time;
+  xti_udp_rr_results->cpu_method     = cpu_method;
+  if (xti_udp_rr_request->measure_cpu) {
+    xti_udp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_udp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+
+  /* we are done with the socket now */
+  close(s_data);
+
+}
+
+ /* this routine implements the receive (netserver) side of a XTI_TCP_RR */
+ /* test */
+void 
+recv_xti_tcp_rr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct sockaddr_in  myaddr_in,  peeraddr_in;
+  struct t_bind bind_req, bind_resp;
+  struct t_call call_req;
+
+  SOCKET s_listen,s_data;
+  int 	addrlen;
+  char	*temp_message_ptr;
+  int	trans_received;
+  int	trans_remaining;
+  int	bytes_sent;
+  int	request_bytes_recvd;
+  int	request_bytes_remaining;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	xti_tcp_rr_request_struct	*xti_tcp_rr_request;
+  struct	xti_tcp_rr_response_struct	*xti_tcp_rr_response;
+  struct	xti_tcp_rr_results_struct	*xti_tcp_rr_results;
+  
+  xti_tcp_rr_request = 
+    (struct xti_tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_rr_response =
+    (struct xti_tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_rr_results =
+    (struct xti_tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_xti_tcp_rr: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen socket with all the desired */
+  /* parameters and then let the initiator know that all is ready. If */
+  /* socket size defaults are to be used, then the initiator will have */
+  /* sent us 0's. If the socket sizes cannot be changed, then we will */
+  /* send-back what they are. If that information cannot be determined, */
+  /* then we send-back -1's for the sizes. If things go wrong for any */
+  /* reason, we will drop back ten yards and punt. */
+  
+  /* If anything goes wrong, we want the remote to know about it. It */
+  /* would be best if the error that the remote reports to the user is */
+  /* the actual error we encountered, rather than some bogus unexpected */
+  /* response type message. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = XTI_TCP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_rr: the response type is set...\n");
+    fflush(where);
+  }
+  
+  /* allocate the recv and send rings with the requested alignments */
+  /* and offsets. raj 7/94 */
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_rr: requested recv alignment of %d offset %d\n",
+	    xti_tcp_rr_request->recv_alignment,
+	    xti_tcp_rr_request->recv_offset);
+    fprintf(where,"recv_xti_tcp_rr: requested send alignment of %d offset %d\n",
+	    xti_tcp_rr_request->send_alignment,
+	    xti_tcp_rr_request->send_offset);
+    fflush(where);
+  }
+
+  /* at some point, these need to come to us from the remote system */
+  if (send_width == 0) send_width = 1;
+  if (recv_width == 0) recv_width = 1;
+
+  send_ring = allocate_buffer_ring(send_width,
+				   xti_tcp_rr_request->response_size,
+				   xti_tcp_rr_request->send_alignment,
+				   xti_tcp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   xti_tcp_rr_request->request_size,
+				   xti_tcp_rr_request->recv_alignment,
+				   xti_tcp_rr_request->recv_offset);
+
+  
+  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
+  /* can put in OUR values !-) At some point, we may want to nail this */
+  /* socket to a particular network-level address, but for now, */
+  /* INADDR_ANY should be just fine. */
+  
+  bzero((char *)&myaddr_in,
+	sizeof(myaddr_in));
+  myaddr_in.sin_family      = AF_INET;
+  myaddr_in.sin_addr.s_addr = INADDR_ANY;
+  myaddr_in.sin_port        = 0;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_xti_endpoint expects to find some things in the global */
+  /* variables, so set the globals based on the values in the request. */
+  /* once the socket has been created, we will set the response values */
+  /* based on the updated value of those globals. raj 7/94 */
+  lss_size = xti_tcp_rr_request->send_buf_size;
+  lsr_size = xti_tcp_rr_request->recv_buf_size;
+  loc_nodelay = xti_tcp_rr_request->no_delay;
+  loc_rcvavoid = xti_tcp_rr_request->so_rcvavoid;
+  loc_sndavoid = xti_tcp_rr_request->so_sndavoid;
+  
+#ifdef __alpha
+  
+  /* ok - even on a DEC box, strings are strings. I din't really want */
+  /* to ntohl the words of a string. since I don't want to teach the */
+  /* send_ and recv_ _request and _response routines about the types, */
+  /* I will put "anti-ntohl" calls here. I imagine that the "pure" */
+  /* solution would be to use XDR, but I am still leary of being able */
+  /* to find XDR libs on all platforms I want running netperf. raj */
+  {
+    int *charword;
+    int *initword;
+    int *lastword;
+    
+    initword = (int *) xti_tcp_rr_request->xti_device;
+    lastword = initword + ((xti_tcp_rr_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+  
+#endif /* __alpha */
+
+  s_listen = create_xti_endpoint(xti_tcp_rr_request->xti_device);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* Let's get an address assigned to this socket so we can tell the */
+  /* initiator how to reach the data socket. There may be a desire to */
+  /* nail this socket to a specific IP address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+
+  bind_req.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_req.addr.len    = sizeof(struct sockaddr_in);
+  bind_req.addr.buf    = (char *)&myaddr_in;
+  bind_req.qlen        = 1;
+
+  bind_resp.addr.maxlen = sizeof(struct sockaddr_in);
+  bind_resp.addr.len    = sizeof(struct sockaddr_in);
+  bind_resp.addr.buf    = (char *)&myaddr_in;
+  bind_resp.qlen        = 1;
+
+  if (t_bind(s_listen,
+	     &bind_req,
+	     &bind_resp) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = t_errno;
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: t_bind complete port %d\n",
+	    ntohs(myaddr_in.sin_port));
+    fflush(where);
+  }
+  
+  /* Now myaddr_in contains the port and the internet address this is */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  
+  xti_tcp_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
+  netperf_response.content.serv_errno   = 0;
+  
+  /* But wait, there's more. If the initiator wanted cpu measurements, */
+  /* then we must call the calibrate routine, which will return the max */
+  /* rate back to the initiator. If the CPU was not to be measured, or */
+  /* something went wrong with the calibration, we will return a 0.0 to */
+  /* the initiator. */
+  
+  xti_tcp_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  xti_tcp_rr_response->measure_cpu = 0;
+
+  if (xti_tcp_rr_request->measure_cpu) {
+    xti_tcp_rr_response->measure_cpu = 1;
+    xti_tcp_rr_response->cpu_rate = calibrate_local_cpu(xti_tcp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  xti_tcp_rr_response->send_buf_size = lss_size;
+  xti_tcp_rr_response->recv_buf_size = lsr_size;
+  xti_tcp_rr_response->no_delay = loc_nodelay;
+  xti_tcp_rr_response->so_rcvavoid = loc_rcvavoid;
+  xti_tcp_rr_response->so_sndavoid = loc_sndavoid;
+  xti_tcp_rr_response->test_length = xti_tcp_rr_request->test_length;
+  send_response();
+  
+  /* Now, let's set-up the socket to listen for connections. for xti, */
+  /* the t_listen call is blocking by default - this is different */
+  /* semantics from BSD - probably has to do with being able to reject */
+  /* a call before an accept */
+  call_req.addr.maxlen = sizeof(struct sockaddr_in);
+  call_req.addr.len    = sizeof(struct sockaddr_in);
+  call_req.addr.buf    = (char *)&peeraddr_in;
+  call_req.opt.maxlen  = 0;
+  call_req.opt.len     = 0;
+  call_req.opt.buf     = NULL;
+  call_req.udata.maxlen= 0;
+  call_req.udata.len   = 0;
+  call_req.udata.buf   = 0;
+
+  if (t_listen(s_listen, &call_req) == -1) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: t_listen: errno %d t_errno %d\n",
+	    errno,
+	    t_errno);
+    fflush(where);
+    netperf_response.content.serv_errno = t_errno;
+    close(s_listen);
+    send_response();
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: t_listen complete t_look 0x%.4x\n",
+	    t_look(s_listen));
+    fflush(where);
+  }
+  
+  /* now just rubber stamp the thing. we want to use the same fd? so */
+  /* we will just equate s_data with s_listen. this seems a little */
+  /* hokey to me, but then I'm a BSD biggot still. raj 2/95 */
+  s_data = s_listen;
+  if (t_accept(s_listen,
+	       s_data,
+	       &call_req) == -1) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: t_accept: errno %d t_errno %d\n",
+	    errno,
+	    t_errno);
+    fflush(where);
+    close(s_listen);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: t_accept complete t_look 0x%.4x",
+	    t_look(s_data));
+    fprintf(where,
+	    " remote is %s port %d\n",
+	    inet_ntoa(*(struct in_addr *)&peeraddr_in.sin_addr),
+	    ntohs(peeraddr_in.sin_port));
+    fflush(where);
+  }
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(xti_tcp_rr_request->measure_cpu);
+  
+  if (xti_tcp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(xti_tcp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = xti_tcp_rr_request->test_length * -1;
+  }
+
+  trans_received = 0;
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    temp_message_ptr = recv_ring->buffer_ptr;
+    request_bytes_remaining	= xti_tcp_rr_request->request_size;
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=t_rcv(s_data,
+				    temp_message_ptr,
+				    request_bytes_remaining,
+				    &xti_flags)) == SOCKET_ERROR) {
+	if (errno == EINTR) {
+	  /* the timer popped */
+	  timed_out = 1;
+	  break;
+	}
+	fprintf(where,
+		"recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
+		errno,
+		t_errno,
+		request_bytes_recvd);
+	fprintf(where,
+		" t_look 0x%x",
+		t_look(s_data));
+	fflush(where);
+	netperf_response.content.serv_errno = t_errno;
+	send_response();
+	exit(1);
+      }
+      else {
+	request_bytes_remaining -= request_bytes_recvd;
+	temp_message_ptr  += request_bytes_recvd;
+      }
+    }
+
+    recv_ring = recv_ring->next;
+
+    if (timed_out) {
+      /* we hit the end of the test based on time - lets */
+      /* bail out of here now... */
+      if (debug) {
+	fprintf(where,"yo5\n");
+	fflush(where);
+      }						
+      break;
+    }
+    
+    /* Now, send the response to the remote */
+    if((bytes_sent=t_snd(s_data,
+			 send_ring->buffer_ptr,
+			 xti_tcp_rr_request->response_size,
+			 0)) == -1) {
+      if (errno == EINTR) {
+	/* the test timer has popped */
+	timed_out = 1;
+	if (debug) {
+	  fprintf(where,"yo6\n");
+	  fflush(where);						
+	}
+	break;
+      }
+      fprintf(where,
+	      "recv_xti_tcp_rr: t_rcv: errno %d t_errno %d len %d",
+	      errno,
+	      t_errno,
+	      bytes_sent);
+      fprintf(where,
+	      " t_look 0x%x",
+	      t_look(s_data));
+      fflush(where);
+      netperf_response.content.serv_errno = t_errno;
+      send_response();
+      exit(1);
+    }
+    
+    send_ring = send_ring->next;
+
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(xti_tcp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer(); /* this is probably unnecessary, but it shouldn't hurt */
+
+  if (timed_out) {
+    /* we ended the test by time, which was at least 2 seconds */
+    /* longer than we wanted to run. so, we want to subtract */
+    /* PAD_TIME from the elapsed_time. */
+    elapsed_time -= PAD_TIME;
+  }
+
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  xti_tcp_rr_results->bytes_received = (trans_received * 
+					(xti_tcp_rr_request->request_size + 
+					 xti_tcp_rr_request->response_size));
+  xti_tcp_rr_results->trans_received = trans_received;
+  xti_tcp_rr_results->elapsed_time   = elapsed_time;
+  xti_tcp_rr_results->cpu_method     = cpu_method;
+  if (xti_tcp_rr_request->measure_cpu) {
+    xti_tcp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are done with the socket, free it */
+  t_close(s_data);
+
+  send_response();
+  
+}
+
+
+
+ /* this test is intended to test the performance of establishing a */
+ /* connection, exchanging a request/response pair, and repeating. it */
+ /* is expected that this would be a good starting-point for */
+ /* comparision of T/TCP with classic TCP for transactional workloads. */
+ /* it will also look (can look) much like the communication pattern */
+ /* of http for www access. */
+
+void 
+send_xti_tcp_conn_rr(char remote_host[])
+{
+  
+  char *tput_title = "\
+Local /Remote\n\
+Socket Size   Request  Resp.   Elapsed  Trans.\n\
+Send   Recv   Size     Size    Time     Rate         \n\
+bytes  Bytes  bytes    bytes   secs.    per sec   \n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   \n";
+  char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *cpu_title = "\
+Local /Remote\n\
+Socket Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
+Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
+bytes  bytes  bytes   bytes  secs.   per sec  %%      %%      us/Tr   us/Tr\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f\n";
+  
+  char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f   %-6.2f %-6.2f %-6.3f  %-6.3f\n";
+  
+  char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *ksink_fmt = "\
+Alignment      Offset\n\
+Local  Remote  Local  Remote\n\
+Send   Recv    Send   Recv\n\
+%5d  %5d   %5d  %5d\n";
+  
+  
+  int 			one = 1;
+  int			timed_out = 0;
+  float			elapsed_time;
+  
+  int	len;
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+  char	*temp_message_ptr;
+  int	nummessages;
+  SOCKET send_socket;
+  int	trans_remaining;
+  double	bytes_xferd;
+  int	sock_opt_len = sizeof(int);
+  int	rsp_bytes_left;
+  int	rsp_bytes_recvd;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct	hostent	        *hp;
+  struct	sockaddr_in	server;
+  struct        sockaddr_in     *myaddr;
+  unsigned      int             addr;
+  int                           myport;
+
+  struct	xti_tcp_conn_rr_request_struct	*xti_tcp_conn_rr_request;
+  struct	xti_tcp_conn_rr_response_struct	*xti_tcp_conn_rr_response;
+  struct	xti_tcp_conn_rr_results_struct	*xti_tcp_conn_rr_result;
+  
+  xti_tcp_conn_rr_request = 
+    (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_conn_rr_response = 
+    (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_conn_rr_result =
+    (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  /* since we are now disconnected from the code that established the */
+  /* control socket, and since we want to be able to use different */
+  /* protocols and such, we are passed the name of the remote host and */
+  /* must turn that into the test specific addressing information. */
+  
+  myaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
+  if (myaddr == NULL) {
+    printf("malloc(%d) failed!\n", sizeof(struct sockaddr_in));
+    exit(1);
+  }
+
+  bzero((char *)&server,
+	sizeof(server));
+  bzero((char *)myaddr,
+	sizeof(struct sockaddr_in));
+  myaddr->sin_family = AF_INET;
+
+  /* it would seem that while HP-UX will allow an IP address (as a */
+  /* string) in a call to gethostbyname, other, less enlightened */
+  /* systems do not. fix from awjacks@ca.sandia.gov raj 10/95 */  
+  /* order changed to check for IP address first. raj 7/96 */
+
+  if ((addr = inet_addr(remote_host)) == SOCKET_ERROR) {
+    /* it was not an IP address, try it as a name */
+    if ((hp = gethostbyname(remote_host)) == NULL) {
+      /* we have no idea what it is */
+      fprintf(where,
+	      "establish_control: could not resolve the destination %s\n",
+	      remote_host);
+      fflush(where);
+      exit(1);
+    }
+    else {
+      /* it was a valid remote_host */
+      bcopy(hp->h_addr,
+	    (char *)&server.sin_addr,
+	    hp->h_length);
+      server.sin_family = hp->h_addrtype;
+    }
+  }
+  else {
+    /* it was a valid IP address */
+    server.sin_addr.s_addr = addr;
+    server.sin_family = AF_INET;
+  }    
+  
+  if ( print_headers ) {
+    fprintf(where,"TCP Connect/Request/Response Test\n");
+    if (local_cpu_usage || remote_cpu_usage)
+      fprintf(where,cpu_title,format_units());
+    else
+      fprintf(where,tput_title,format_units());
+  }
+  
+  /* initialize a few counters */
+  
+  nummessages	=	0;
+  bytes_xferd	=	0.0;
+  times_up 	= 	0;
+  
+  /* set-up the data buffers with the requested alignment and offset */
+  if (send_width == 0) send_width = 1;
+  if (recv_width == 0) recv_width = 1;
+
+  send_ring = allocate_buffer_ring(send_width,
+				   req_size,
+				   local_send_align,
+				   local_send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   rsp_size,
+				   local_recv_align,
+				   local_recv_offset);
+
+
+  if (debug) {
+    fprintf(where,"send_xti_tcp_conn_rr: send_socket obtained...\n");
+  }
+  
+  /* If the user has requested cpu utilization measurements, we must */
+  /* calibrate the cpu(s). We will perform this task within the tests */
+  /* themselves. If the user has specified the cpu rate, then */
+  /* calibrate_local_cpu will return rather quickly as it will have */
+  /* nothing to do. If local_cpu_rate is zero, then we will go through */
+  /* all the "normal" calibration stuff and return the rate back.*/
+  
+  if (local_cpu_usage) {
+    local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+  }
+  
+  /* Tell the remote end to do a listen. The server alters the socket */
+  /* paramters on the other side at this point, hence the reason for */
+  /* all the values being passed in the setup message. If the user did */
+  /* not specify any of the parameters, they will be passed as 0, which */
+  /* will indicate to the remote that no changes beyond the system's */
+  /* default should be used. Alignment is the exception, it will */
+  /* default to 8, which will be no alignment alterations. */
+  
+  netperf_request.content.request_type	        =	DO_XTI_TCP_CRR;
+  xti_tcp_conn_rr_request->recv_buf_size	=	rsr_size;
+  xti_tcp_conn_rr_request->send_buf_size	=	rss_size;
+  xti_tcp_conn_rr_request->recv_alignment	=	remote_recv_align;
+  xti_tcp_conn_rr_request->recv_offset	=	remote_recv_offset;
+  xti_tcp_conn_rr_request->send_alignment	=	remote_send_align;
+  xti_tcp_conn_rr_request->send_offset	=	remote_send_offset;
+  xti_tcp_conn_rr_request->request_size	=	req_size;
+  xti_tcp_conn_rr_request->response_size	=	rsp_size;
+  xti_tcp_conn_rr_request->no_delay	        =	rem_nodelay;
+  xti_tcp_conn_rr_request->measure_cpu	=	remote_cpu_usage;
+  xti_tcp_conn_rr_request->cpu_rate	        =	remote_cpu_rate;
+  xti_tcp_conn_rr_request->so_rcvavoid	=	rem_rcvavoid;
+  xti_tcp_conn_rr_request->so_sndavoid	=	rem_sndavoid;
+  if (test_time) {
+    xti_tcp_conn_rr_request->test_length	=	test_time;
+  }
+  else {
+    xti_tcp_conn_rr_request->test_length	=	test_trans * -1;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"netperf: send_xti_tcp_conn_rr: requesting TCP crr test\n");
+  }
+  
+  send_request();
+  
+  /* The response from the remote will contain all of the relevant 	*/
+  /* socket parameters for this test type. We will put them back into 	*/
+  /* the variables here so they can be displayed if desired.  The	*/
+  /* remote will have calibrated CPU if necessary, and will have done	*/
+  /* all the needed set-up we will have calibrated the cpu locally	*/
+  /* before sending the request, and will grab the counter value right	*/
+  /* after the connect returns. The remote will grab the counter right	*/
+  /* after the accept call. This saves the hassle of extra messages	*/
+  /* being sent for the TCP tests.					*/
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    rsr_size	=	xti_tcp_conn_rr_response->recv_buf_size;
+    rss_size	=	xti_tcp_conn_rr_response->send_buf_size;
+    rem_nodelay	=	xti_tcp_conn_rr_response->no_delay;
+    remote_cpu_usage=	xti_tcp_conn_rr_response->measure_cpu;
+    remote_cpu_rate = 	xti_tcp_conn_rr_response->cpu_rate;
+    /* make sure that port numbers are in network order */
+    server.sin_port	=	(short)xti_tcp_conn_rr_response->data_port_number;
+    server.sin_port =	htons(server.sin_port);
+    if (debug) {
+      fprintf(where,"remote listen done.\n");
+      fprintf(where,"remote port is %d\n",ntohs(server.sin_port));
+      fflush(where);
+    }
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    
+    exit(1);
+  }
+  
+  /* Set-up the test end conditions. For a request/response test, they */
+  /* can be either time or transaction based. */
+  
+  if (test_time) {
+    /* The user wanted to end the test after a period of time. */
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(test_time);
+  }
+  else {
+    /* The tester wanted to send a number of bytes. */
+    trans_remaining = test_bytes;
+    times_up = 1;
+  }
+  
+  /* The cpu_start routine will grab the current time and possibly */
+  /* value of the idle counter for later use in measuring cpu */
+  /* utilization and/or service demand and thruput. */
+  
+  cpu_start(local_cpu_usage);
+  
+  /* We use an "OR" to control test execution. When the test is */
+  /* controlled by time, the byte count check will always return false. */
+  /* When the test is controlled by byte count, the time test will */
+  /* always return false. When the test is finished, the whole */
+  /* expression will go false and we will stop sending data. I think I */
+  /* just arbitrarily decrement trans_remaining for the timed test, but */
+  /* will not do that just yet... One other question is whether or not */
+  /* the send buffer and the receive buffer should be the same buffer. */
+
+  /* just for grins, start the port numbers at 65530. this should */
+  /* quickly flush-out those broken implementations of TCP which treat */
+  /* the port number as a signed 16 bit quantity. */
+  myport = 65530;
+  myaddr->sin_port = htons(myport);
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+
+    /* set up the data socket */
+    send_socket = create_xti_endpoint(loc_xti_device);
+  
+    if (send_socket == INVALID_SOCKET) {
+      perror("netperf: send_xti_tcp_conn_rr: tcp stream data socket");
+      exit(1);
+    }
+
+    /* we set SO_REUSEADDR on the premis that no unreserved port */
+    /* number on the local system is going to be already connected to */
+    /* the remote netserver's port number. we might still have a */
+    /* problem if there is a port in the unconnected state. In that */
+    /* case, we might want to throw-in a goto to the point where we */
+    /* increment the port number by one and try again. of course, this */
+    /* could lead to a big load of spinning. one thing that I might */
+    /* try later is to have the remote actually allocate a couple of */
+    /* port numbers and cycle through those as well. depends on if we */
+    /* can get through all the unreserved port numbers in less than */
+    /* the length of the TIME_WAIT state raj 8/94 */
+    one = 1;
+    if(setsockopt(send_socket, SOL_SOCKET, SO_REUSEADDR,
+		  (char *)&one, sock_opt_len) == SOCKET_ERROR) {
+      perror("netperf: send_xti_tcp_conn_rr: so_reuseaddr");
+      exit(1);
+    }
+
+    /* we want to bind our socket to a particular port number. */
+    if (bind(send_socket,
+	     (struct sockaddr *)myaddr,
+	     sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
+      printf("netperf: send_xti_tcp_conn_rr: tried to bind to port %d\n",
+	     ntohs(myaddr->sin_port));
+      perror("netperf: send_xti_tcp_conn_rr: bind");
+      exit(1);
+    }
+
+    /* Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		(struct sockaddr *)&server,
+		sizeof(server)) == INVALID_SOCKET){
+      if (errno == EINTR) {
+	/* we hit the end of a */
+	/* timed test. */
+	timed_out = 1;
+	break;
+      }
+      perror("netperf: data socket connect failed");
+      printf("\tattempted to connect on socket %d to port %d",
+	     send_socket,
+	     ntohs(server.sin_port));
+      printf(" from port %d \n",ntohs(myaddr->sin_port));
+      exit(1);
+    }
+
+    /* send the request */
+    if((len=send(send_socket,
+		 send_ring->buffer_ptr,
+		 req_size,
+		 0)) != req_size) {
+      if (errno == EINTR) {
+	/* we hit the end of a */
+	/* timed test. */
+	timed_out = 1;
+	break;
+      }
+      perror("send_xti_tcp_conn_rr: data send error");
+      exit(1);
+    }
+    send_ring = send_ring->next;
+
+    /* receive the response */
+    rsp_bytes_left = rsp_size;
+    temp_message_ptr  = recv_ring->buffer_ptr;
+    while(rsp_bytes_left > 0) {
+      if((rsp_bytes_recvd=recv(send_socket,
+			       temp_message_ptr,
+			       rsp_bytes_left,
+			       0)) == SOCKET_ERROR) {
+	if (errno == EINTR) {
+	  /* We hit the end of a timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_xti_tcp_conn_rr: data recv error");
+	exit(1);
+      }
+      rsp_bytes_left -= rsp_bytes_recvd;
+      temp_message_ptr  += rsp_bytes_recvd;
+    }	
+    recv_ring = recv_ring->next;
+
+    if (timed_out) {
+      /* we may have been in a nested while loop - we need */
+      /* another call to break. */
+      break;
+    }
+
+    close(send_socket);
+
+    nummessages++;          
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug > 3) {
+      fprintf(where,
+	      "Transaction %d completed on local port %d\n",
+	      nummessages,
+	      ntohs(myaddr->sin_port));
+      fflush(where);
+    }
+
+newport:
+    /* pick a new port number */
+    myport = ntohs(myaddr->sin_port);
+    myport++;
+    /* we do not want to use the port number that the server is */
+    /* sitting at - this would cause us to fail in a loopback test */
+
+    if (myport == ntohs(server.sin_port)) myport++;
+
+    /* wrap the port number when we get to 65535. NOTE, some broken */
+    /* TCP's might treat the port number as a signed 16 bit quantity. */
+    /* we aren't interested in testing such broekn implementations :) */
+    /* raj 8/94  */
+    if (myport == 65535) {
+      myport = 5000;
+    }
+    myaddr->sin_port = htons(myport);
+
+    if (debug) {
+      if ((myport % 1000) == 0) {
+	printf("port %d\n",myport);
+      }
+    }
+
+  }
+  
+  /* this call will always give us the elapsed time for the test, and */
+  /* will also store-away the necessaries for cpu utilization */
+
+  cpu_stop(local_cpu_usage,&elapsed_time);	/* was cpu being measured? */
+  /* how long did we really run? */
+  
+  /* Get the statistics from the remote end. The remote will have */
+  /* calculated service demand and all those interesting things. If it */
+  /* wasn't supposed to care, it will return obvious values. */
+  
+  recv_response();
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"remote results obtained\n");
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    
+    exit(1);
+  }
+  
+  /* We now calculate what our thruput was for the test. In the future, */
+  /* we may want to include a calculation of the thruput measured by */
+  /* the remote, but it should be the case that for a TCP stream test, */
+  /* that the two numbers should be *very* close... We calculate */
+  /* bytes_sent regardless of the way the test length was controlled. */
+  /* If it was time, we needed to, and if it was by bytes, the user may */
+  /* have specified a number of bytes that wasn't a multiple of the */
+  /* send_size, so we really didn't send what he asked for ;-) We use */
+  /* Kbytes/s as the units of thruput for a TCP stream test, where K = */
+  /* 1024. A future enhancement *might* be to choose from a couple of */
+  /* unit selections. */ 
+  
+  bytes_xferd	= (req_size * nummessages) + (rsp_size * nummessages);
+  thruput	= calc_thruput(bytes_xferd);
+  
+  if (local_cpu_usage || remote_cpu_usage) {
+    /* We must now do a little math for service demand and cpu */
+    /* utilization for the system(s) */
+    /* Of course, some of the information might be bogus because */
+    /* there was no idle counter in the kernel(s). We need to make */
+    /* a note of this for the user's benefit...*/
+    if (local_cpu_usage) {
+      if (local_cpu_rate == 0.0) {
+	fprintf(where,"WARNING WARNING WARNING  WARNING WARNING WARNING  WARNING!\n");
+	fprintf(where,"Local CPU usage numbers based on process information only!\n");
+	fflush(where);
+      }
+      local_cpu_utilization = calc_cpu_util(0.0);
+      /* since calc_service demand is doing ms/Kunit we will */
+      /* multiply the number of transaction by 1024 to get */
+      /* "good" numbers */
+      local_service_demand  = calc_service_demand((double) nummessages*1024,
+						  0.0,
+						  0.0,
+						  0);
+    }
+    else {
+      local_cpu_utilization	= -1.0;
+      local_service_demand	= -1.0;
+    }
+    
+    if (remote_cpu_usage) {
+      if (remote_cpu_rate == 0.0) {
+	fprintf(where,"DANGER  DANGER  DANGER    DANGER  DANGER  DANGER    DANGER!\n");
+	fprintf(where,"Remote CPU usage numbers based on process information only!\n");
+	fflush(where);
+      }
+      remote_cpu_utilization = xti_tcp_conn_rr_result->cpu_util;
+      /* since calc_service demand is doing ms/Kunit we will */
+      /* multiply the number of transaction by 1024 to get */
+      /* "good" numbers */
+      remote_service_demand = calc_service_demand((double) nummessages*1024,
+						  0.0,
+						  remote_cpu_utilization,
+						  xti_tcp_conn_rr_result->num_cpus);
+    }
+    else {
+      remote_cpu_utilization = -1.0;
+      remote_service_demand  = -1.0;
+    }
+    
+    /* We are now ready to print all the information. If the user */
+    /* has specified zero-level verbosity, we will just print the */
+    /* local service demand, or the remote service demand. If the */
+    /* user has requested verbosity level 1, he will get the basic */
+    /* "streamperf" numbers. If the user has specified a verbosity */
+    /* of greater than 1, we will display a veritable plethora of */
+    /* background information from outside of this block as it it */
+    /* not cpu_measurement specific...  */
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand);
+      }
+      break;
+    case 1:
+      fprintf(where,
+	      cpu_fmt_1_line_1,		/* the format string */
+	      lss_size,		/* local sendbuf size */
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* guess */
+	      elapsed_time,		/* how long was the test */
+	      nummessages/elapsed_time,
+	      local_cpu_utilization,	/* local cpu */
+	      remote_cpu_utilization,	/* remote cpu */
+	      local_service_demand,	/* local service demand */
+	      remote_service_demand);	/* remote service demand */
+      fprintf(where,
+	      cpu_fmt_1_line_2,
+	      rss_size,
+	      rsr_size);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      nummessages/elapsed_time);
+      break;
+    case 1:
+      fprintf(where,
+	      tput_fmt_1_line_1,	/* the format string */
+	      lss_size,
+	      lsr_size,
+	      req_size,		/* how large were the requests */
+	      rsp_size,		/* how large were the responses */
+	      elapsed_time, 		/* how long did it take */
+	      nummessages/elapsed_time);
+      fprintf(where,
+	      tput_fmt_1_line_2,
+	      rss_size, 		/* remote recvbuf size */
+	      rsr_size);
+      
+      break;
+    }
+  }
+  
+  /* it would be a good thing to include information about some of the */
+  /* other parameters that may have been set for this test, but at the */
+  /* moment, I do not wish to figure-out all the  formatting, so I will */
+  /* just put this comment here to help remind me that it is something */
+  /* that should be done at a later time. */
+  
+  if (verbosity > 1) {
+    /* The user wanted to know it all, so we will give it to him. */
+    /* This information will include as much as we can find about */
+    /* TCP statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+    fprintf(where,
+	    ksink_fmt);
+  }
+  
+}
+
+
+void 
+recv_xti_tcp_conn_rr()
+{
+  
+  char  *message;
+  struct	sockaddr_in        myaddr_in,
+  peeraddr_in;
+  SOCKET s_listen,s_data;
+  int 	addrlen;
+  char	*recv_message_ptr;
+  char	*send_message_ptr;
+  char	*temp_message_ptr;
+  int	trans_received;
+  int	trans_remaining;
+  int	bytes_sent;
+  int	request_bytes_recvd;
+  int	request_bytes_remaining;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	xti_tcp_conn_rr_request_struct	*xti_tcp_conn_rr_request;
+  struct	xti_tcp_conn_rr_response_struct	*xti_tcp_conn_rr_response;
+  struct	xti_tcp_conn_rr_results_struct	*xti_tcp_conn_rr_results;
+  
+  xti_tcp_conn_rr_request = 
+    (struct xti_tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
+  xti_tcp_conn_rr_response = 
+    (struct xti_tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
+  xti_tcp_conn_rr_results = 
+    (struct xti_tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_xti_tcp_conn_rr: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen socket with all the desired */
+  /* parameters and then let the initiator know that all is ready. If */
+  /* socket size defaults are to be used, then the initiator will have */
+  /* sent us 0's. If the socket sizes cannot be changed, then we will */
+  /* send-back what they are. If that information cannot be determined, */
+  /* then we send-back -1's for the sizes. If things go wrong for any */
+  /* reason, we will drop back ten yards and punt. */
+  
+  /* If anything goes wrong, we want the remote to know about it. It */
+  /* would be best if the error that the remote reports to the user is */
+  /* the actual error we encountered, rather than some bogus unexpected */
+  /* response type message. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_conn_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = XTI_TCP_CRR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_conn_rr: the response type is set...\n");
+    fflush(where);
+  }
+
+  /* set-up the data buffer with the requested alignment and offset */
+  message = (char *)malloc(DATABUFFERLEN);
+  if (message == NULL) {
+    printf("malloc(%d) failed!\n", DATABUFFERLEN);
+    exit(1);
+  }
+  
+  /* We now alter the message_ptr variables to be at the desired */
+  /* alignments with the desired offsets. */
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_conn_rr: requested recv alignment of %d offset %d\n",
+	    xti_tcp_conn_rr_request->recv_alignment,
+	    xti_tcp_conn_rr_request->recv_offset);
+    fprintf(where,
+	    "recv_xti_tcp_conn_rr: requested send alignment of %d offset %d\n",
+	    xti_tcp_conn_rr_request->send_alignment,
+	    xti_tcp_conn_rr_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->recv_alignment, xti_tcp_conn_rr_request->recv_offset);
+  
+  send_message_ptr = ALIGN_BUFFER(message, xti_tcp_conn_rr_request->send_alignment, xti_tcp_conn_rr_request->send_offset);
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_conn_rr: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Let's clear-out our sockaddr for the sake of cleanlines. Then we */
+  /* can put in OUR values !-) At some point, we may want to nail this */
+  /* socket to a particular network-level address, but for now, */
+  /* INADDR_ANY should be just fine. */
+  
+  bzero((char *)&myaddr_in,
+	sizeof(myaddr_in));
+  myaddr_in.sin_family      = AF_INET;
+  myaddr_in.sin_addr.s_addr = INADDR_ANY;
+  myaddr_in.sin_port        = 0;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_xti_tcp_conn_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_xti_endpoint expects to find some things in the global */
+  /* variables, so set the globals based on the values in the request. */
+  /* once the socket has been created, we will set the response values */
+  /* based on the updated value of those globals. raj 7/94 */
+  lss_size = xti_tcp_conn_rr_request->send_buf_size;
+  lsr_size = xti_tcp_conn_rr_request->recv_buf_size;
+  loc_nodelay = xti_tcp_conn_rr_request->no_delay;
+  loc_rcvavoid = xti_tcp_conn_rr_request->so_rcvavoid;
+  loc_sndavoid = xti_tcp_conn_rr_request->so_sndavoid;
+  
+  s_listen = create_xti_endpoint(loc_xti_device);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    if (debug) {
+      fprintf(where,"could not create data socket\n");
+      fflush(where);
+    }
+    exit(1);
+  }
+
+  /* Let's get an address assigned to this socket so we can tell the */
+  /* initiator how to reach the data socket. There may be a desire to */
+  /* nail this socket to a specific IP address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+  
+  if (bind(s_listen,
+	   (struct sockaddr *)&myaddr_in,
+	   sizeof(myaddr_in)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    if (debug) {
+      fprintf(where,"could not bind\n");
+      fflush(where);
+    }
+    exit(1);
+  }
+
+  /* Now, let's set-up the socket to listen for connections */
+  if (listen(s_listen, 5) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    if (debug) {
+      fprintf(where,"could not listen\n");
+      fflush(where);
+    }
+    exit(1);
+  }
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_listen,
+		  (struct sockaddr *)&myaddr_in,
+		  &addrlen) == SOCKET_ERROR){
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    if (debug) {
+      fprintf(where,"could not geetsockname\n");
+      fflush(where);
+    }
+    exit(1);
+  }
+  
+  /* Now myaddr_in contains the port and the internet address this is */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  
+  xti_tcp_conn_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
+  if (debug) {
+    fprintf(where,"telling the remote to call me at %d\n",
+	    xti_tcp_conn_rr_response->data_port_number);
+    fflush(where);
+  }
+  netperf_response.content.serv_errno   = 0;
+  
+  /* But wait, there's more. If the initiator wanted cpu measurements, */
+  /* then we must call the calibrate routine, which will return the max */
+  /* rate back to the initiator. If the CPU was not to be measured, or */
+  /* something went wrong with the calibration, we will return a 0.0 to */
+  /* the initiator. */
+  
+  xti_tcp_conn_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (xti_tcp_conn_rr_request->measure_cpu) {
+    xti_tcp_conn_rr_response->measure_cpu = 1;
+    xti_tcp_conn_rr_response->cpu_rate = 
+      calibrate_local_cpu(xti_tcp_conn_rr_request->cpu_rate);
+  }
+  
+
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  xti_tcp_conn_rr_response->send_buf_size = lss_size;
+  xti_tcp_conn_rr_response->recv_buf_size = lsr_size;
+  xti_tcp_conn_rr_response->no_delay = loc_nodelay;
+  xti_tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
+  xti_tcp_conn_rr_response->so_sndavoid = loc_sndavoid;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(xti_tcp_conn_rr_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (xti_tcp_conn_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(xti_tcp_conn_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = xti_tcp_conn_rr_request->test_length * -1;
+  }
+  
+  trans_received = 0;
+
+  while ((!times_up) || (trans_remaining > 0)) {
+
+    /* accept a connection from the remote */
+    if ((s_data=accept(s_listen,
+		       (struct sockaddr *)&peeraddr_in,
+		       &addrlen)) == INVALID_SOCKET) {
+      if (errno == EINTR) {
+	/* the timer popped */
+	timed_out = 1;
+	break;
+      }
+      fprintf(where,"recv_xti_tcp_conn_rr: accept: errno = %d\n",errno);
+      fflush(where);
+      close(s_listen);
+      
+      exit(1);
+    }
+  
+    if (debug) {
+      fprintf(where,"recv_xti_tcp_conn_rr: accepted data connection.\n");
+      fflush(where);
+    }
+  
+    temp_message_ptr	= recv_message_ptr;
+    request_bytes_remaining	= xti_tcp_conn_rr_request->request_size;
+    
+    /* receive the request from the other side */
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	if (errno == EINTR) {
+	  /* the timer popped */
+	  timed_out = 1;
+	  break;
+	}
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      else {
+	request_bytes_remaining -= request_bytes_recvd;
+	temp_message_ptr  += request_bytes_recvd;
+      }
+    }
+    
+    if (timed_out) {
+      /* we hit the end of the test based on time - lets */
+      /* bail out of here now... */
+      fprintf(where,"yo5\n");
+      fflush(where);						
+      break;
+    }
+    
+    /* Now, send the response to the remote */
+    if((bytes_sent=send(s_data,
+			send_message_ptr,
+			xti_tcp_conn_rr_request->response_size,
+			0)) == SOCKET_ERROR) {
+      if (errno == EINTR) {
+	/* the test timer has popped */
+	timed_out = 1;
+	fprintf(where,"yo6\n");
+	fflush(where);						
+	break;
+      }
+      netperf_response.content.serv_errno = 99;
+      send_response();
+      exit(1);
+    }
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_xti_tcp_conn_rr: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+
+    /* close the connection */
+    close(s_data);
+
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(xti_tcp_conn_rr_request->measure_cpu,&elapsed_time);
+  
+  if (timed_out) {
+    /* we ended the test by time, which was at least 2 seconds */
+    /* longer than we wanted to run. so, we want to subtract */
+    /* PAD_TIME from the elapsed_time. */
+    elapsed_time -= PAD_TIME;
+  }
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_conn_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  xti_tcp_conn_rr_results->bytes_received	= (trans_received * 
+					   (xti_tcp_conn_rr_request->request_size + 
+					    xti_tcp_conn_rr_request->response_size));
+  xti_tcp_conn_rr_results->trans_received	= trans_received;
+  xti_tcp_conn_rr_results->elapsed_time	= elapsed_time;
+  if (xti_tcp_conn_rr_request->measure_cpu) {
+    xti_tcp_conn_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_xti_tcp_conn_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+void
+print_xti_usage()
+{
+
+  fwrite(xti_usage, sizeof(char), strlen(xti_usage), stdout);
+  exit(1);
+
+}
+
+void
+scan_xti_args(int argc, char *argv[])
+{
+#define XTI_ARGS "Dhm:M:r:s:S:Vw:W:X:"
+  extern int	optind, opterrs;  /* index of first unused arg 	*/
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	
+    arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+  
+  if (no_control) {
+    fprintf(where,
+	    "The XTI tests do not know how to run with no control connection\n");
+    exit(-1);
+  }
+
+  /* Go through all the command line arguments and break them */
+  /* out. For those options that take two parms, specifying only */
+  /* the first will set both to that value. Specifying only the */
+  /* second will leave the first untouched. To change only the */
+  /* first, use the form "first," (see the routine break_args.. */
+  
+  while ((c= getopt(argc, argv, XTI_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case 'h':
+      print_xti_usage();
+      exit(1);
+    case 'D':
+      /* set the TCP nodelay flag */
+      loc_nodelay = 1;
+      rem_nodelay = 1;
+      break;
+    case 's':
+      /* set local socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lss_size = convert(arg1);
+      if (arg2[0])
+	lsr_size = convert(arg2);
+      break;
+    case 'S':
+      /* set remote socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rss_size = convert(arg1);
+      if (arg2[0])
+	rsr_size = convert(arg2);
+      break;
+    case 'r':
+      /* set the request/response sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	req_size = convert(arg1);
+      if (arg2[0])	
+	rsp_size = convert(arg2);
+      break;
+    case 'm':
+      /* set the send size */
+      send_size = convert(optarg);
+      break;
+    case 'M':
+      /* set the recv size */
+      recv_size = convert(optarg);
+      break;
+    case 'W':
+      /* set the "width" of the user space data */
+      /* buffer. This will be the number of */
+      /* send_size buffers malloc'd in the */
+      /* *_STREAM test. It may be enhanced to set */
+      /* both send and receive "widths" but for now */
+      /* it is just the sending *_STREAM. */
+      send_width = convert(optarg);
+      break;
+    case 'V' :
+      /* we want to do copy avoidance and will set */
+      /* it for everything, everywhere, if we really */
+      /* can. of course, we don't know anything */
+      /* about the remote... */
+#ifdef SO_SND_COPYAVOID
+      loc_sndavoid = 1;
+#else
+      loc_sndavoid = 0;
+      printf("Local send copy avoidance not available.\n");
+#endif
+#ifdef SO_RCV_COPYAVOID
+      loc_rcvavoid = 1;
+#else
+      loc_rcvavoid = 0;
+      printf("Local recv copy avoidance not available.\n");
+#endif
+      rem_sndavoid = 1;
+      rem_rcvavoid = 1;
+      break;
+    case 'X':
+      /* set the xti device file name(s) */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	strcpy(loc_xti_device,arg1);
+      if (arg2[0])
+	strcpy(rem_xti_device,arg2);
+      break;
+    };
+  }
+}
+#endif /* WANT_XTI */