auto import from //depot/cupcake/@135843
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..a0d5b80
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+L_DEFS := -DHAVE_CONFIG_H -UAF_INET6
+L_CFLAGS := $(L_DEFS)
+L_USE_CPU_SOURCE := netcpu_none.c
+
+L_COMMON_SRC := hist.h netlib.c netsh.c nettest_bsd.c nettest_dlpi.c \
+  nettest_unix.c nettest_xti.c nettest_sctp.c nettest_sdp.c
+
+netperf_SOURCES := netperf.c $(L_COMMON_SRC) $(L_USE_CPU_SOURCE)
+netserver_SOURCES := netserver.c $(L_COMMON_SRC) $(L_USE_CPU_SOURCE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := netperf
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := tests eng
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(netperf_SOURCES)
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := netserver
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := tests eng
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(netserver_SOURCES)
+include $(BUILD_EXECUTABLE)
+
diff --git a/MODULE_LICENSE_HP b/MODULE_LICENSE_HP
new file mode 100644
index 0000000..3f3ceb2
--- /dev/null
+++ b/MODULE_LICENSE_HP
@@ -0,0 +1,43 @@
+
+ 
+              Copyright (C) 1993 Hewlett-Packard Company
+                         ALL RIGHTS RESERVED.
+ 
+  The enclosed software and documentation includes copyrighted works
+  of Hewlett-Packard Co. For as long as you comply with the following
+  limitations, you are hereby authorized to (i) use, reproduce, and
+  modify the software and documentation, and to (ii) distribute the
+  software and documentation, including modifications, for
+  non-commercial purposes only.
+      
+  1.  The enclosed software and documentation is made available at no
+      charge in order to advance the general development of
+      high-performance networking products.
+ 
+  2.  You may not delete any copyright notices contained in the
+      software or documentation. All hard copies, and copies in
+      source code or object code form, of the software or
+      documentation (including modifications) must contain at least
+      one of the copyright notices.
+ 
+  3.  The enclosed software and documentation has not been subjected
+      to testing and quality control and is not a Hewlett-Packard Co.
+      product. At a future time, Hewlett-Packard Co. may or may not
+      offer a version of the software and documentation as a product.
+  
+  4.  THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS".
+      HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE,
+      REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
+      DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL
+      PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR
+      DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES,
+      EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE
+      DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF
+      MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  
+  5.  HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY
+      DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+      (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION,
+      MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION.
+ 
+
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..5c89615
--- /dev/null
+++ b/config.h
@@ -0,0 +1,351 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to one to enable dirty buffer support. May affect results. */
+/* #undef DIRTY */
+
+#undef AF_INET6
+
+/* Define to 1 if you have the `alarm' function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the `bindprocessor' function. */
+/* #undef HAVE_BINDPROCESSOR */
+
+/* Define to 1 if you have the `bind_to_cpu_id' function. */
+/* #undef HAVE_BIND_TO_CPU_ID */
+
+/* Define to 1 if you have the `bzero' function. */
+#define HAVE_BZERO 1
+
+/* Define to 1 if you have the <endian.h> header file. */
+/* #define HAVE_ENDIAN_H 1 */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethrtime' function. */
+/* #undef HAVE_GETHRTIME */
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to one to include ICSC-EXS tests. */
+/* #undef HAVE_ICSC_EXS */
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `exs' library (-lexs). */
+/* #undef HAVE_LIBEXS */
+
+/* Define to 1 if you have the `kstat' library (-lkstat). */
+/* #undef HAVE_LIBKSTAT */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the `mach' library (-lmach). */
+/* #undef HAVE_LIBMACH */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `perfstat' library (-lperfstat). */
+/* #undef HAVE_LIBPERFSTAT */
+
+/* Define to 1 if you have the `sctp' library (-lsctp). */
+/* #undef HAVE_LIBSCTP */
+
+/* Define to 1 if you have the `sdp' library (-lsdp). */
+/* #undef HAVE_LIBSDP */
+
+/* Define to 1 if you have the `sendfile' library (-lsendfile). */
+/* #undef HAVE_LIBSENDFILE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+/* #define HAVE_MALLOC_H 1 */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `mpctl' function. */
+/* #undef HAVE_MPCTL */
+
+/* Define to 1 if you have the `munmap' function. */
+#define HAVE_MUNMAP 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+/* #undef HAVE_NETINET_SCTP_H */
+
+/* Define to 1 if you have the `processor_bind' function. */
+/* #undef HAVE_PROCESSOR_BIND */
+
+/* Define to 1 if you have the `sched_setaffinity' function. */
+/* #define HAVE_SCHED_SETAFFINITY 1 */
+
+/* Define to 1 if `struct sctp_event_subscribe' has a
+   `sctp_adaptation_layer_event' member */
+/* #undef HAVE_SCTP_ADAPTATION_LAYER_EVENT */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the `sendfile' function. */
+/* #undef HAVE_SENDFILE */ 
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the `sqrt' function. */
+#define HAVE_SQRT 1
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if <netinet/in.h> defines `struct sockaddr_storage' */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if the system has the type `_Bool'. */
+#define HAVE__BOOL 1
+
+/* Define to 1 if `h_errno' is declared by <netdb.h> */
+#define H_ERRNO_DECLARED 1
+
+/* Name of package */
+#define PACKAGE "netperf"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "netperf"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "netperf 2.4.4"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "netperf"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.4.4"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type of arg 1 for `select'. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#define SELECT_TYPE_ARG234 (fd_set *)
+
+/* Define to the type of arg 5 for `select'. */
+#define SELECT_TYPE_ARG5 (struct timeval *)
+
+/* Define to 1 if the `setpgrp' function takes no argument. */
+#define SETPGRP_VOID 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Use Solaris's kstat interface to measure CPU util. */
+/* #undef USE_KSTAT */
+
+/* Use looper/soaker processes to measure CPU util. */
+/* #undef USE_LOOPER */
+
+/* Use MacOS X's host_info interface to measure CPU util. */
+/* #undef USE_OSX */
+
+/* Use AIX's perfstat interface to measure CPU util. */
+/* #undef USE_PERFSTAT */
+
+/* Use Linux's procstat interface to measure CPU util. */
+#define USE_PROC_STAT 1
+
+/* Use HP-UX's pstat interface to measure CPU util. */
+/* #undef USE_PSTAT */
+
+/* Use FreeBSD's sysctl interface to measure CPU util. */
+/* #undef USE_SYSCTL */
+
+/* Version number of package */
+#define VERSION "2.4.4"
+
+/* Define to one to enable demo support. May affect results. */
+/* #undef WANT_DEMO */
+
+/* Define to one to include DLPI tests. */
+/* #undef WANT_DLPI */
+
+/* Define to one to enable initial _RR burst support. May affect results. */
+/* #undef WANT_FIRST_BURST */
+
+/* Define to one to enable histogram support. May affect results. */
+/* #undef WANT_HISTOGRAM */
+
+/* Define to one to enable paced operation support. May affect results. */
+/* #undef WANT_INTERVALS */
+
+/* Define to one to include SCTP tests. */
+/* #define WANT_SCTP 1 */
+
+/* Define to one to include SDP tests. */
+/* #undef WANT_SDP */
+
+/* Define to one to spin waiting on paced operation. WILL AFFEFCT CPU
+   UTILIZATION */
+/* #undef WANT_SPIN */
+
+/* Define to one to include Unix Domain socket tests. */
+/* #undef WANT_UNIX */
+
+/* Define to one to include XTI tests. */
+/* #undef WANT_XTI */
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* type to use in place of socklen_t if not defined */
+#define netperf_socklen_t size_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/hist.h b/hist.h
new file mode 100644
index 0000000..b2ed22b
--- /dev/null
+++ b/hist.h
@@ -0,0 +1,116 @@
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+/* hist.h
+
+   Given a time difference in microseconds, increment one of 61
+   different buckets: 
+   
+   0 - 9 in increments of 1 usec
+   0 - 9 in increments of 10 usecs
+   0 - 9 in increments of 100 usecs
+   0 - 9 in increments of 1 msec
+   0 - 9 in increments of 10 msecs
+   0 - 9 in increments of 100 msecs
+   0 - 9 in increments of 1 sec
+   0 - 9 in increments of 10 sec
+   > 100 secs
+   
+   This will allow any time to be recorded to within an accuracy of
+   10%, and provides a compact representation for capturing the
+   distribution of a large number of time differences (e.g.
+   request-response latencies).
+   
+   Colin Low  10/6/93
+   Rick Jones 2004-06-15 - extend to 1 and 10 usec
+*/
+#ifndef _HIST_INCLUDED
+#define _HIST_INCLUDED
+
+#ifdef IRIX
+#include <sys/time.h>
+#endif /* IRIX */
+
+#if defined(HAVE_GET_HRT)
+#include "hrt.h"
+#endif
+   
+struct histogram_struct {
+  int unit_usec[10];
+  int ten_usec[10];
+  int hundred_usec[10];
+  int unit_msec[10];
+  int ten_msec[10];
+  int hundred_msec[10];
+  int unit_sec[10];
+  int ten_sec[10];
+  int ridiculous;
+  int total;
+};
+
+typedef struct histogram_struct *HIST;
+
+/* 
+   HIST_new - return a new, cleared histogram data type
+*/
+
+HIST HIST_new(void); 
+
+/* 
+   HIST_clear - reset a histogram by clearing all totals to zero
+*/
+
+void HIST_clear(HIST h);
+
+/*
+   HIST_add - add a time difference to a histogram. Time should be in
+   microseconds. 
+*/
+
+void HIST_add(register HIST h, int time_delta);
+
+/* 
+  HIST_report - create an ASCII report on the contents of a histogram.
+  Currently printsto standard out 
+*/
+
+void HIST_report(HIST h);
+
+/*
+  HIST_timestamp - take a timestamp suitable for use in a histogram.
+*/
+
+#ifdef HAVE_GETHRTIME
+void HIST_timestamp(hrtime_t *timestamp);
+#elif defined(HAVE_GET_HRT)
+void HIST_timestamp(hrt_t *timestamp);
+#elif defined(WIN32)
+void HIST_timestamp(LARGE_INTEGER *timestamp);
+#else
+void HIST_timestamp(struct timeval *timestamp);
+#endif
+
+/*
+  delta_micro - calculate the difference in microseconds between two
+  timestamps
+*/
+#ifdef HAVE_GETHRTIME
+int delta_micro(hrtime_t *begin, hrtime_t *end);
+#elif defined(HAVE_GET_HRT)
+int delta_micro(hrt_t *begin, hrt_t *end);
+#elif defined(WIN32)
+int delta_micro(LARGE_INTEGER *begin, LARGE_INTEGER *end);
+#else
+int delta_micro(struct timeval *begin, struct timeval *end);
+#endif
+
+#endif
+
diff --git a/netcpu.h b/netcpu.h
new file mode 100644
index 0000000..58d1e1c
--- /dev/null
+++ b/netcpu.h
@@ -0,0 +1,19 @@
+/* This should define all the common routines etc exported by the
+   various netcpu_mumble.c files raj 2005-01-26 */
+
+extern void  cpu_util_init(void);
+extern void  cpu_util_terminate(void);
+extern int   get_cpu_method();
+
+#ifdef WIN32
+/* +*+ temp until I figure out what header this is in; I know it's
+   there someplace...  */
+typedef unsigned __int64    uint64_t;
+#endif
+
+extern void  get_cpu_idle(uint64_t *res);
+extern float calibrate_idle_rate(int iterations, int interval);
+extern float calc_cpu_util_internal(float elapsed);
+extern void  cpu_start_internal(void);
+extern void  cpu_stop_internal(void);
+
diff --git a/netcpu_kstat.c b/netcpu_kstat.c
new file mode 100644
index 0000000..6320658
--- /dev/null
+++ b/netcpu_kstat.c
@@ -0,0 +1,415 @@
+char   netcpu_kstat_id[]="\
+@(#)netcpu_kstat.c  Version 2.4.0";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+
+#include <kstat.h>
+#include <sys/sysinfo.h>
+
+#include "netsh.h"
+#include "netlib.h"
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibrarion to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+static uint64_t  lib_start_count[MAXCPUS];
+static uint64_t  lib_end_count[MAXCPUS];
+
+static  kstat_t *cpu_ks[MAXCPUS]; /* the addresses that kstat will
+                                     need to pull the cpu info from
+                                     the kstat interface.  at least I
+                                     think that is what this is :) raj
+                                     8/2000 */  
+
+#define UPDKCID(nk,ok) \
+if (nk == -1) { \
+  perror("kstat_read "); \
+  exit(1); \
+} \
+if (nk != ok)\
+  goto kcid_changed;
+
+static kstat_ctl_t *kc = NULL;
+static kid_t kcid = 0;
+
+/* do the initial open of the kstat interface, get the chain id's all
+   straightened-out and set-up the addresses for get_kstat_idle to do
+   its thing.  liberally borrowed from the sources to TOP. raj 8/2000 */
+
+static int
+open_kstat()
+{
+  kstat_t *ks;
+  kid_t nkcid;
+  int i;
+  int changed = 0;
+  static int ncpu = 0;
+
+  kstat_named_t *kn;
+
+  if (debug) {
+    fprintf(where,"open_kstat: enter\n");
+    fflush(where);
+  }
+  
+  /*
+   * 0. kstat_open
+   */
+  
+  if (!kc)
+    {
+      kc = kstat_open();
+      if (!kc)
+        {
+          perror("kstat_open ");
+          exit(1);
+        }
+      changed = 1;
+      kcid = kc->kc_chain_id;
+    }
+#ifdef rickwasstupid
+  else {
+    fprintf(where,"open_kstat double open!\n");
+    fflush(where);
+    exit(1);
+  }
+#endif
+
+  /* keep doing it until no more changes */
+ kcid_changed:
+
+  if (debug) {
+    fprintf(where,"passing kcid_changed\n");
+    fflush(where);
+  }
+  
+  /*
+   * 1.  kstat_chain_update
+   */
+  nkcid = kstat_chain_update(kc);
+  if (nkcid)
+    {
+      /* UPDKCID will abort if nkcid is -1, so no need to check */
+      changed = 1;
+      kcid = nkcid;
+    }
+  UPDKCID(nkcid,0);
+
+  if (debug) {
+    fprintf(where,"kstat_lookup for unix/system_misc\n");
+    fflush(where);
+  }
+  
+  ks = kstat_lookup(kc, "unix", 0, "system_misc");
+  if (kstat_read(kc, ks, 0) == -1) {
+    perror("kstat_read");
+    exit(1);
+  }
+  
+  
+  if (changed) {
+    
+    /*
+     * 2. get data addresses
+     */
+    
+    ncpu = 0;
+    
+    kn = kstat_data_lookup(ks, "ncpus");
+    if (kn && kn->value.ui32 > lib_num_loc_cpus) {
+      fprintf(stderr,"number of CPU's mismatch!");
+      exit(1);
+    }
+    
+    for (ks = kc->kc_chain; ks;
+         ks = ks->ks_next)
+      {
+        if (strncmp(ks->ks_name, "cpu_stat", 8) == 0)
+          {
+            nkcid = kstat_read(kc, ks, NULL);
+            /* if kcid changed, pointer might be invalid. we'll deal
+               wtih changes at this stage, but will not accept them
+               when we are actually in the middle of reading
+               values. hopefully this is not going to be a big
+               issue. raj 8/2000 */
+            UPDKCID(nkcid, kcid);
+            
+            if (debug) {
+              fprintf(where,"cpu_ks[%d] getting %p\n",ncpu,ks);
+              fflush(where);
+            }
+
+            cpu_ks[ncpu] = ks;
+            ncpu++;
+            if (ncpu > lib_num_loc_cpus)
+              {
+                /* with the check above, would we ever hit this? */
+                fprintf(stderr, 
+                        "kstat finds too many cpus %d: should be %d\n",
+                        ncpu,lib_num_loc_cpus);
+                exit(1);
+              }
+          }
+      }
+    /* note that ncpu could be less than ncpus, but that's okay */
+    changed = 0;
+  }
+}
+
+/* return the value of the idle tick counter for the specified CPU */
+static long
+get_kstat_idle(cpu)
+     int cpu;
+{
+  cpu_stat_t cpu_stat;
+  kid_t nkcid;
+
+  if (debug) {
+    fprintf(where,
+            "get_kstat_idle reading with kc %x and ks %p\n",
+            kc,
+            cpu_ks[cpu]);
+  }
+
+  nkcid = kstat_read(kc, cpu_ks[cpu], &cpu_stat);
+  /* if kcid changed, pointer might be invalid, fail the test */
+  UPDKCID(nkcid, kcid);
+
+  return(cpu_stat.cpu_sysinfo.cpu[CPU_IDLE]);
+
+ kcid_changed:
+  perror("kcid changed midstream and I cannot deal with that!");
+  exit(1);
+}
+
+void
+cpu_util_init(void) 
+{
+  open_kstat();
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return KSTAT;
+}
+
+void
+get_cpu_idle(uint64_t *res)
+{
+
+  int i;
+
+  /* this open may be redundant */
+  open_kstat();
+
+  for (i = 0; i < lib_num_loc_cpus; i++){
+    res[i] = get_kstat_idle(i);
+  }
+  return;
+}
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+ 
+  long  
+    firstcnt[MAXCPUS],
+    secondcnt[MAXCPUS];
+
+  float 
+    elapsed,
+    temp_rate,
+    rate[MAXTIMES],
+    local_maxrate;
+
+  long  
+    sec,
+    usec;
+
+  int   
+    i,
+    j;
+  
+  struct  timeval time1, time2 ;
+  struct  timezone tz;
+  
+  if (debug) {
+    fprintf(where,"calling open_kstat from calibrate_kstat\n");
+    fflush(where);
+  }
+
+  open_kstat();
+
+  if (iterations > MAXTIMES) {
+    iterations = MAXTIMES;
+  }
+
+  local_maxrate = (float)-1.0;
+  
+  for(i = 0; i < iterations; i++) {
+    rate[i] = (float)0.0;
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      firstcnt[j] = get_kstat_idle(j);
+    }
+    gettimeofday (&time1, &tz);
+    sleep(interval);
+    gettimeofday (&time2, &tz);
+
+    if (time2.tv_usec < time1.tv_usec)
+      {
+        time2.tv_usec += 1000000;
+        time2.tv_sec -=1;
+      }
+    sec = time2.tv_sec - time1.tv_sec;
+    usec = time2.tv_usec - time1.tv_usec;
+    elapsed = (float)sec + ((float)usec/(float)1000000.0);
+    
+    if(debug) {
+      fprintf(where, "Calibration for kstat counter run: %d\n",i);
+      fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
+      fprintf(where,"\telapsed time = %g\n",elapsed);
+    }
+
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      secondcnt[j] = get_kstat_idle(j);
+      if(debug) {
+        /* I know that there are situations where compilers know about */
+        /* long long, but the library functions do not... raj 4/95 */
+        fprintf(where,
+                "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n",
+                j,
+                firstcnt[j],
+                firstcnt[j],
+                j,
+                secondcnt[j],
+                secondcnt[j]);
+      }
+      /* we assume that it would wrap no more than once. we also */
+      /* assume that the result of subtracting will "fit" raj 4/95 */
+      temp_rate = (secondcnt[j] >= firstcnt[j]) ?
+        (float)(secondcnt[j] - firstcnt[j])/elapsed : 
+          (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
+      if (temp_rate > rate[i]) rate[i] = temp_rate;
+      if(debug) {
+        fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
+        fflush(where);
+      }
+      if (local_maxrate < rate[i]) local_maxrate = rate[i];
+    }
+  }
+  if(debug) {
+    fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
+    fflush(where);
+  }
+  return local_maxrate;
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+  float correction_factor;
+  float actual_rate;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+
+    /* it would appear that on some systems, in loopback, nice is
+     *very* effective, causing the looper process to stop dead in its
+     tracks. if this happens, we need to ensure that the calculation
+     does not go south. raj 6/95 and if we run completely out of idle,
+     the same thing could in theory happen to the USE_KSTAT path. raj
+     8/2000 */ 
+    
+    if (lib_end_count[i] == lib_start_count[i]) {
+      lib_end_count[i]++;
+    }
+    
+    actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
+      (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
+      (float)(lib_end_count[i] - lib_start_count[i] +
+	      MAXLONG)/ lib_elapsed;
+    if (debug) {
+      fprintf(where,
+              "calc_cpu_util: actual_rate on processor %d is %f start %lx end %lx\n",
+              i,
+              actual_rate,
+              lib_start_count[i],
+              lib_end_count[i]);
+    }
+    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
+      lib_local_maxrate * 100;
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+  }
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  lib_local_cpu_util *= correction_factor;
+  return lib_local_cpu_util;
+
+
+}
+
+void
+cpu_start_internal(void)
+{
+  get_cpu_idle(lib_start_count);
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_idle(lib_end_count);
+}
diff --git a/netcpu_kstat10.c b/netcpu_kstat10.c
new file mode 100644
index 0000000..299e66d
--- /dev/null
+++ b/netcpu_kstat10.c
@@ -0,0 +1,559 @@
+char   netcpu_kstat10_id[]="\
+@(#)netcpu_kstat10.c (c) Copyright 2005-2007, Hewlett-Packard Company Version 2.4.3";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+
+#include <errno.h>
+
+#include <kstat.h>
+#include <sys/sysinfo.h>
+
+#include "netsh.h"
+#include "netlib.h"
+
+static kstat_ctl_t *kc = NULL;
+static kid_t kcid = 0;
+
+typedef struct cpu_time_counters {
+  uint64_t idle;
+  uint64_t user;
+  uint64_t kernel;
+  uint64_t interrupt;
+} cpu_time_counters_t;
+
+static cpu_time_counters_t starting_cpu_counters[MAXCPUS];
+static cpu_time_counters_t ending_cpu_counters[MAXCPUS];
+static cpu_time_counters_t delta_cpu_counters[MAXCPUS];
+static cpu_time_counters_t corrected_cpu_counters[MAXCPUS];
+
+static void
+print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters) 
+{
+  fprintf(where,"%s[%d]:\n",name,instance);
+  fprintf(where,
+	  "\t idle %llu\n",counters[instance].idle);
+  fprintf(where,
+	  "\t user %llu\n",counters[instance].user);
+  fprintf(where,
+	  "\t kernel %llu\n",counters[instance].kernel);
+  fprintf(where,
+	  "\t interrupt %llu\n",counters[instance].interrupt);
+}
+
+void
+cpu_util_init(void) 
+{
+  kc = kstat_open();
+
+  if (kc == NULL) {
+    fprintf(where,
+	    "cpu_util_init: kstat_open: errno %d %s\n",
+	    errno,
+	    strerror(errno));
+    fflush(where);
+    exit(-1);
+  }
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  kstat_close(kc);
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return KSTAT_10;
+}
+
+static void
+print_unexpected_statistic_warning(char *who, char *what, char *why)
+{
+  if (why) {
+    fprintf(where,
+	    "WARNING! WARNING! WARNING! WARNING!\n");
+    fprintf(where,
+	    "%s found an unexpected %s statistic %.16s\n",
+	    who,
+	    why,
+	    what);
+  }
+  else {
+    fprintf(where,
+	    "%s is ignoring statistic %.16s\n",
+	    who,
+	    what);
+  }
+}
+
+static void
+get_cpu_counters(int cpu_num, cpu_time_counters_t *counters)
+{
+
+  kstat_t *ksp;
+  int found=0;
+  kid_t nkcid;
+  kstat_named_t *knp;
+  int i;
+
+  ksp = kstat_lookup(kc, "cpu", cpu_num, "sys");
+  if ((ksp) && (ksp->ks_type == KSTAT_TYPE_NAMED)) {
+    /* happiness and joy, keep going */
+    nkcid = kstat_read(kc, ksp, NULL);
+    if (nkcid != -1) {
+      /* happiness and joy, keep going. we could consider adding a
+	 "found < 3" to the end conditions, but then we wouldn't
+	 search to the end and find that Sun added some nsec. we
+	 probably want to see if they add an nsec. raj 2005-01-28 */
+      for (i = ksp->ks_ndata, knp = ksp->ks_data;
+	   i > 0;
+	   knp++,i--) {
+	/* we would be hosed if the same name could appear twice */
+	if (!strcmp("cpu_nsec_idle",knp->name)) {
+	  found++;
+	  counters[cpu_num].idle = knp->value.ui64;
+	}
+	else if (!strcmp("cpu_nsec_user",knp->name)) {
+	  found++;
+	  counters[cpu_num].user = knp->value.ui64;
+	}
+	else if (!strcmp("cpu_nsec_kernel",knp->name)) {
+	  found++;
+	  counters[cpu_num].kernel = knp->value.ui64;
+	}
+	else if (strstr(knp->name,"nsec")) {
+	  /* finding another nsec here means Sun have changed
+	     something and we need to warn the user. raj 2005-01-28 */ 
+	  print_unexpected_statistic_warning("get_cpu_counters",
+					     knp->name,
+					     "nsec");
+	}
+	else if (debug >=2) {
+
+	  /* might want to tell people about what we are skipping.
+	     however, only display other names debug >=2. raj
+	     2005-01-28
+	  */
+
+	  print_unexpected_statistic_warning("get_cpu_counters",
+					     knp->name,
+					     NULL);
+	}
+      }
+      if (3 == found) {
+	/* happiness and joy */
+	return;
+      }
+      else {
+	fprintf(where,
+		"get_cpu_counters could not find one or more of the expected counters!\n");
+	fflush(where);
+	exit(-1);
+      }
+    }
+    else {
+      /* the kstat_read returned an error or the chain changed */
+      fprintf(where,
+	      "get_cpu_counters: kstat_read failed or chain id changed %d %s\n",
+	      errno,
+	      strerror(errno));
+      fflush(where);
+      exit(-1);
+    }
+  }
+  else {
+    /* the lookup failed or found the wrong type */
+    fprintf(where,
+	    "get_cpu_counters: kstat_lookup failed for module 'cpu' instance %d name 'sys' and KSTAT_TYPE_NAMED: errno %d %s\n",
+	    cpu_num,
+	    errno,
+	    strerror(errno));
+    fflush(where);
+    exit(-1);
+  }
+}
+
+static void
+get_interrupt_counters(int cpu_num, cpu_time_counters_t *counters)
+{
+  kstat_t *ksp;
+  int found=0;
+  kid_t nkcid;
+  kstat_named_t *knp;
+  int i;
+
+  ksp = kstat_lookup(kc, "cpu", cpu_num, "intrstat");
+
+  counters[cpu_num].interrupt = 0;
+  if ((ksp) && (ksp->ks_type == KSTAT_TYPE_NAMED)) {
+    /* happiness and joy, keep going */
+    nkcid = kstat_read(kc, ksp, NULL);
+    if (nkcid != -1) {
+      /* happiness and joy, keep going. we could consider adding a
+	 "found < 15" to the end conditions, but then we wouldn't
+	 search to the end and find that Sun added some "time." we
+	 probably want to see if they add a "nsec." raj 2005-01-28 */
+      for (i = ksp->ks_ndata, knp = ksp->ks_data;
+	   i > 0;
+	   knp++,i--) {
+	if (strstr(knp->name,"time")) {
+	  found++;
+	  counters[cpu_num].interrupt += knp->value.ui64;
+	}
+	else if (debug >=2) {
+
+	  /* might want to tell people about what we are skipping.
+	     however, only display other names debug >=2. raj
+	     2005-01-28
+	  */
+
+	  print_unexpected_statistic_warning("get_cpu_counters",
+					     knp->name,
+					     NULL);
+	}
+      }
+      if (15 == found) {
+	/* happiness and joy */
+	return;
+      }
+      else {
+	fprintf(where,
+		"get_cpu_counters could not find one or more of the expected counters!\n");
+	fflush(where);
+	exit(-1);
+      }
+    }
+    else {
+      /* the kstat_read returned an error or the chain changed */
+      fprintf(where,
+	      "get_cpu_counters: kstat_read failed or chain id changed %d %s\n",
+	      errno,
+	      strerror(errno));
+      fflush(where);
+      exit(-1);
+    }
+  }
+  else {
+    /* the lookup failed or found the wrong type */
+    fprintf(where,
+	    "get_cpu_counters: kstat_lookup failed for module 'cpu' instance %d class 'intrstat' and KSTAT_TYPE_NAMED: errno %d %s\n",
+	    cpu_num,
+	    errno,
+	    strerror(errno));
+    fflush(where);
+    exit(-1);
+  }
+
+}
+
+static void
+get_cpu_time_counters(cpu_time_counters_t *counters)
+{
+
+  int i;
+
+  for (i = 0; i < lib_num_loc_cpus; i++){
+    get_cpu_counters(i, counters);
+    get_interrupt_counters(i, counters);
+  }
+
+  return;
+}
+
+/* the kstat10 mechanism, since it is based on actual nanosecond
+   counters is not going to use a comparison to an idle rate. so, the
+   calibrate_idle_rate routine will be rather simple :) raj 2005-01-28
+   */ 
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  return 0.0;
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+  float correction_factor;
+  float actual_rate;
+  
+  uint64_t total_cpu_nsec;
+
+  /* multiply by 100 and divide by total and you get whole
+     percentages. multiply by 1000 and divide by total and you get
+     tenths of percentages.  multiply by 10000 and divide by total and
+     you get hundredths of percentages. etc etc etc raj 2005-01-28 */
+
+#define CALC_PERCENT 100
+#define CALC_TENTH_PERCENT 1000
+#define CALC_HUNDREDTH_PERCENT 10000
+#define CALC_THOUSANDTH_PERCENT 100000
+#define CALC_ACCURACY CALC_THOUSANDTH_PERCENT
+  
+  uint64_t fraction_idle;
+  uint64_t fraction_user;
+  uint64_t fraction_kernel;
+  uint64_t fraction_interrupt;
+
+  uint64_t interrupt_idle;
+  uint64_t interrupt_user;
+  uint64_t interrupt_kernel;
+
+  lib_local_cpu_util = (float)0.0;
+
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+
+    /* this is now the fun part.  we have the nanoseconds _allegedly_
+       spent in user, idle and kernel.  We also have nanoseconds spent
+       servicing interrupts.  Sadly, in the developer's finite wisdom,
+       the interrupt time accounting is in parallel with the other
+       accounting. this means that time accounted in user, kernel or
+       idle will also include time spent in interrupt.  for netperf's
+       porpoises we do not really care about that for user and kernel,
+       but we certainly do care for idle.  the $64B question becomes -
+       how to "correct" for this?
+
+       we could just subtract interrupt time from idle.  that has the
+       virtue of simplicity and also "punishes" Sun for doing
+       something that seems to be so stupid.  however, we probably
+       have to be "fair" even to the allegedly stupid so the other
+       mechanism, suggested by a Sun engineer is to subtract interrupt
+       time from each of user, kernel and idle in proportion to their
+       numbers.  then we sum the corrected user, kernel and idle along
+       with the interrupt time and use that to calculate a new idle
+       percentage and thus a CPU util percentage.
+
+       that is what we will attempt to do here.  raj 2005-01-28 
+
+       of course, we also have to wonder what we should do if there is
+       more interrupt time than the sum of user, kernel and idle.
+       that is a theoretical possibility I suppose, but for the
+       time-being, one that we will blythly ignore, except perhaps for
+       a quick check. raj 2005-01-31 
+    */
+    
+    /* we ass-u-me that these counters will never wrap during a
+       netperf run.  this may not be a particularly safe thing to
+       do. raj 2005-01-28 */
+    delta_cpu_counters[i].idle = ending_cpu_counters[i].idle -
+      starting_cpu_counters[i].idle;
+    delta_cpu_counters[i].user = ending_cpu_counters[i].user -
+      starting_cpu_counters[i].user;
+    delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel -
+      starting_cpu_counters[i].kernel;
+    delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt -
+      starting_cpu_counters[i].interrupt;
+    
+    if (debug) {
+      print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters);
+    }
+
+    /* for this summation, we do not include interrupt time */
+    total_cpu_nsec = 
+      delta_cpu_counters[i].idle +
+      delta_cpu_counters[i].user +
+      delta_cpu_counters[i].kernel;
+
+    if (debug) {
+      fprintf(where,"total_cpu_nsec %llu\n",total_cpu_nsec);
+    }
+
+    if (delta_cpu_counters[i].interrupt > total_cpu_nsec) {
+      /* we are not in Kansas any more Toto, and I am not quite sure
+	 the best way to get our tails out of here so let us just
+	 punt. raj 2005-01-31 */
+      fprintf(where,
+	      "WARNING! WARNING! WARNING! WARNING! WARNING! \n");
+      fprintf(where,
+	      "calc_cpu_util_internal: more interrupt time than others combined!\n");
+      fprintf(where,
+	      "\tso CPU util cannot be estimated\n");
+      fprintf(where,
+	      "\t delta[%d].interrupt %llu\n",i,delta_cpu_counters[i].interrupt);
+      fprintf(where,
+	      "\t delta[%d].idle %llu\n",i,delta_cpu_counters[i].idle);
+      fprintf(where,
+	      "\t delta[%d].user %llu\n",i,delta_cpu_counters[i].user);
+      fprintf(where,
+	      "\t delta[%d].kernel %llu\n",i,delta_cpu_counters[i].kernel);
+      fflush(where);
+      
+      lib_local_cpu_util = -1.0;
+      lib_local_per_cpu_util[i] = -1.0;
+      return -1.0;
+    }
+
+    /* and now some fun with integer math.  i initially tried to
+       promote things to long doubled but that didn't seem to result
+       in happiness and joy. raj 2005-01-28 */
+
+    fraction_idle = 
+      (delta_cpu_counters[i].idle * CALC_ACCURACY) / total_cpu_nsec;
+
+    fraction_user = 
+      (delta_cpu_counters[i].user * CALC_ACCURACY) / total_cpu_nsec;
+
+    fraction_kernel = 
+      (delta_cpu_counters[i].kernel * CALC_ACCURACY) / total_cpu_nsec;
+
+    /* ok, we have our fractions, now we want to take that fraction of
+       the interrupt time and subtract that from the bucket. */
+
+    interrupt_idle =  ((delta_cpu_counters[i].interrupt * fraction_idle) / 
+		       CALC_ACCURACY);
+
+    interrupt_user = ((delta_cpu_counters[i].interrupt * fraction_user) / 
+		      CALC_ACCURACY);
+
+    interrupt_kernel = ((delta_cpu_counters[i].interrupt * fraction_kernel) / 
+			CALC_ACCURACY);
+
+    if (debug) {
+      fprintf(where,
+	      "\tfraction_idle %llu interrupt_idle %llu\n",
+	      fraction_idle,
+	      interrupt_idle);
+      fprintf(where,
+	      "\tfraction_user %llu interrupt_user %llu\n",
+	      fraction_user,
+	      interrupt_user);
+      fprintf(where,"\tfraction_kernel %llu interrupt_kernel %llu\n",
+	      fraction_kernel,
+	      interrupt_kernel);
+    }
+
+    corrected_cpu_counters[i].idle = delta_cpu_counters[i].idle - 
+      interrupt_idle;
+
+    corrected_cpu_counters[i].user = delta_cpu_counters[i].user - 
+      interrupt_user;
+
+    corrected_cpu_counters[i].kernel = delta_cpu_counters[i].kernel - 
+      interrupt_kernel;
+
+    corrected_cpu_counters[i].interrupt = delta_cpu_counters[i].interrupt;
+		  
+    if (debug) {
+      print_cpu_time_counters("corrected_cpu_counters",
+			      i,
+			      corrected_cpu_counters);
+    }
+
+    /* I was going to checkfor going less than zero, but since all the
+       calculations are in unsigned quantities that would seem to be a
+       triffle silly... raj 2005-01-28 */
+
+    /* ok, now we sum the numbers again, this time including interrupt
+       */
+
+    total_cpu_nsec = 
+      corrected_cpu_counters[i].idle +
+      corrected_cpu_counters[i].user +
+      corrected_cpu_counters[i].kernel +
+      corrected_cpu_counters[i].interrupt;
+
+    /* and recalculate our fractions we are really only going to use
+       fraction_idle, but lets calculate the rest just for the heck of
+       it. one day we may want to display them. raj 2005-01-28 */
+    
+    /* multiply by 100 and divide by total and you get whole
+       percentages. multiply by 1000 and divide by total and you get
+       tenths of percentages.  multiply by 10000 and divide by total
+       and you get hundredths of percentages. etc etc etc raj
+       2005-01-28 */
+    fraction_idle = 
+      (corrected_cpu_counters[i].idle * CALC_ACCURACY) / total_cpu_nsec;
+
+    fraction_user = 
+      (corrected_cpu_counters[i].user * CALC_ACCURACY) / total_cpu_nsec;
+
+    fraction_kernel = 
+      (corrected_cpu_counters[i].kernel * CALC_ACCURACY) / total_cpu_nsec;
+
+    fraction_interrupt = 
+      (corrected_cpu_counters[i].interrupt * CALC_ACCURACY) / total_cpu_nsec;
+
+    if (debug) {
+      fprintf(where,"\tfraction_idle %lu\n",fraction_idle);
+      fprintf(where,"\tfraction_user %lu\n",fraction_user);
+      fprintf(where,"\tfraction_kernel %lu\n",fraction_kernel);
+      fprintf(where,"\tfraction_interrupt %lu\n",fraction_interrupt);
+    }
+
+    /* and finally, what is our CPU utilization? */
+    lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle / 
+					  (float)CALC_ACCURACY) * 100.0);
+    if (debug) {
+      fprintf(where,
+	      "lib_local_per_cpu_util[%d] %g\n",
+	      i,
+	      lib_local_per_cpu_util[i]);
+    }
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+  }
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  lib_local_cpu_util *= correction_factor;
+  return lib_local_cpu_util;
+
+
+}
+
+void
+cpu_start_internal(void)
+{
+  get_cpu_time_counters(starting_cpu_counters);
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_time_counters(ending_cpu_counters);
+}
diff --git a/netcpu_looper.c b/netcpu_looper.c
new file mode 100644
index 0000000..b76c7c9
--- /dev/null
+++ b/netcpu_looper.c
@@ -0,0 +1,656 @@
+char   netcpu_looper_id[]="\
+@(#)netcpu_looper.c (c) Copyright 2005-2007. Version 2.4.3";
+
+/* netcpu_looper.c
+  
+   Implement the soaker process specific portions of netperf CPU
+   utilization measurements. These are broken-out into a separate file
+   to make life much nicer over in netlib.c which had become a maze of
+   twisty, CPU-util-related, #ifdefs, all different.  raj 2005-01-26
+   */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if defined(HAVE_MMAP) || defined(HAVE_SYS_MMAN_H)
+# include <sys/mman.h>
+#else
+# error netcpu_looper requires mmap
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "netsh.h"
+#include "netlib.h"
+
+#define PAGES_PER_CHILD 2
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibrarion to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+static uint64_t  lib_start_count[MAXCPUS];
+static uint64_t  lib_end_count[MAXCPUS];
+
+static int *cpu_mappings;
+
+static int lib_idle_fd;
+static uint64_t *lib_idle_address[MAXCPUS];
+static long     *lib_base_pointer;
+static pid_t     lib_idle_pids[MAXCPUS];
+static int       lib_loopers_running=0;
+
+/* we used to use this code to bind the loopers, but since we have
+   decided to enable processor affinity for the actual
+   netperf/netserver processes we will use that affinity routine,
+   which happens to know about more systems than this */
+
+#ifdef NOTDEF
+static void
+bind_to_processor(int child_num)
+{
+  /* This routine will bind the calling process to a particular */
+  /* processor. We are not choosy as to which processor, so it will be */
+  /* the process id mod the number of processors - shifted by one for */
+  /* those systems which name processor starting from one instead of */
+  /* zero. on those systems where I do not yet know how to bind a */
+  /* process to a processor, this routine will be a no-op raj 10/95 */
+
+  /* just as a reminder, this is *only* for the looper processes, not */
+  /* the actual measurement processes. those will, should, MUST float */
+  /* or not float from CPU to CPU as controlled by the operating */
+  /* system defaults. raj 12/95 */
+
+#ifdef __hpux
+#include <sys/syscall.h>
+#include <sys/mp.h>
+
+  int old_cpu = -2;
+
+  if (debug) {
+    fprintf(where,
+            "child %d asking for CPU %d as pid %d with %d CPUs\n",
+            child_num,
+            (child_num % lib_num_loc_cpus),
+            getpid(),
+            lib_num_loc_cpus);
+    fflush(where);
+  }
+
+  SETPROCESS((child_num % lib_num_loc_cpus), getpid());
+  return;
+
+#else
+#if defined(__sun) && defined(__SVR4)
+ /* should only be Solaris */
+#include <sys/processor.h>
+#include <sys/procset.h>
+
+  int old_binding;
+
+  if (debug) {
+    fprintf(where,
+            "bind_to_processor: child %d asking for CPU %d as pid %d with %d CPUs\n",
+            child_num,
+            (child_num % lib_num_loc_cpus),
+            getpid(),
+            lib_num_loc_cpus);
+    fflush(where);
+  }
+
+  if (processor_bind(P_PID,
+                     getpid(),
+                     (child_num % lib_num_loc_cpus), 
+                      &old_binding) != 0) {
+    fprintf(where,"bind_to_processor: unable to perform processor binding\n");
+    fprintf(where,"                   errno %d\n",errno);
+    fflush(where);
+  }
+  return;
+#else
+#ifdef WIN32
+
+  if (!SetThreadAffinityMask(GetCurrentThread(), (ULONG_PTR)1 << (child_num % lib_num_loc_cpus))) {
+    perror("SetThreadAffinityMask failed");
+    fflush(stderr);
+  }
+
+  if (debug) {
+    fprintf(where,
+            "bind_to_processor: child %d asking for CPU %d of %d CPUs\n",
+            child_num,
+            (child_num % lib_num_loc_cpus),
+            lib_num_loc_cpus);
+    fflush(where);
+  }
+
+#endif
+  return;
+#endif /* __sun && _SVR4 */
+#endif /* __hpux */
+}
+#endif
+
+ /* sit_and_spin will just spin about incrementing a value */
+ /* this value will either be in a memory mapped region on Unix shared */
+ /* by each looper process, or something appropriate on Windows/NT */
+ /* (malloc'd or such). This routine is reasonably ugly in that it has */
+ /* priority manipulating code for lots of different operating */
+ /* systems. This routine never returns. raj 1/96 */ 
+
+static void
+sit_and_spin(int child_index)
+
+{
+  uint64_t *my_counter_ptr;
+
+ /* only use C stuff if we are not WIN32 unless and until we */
+ /* switch from CreateThread to _beginthread. raj 1/96 */
+#ifndef WIN32
+  /* we are the child. we could decide to exec some separate */
+  /* program, but that doesn't really seem worthwhile - raj 4/95 */
+  if (debug > 1) {
+    fprintf(where,
+            "Looper child %d is born, pid %d\n",
+            child_index,
+            getpid());
+    fflush(where);
+  }
+  
+#endif /* WIN32 */
+
+  /* reset our base pointer to be at the appropriate offset */
+  my_counter_ptr = (uint64_t *) ((char *)lib_base_pointer + 
+                             (netlib_get_page_size() * 
+                              PAGES_PER_CHILD * child_index));
+  
+  /* in the event we are running on an MP system, it would */
+  /* probably be good to bind the soaker processes to specific */
+  /* processors. I *think* this is the most reasonable thing to */
+  /* do, and would be closes to simulating the information we get */
+  /* on HP-UX with pstat. I could put all the system-specific code */
+  /* here, but will "abstract it into another routine to keep this */
+  /* area more readable. I'll probably do the same thine with the */
+  /* "low pri code" raj 10/95 */
+  
+  /* since we are "flying blind" wrt where we should bind the looper
+     processes, we want to use the cpu_map that was prepared by netlib
+     rather than assume that the CPU ids on the system start at zero
+     and are contiguous. raj 2006-04-03 */
+  bind_to_specific_processor(child_index % lib_num_loc_cpus,1);
+  
+  for (*my_counter_ptr = 0L;
+       ;
+       (*my_counter_ptr)++) {
+    if (!(*lib_base_pointer % 1)) {
+      /* every once and again, make sure that our process priority is */
+      /* nice and low. also, by making system calls, it may be easier */
+      /* for us to be pre-empted by something that needs to do useful */
+      /* work - like the thread of execution actually sending and */
+      /* receiving data across the network :) */
+#ifdef _AIX
+      int pid,prio;
+
+      prio = PRIORITY;
+      pid = getpid();
+      /* if you are not root, this call will return EPERM - why one */
+      /* cannot change one's own priority to  lower value is beyond */
+      /* me. raj 2/26/96 */  
+      setpri(pid, prio);
+#else /* _AIX */
+#ifdef __sgi
+      int pid,prio;
+
+      prio = PRIORITY;
+      pid = getpid();
+      schedctl(NDPRI, pid, prio);
+      sginap(0);
+#else /* __sgi */
+#ifdef WIN32
+      SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE);
+#else /* WIN32 */
+#if defined(__sun) && defined(__SVR4)
+#include <sys/types.h>
+#include <sys/priocntl.h>
+#include <sys/rtpriocntl.h>
+#include <sys/tspriocntl.h>
+      /* I would *really* like to know how to use priocntl to make the */
+      /* priority low for this looper process. however, either my mind */
+      /* is addled, or the manpage in section two for priocntl is not */
+      /* terribly helpful - for one, it has no examples :( so, if you */
+      /* can help, I'd love to hear from you. in the meantime, we will */
+      /* rely on nice(39). raj 2/26/96 */
+      nice(39);
+#else /* __sun && __SVR4 */
+      nice(39);
+#endif /* __sun && _SVR4 */
+#endif /* WIN32 */
+#endif /* __sgi */
+#endif /* _AIX */
+    }
+  }
+}
+
+
+
+ /* this routine will start all the looper processes or threads for */
+ /* measuring CPU utilization. */
+
+static void
+start_looper_processes()
+{
+
+  unsigned int      i, file_size;
+  
+  /* we want at least two pages for each processor. the */
+  /* child for any one processor will write to the first of his two */
+  /* pages, and the second page will be a buffer in case there is page */
+  /* prefetching. if your system pre-fetches more than a single page, */
+  /* well, you'll have to modify this or live with it :( raj 4/95 */
+
+  file_size = ((netlib_get_page_size() * PAGES_PER_CHILD) * 
+               lib_num_loc_cpus);
+  
+#ifndef WIN32
+
+  /* we we are not using WINDOWS NT (or 95 actually :), then we want */
+  /* to create a memory mapped region so we can see all the counting */
+  /* rates of the loopers */
+
+  /* could we just use an anonymous memory region for this? it is */
+  /* possible that using a mmap()'ed "real" file, while convenient for */
+  /* debugging, could result in some filesystem activity - like */
+  /* metadata updates? raj 4/96 */
+  lib_idle_fd = open("/tmp/netperf_cpu",O_RDWR | O_CREAT | O_EXCL);
+  
+  if (lib_idle_fd == -1) {
+    fprintf(where,"create_looper: file creation; errno %d\n",errno);
+    fflush(where);
+    exit(1);
+  }
+  
+  if (chmod("/tmp/netperf_cpu",0644) == -1) {
+    fprintf(where,"create_looper: chmod; errno %d\n",errno);
+    fflush(where);
+    exit(1);
+  }
+  
+  /* with the file descriptor in place, lets be sure that the file is */
+  /* large enough. */
+  
+  if (truncate("/tmp/netperf_cpu",file_size) == -1) {
+    fprintf(where,"create_looper: truncate: errno %d\n",errno);
+    fflush(where);
+    exit(1);
+  }
+  
+  /* the file should be large enough now, so we can mmap it */
+  
+  /* if the system does not have MAP_VARIABLE, just define it to */
+  /* be zero. it is only used/needed on HP-UX (?) raj 4/95 */
+#ifndef MAP_VARIABLE
+#define MAP_VARIABLE 0x0000
+#endif /* MAP_VARIABLE */
+#ifndef MAP_FILE
+#define MAP_FILE 0x0000
+#endif /* MAP_FILE */
+  if ((lib_base_pointer = (long *)mmap(NULL,
+                                       file_size,
+                                       PROT_READ | PROT_WRITE,
+                                       MAP_FILE | MAP_SHARED | MAP_VARIABLE,
+                                       lib_idle_fd,
+                                       0)) == (long *)-1) {
+    fprintf(where,"create_looper: mmap: errno %d\n",errno);
+    fflush(where);
+    exit(1);
+  }
+  
+
+  if (debug > 1) {
+    fprintf(where,"num CPUs %d, file_size %d, lib_base_pointer %p\n",
+            lib_num_loc_cpus,
+            file_size,
+            lib_base_pointer);
+    fflush(where);
+  }
+
+  /* we should have a valid base pointer. lets fork */
+  
+  for (i = 0; i < (unsigned int)lib_num_loc_cpus; i++) {
+    switch (lib_idle_pids[i] = fork()) {
+    case -1:
+      perror("netperf: fork");
+      exit(1);
+    case 0:
+      /* we are the child. we could decide to exec some separate */
+      /* program, but that doesn't really seem worthwhile - raj 4/95 */
+
+      signal(SIGTERM, SIG_DFL);
+      sit_and_spin(i);
+
+      /* we should never really get here, but if we do, just exit(0) */
+      exit(0);
+      break;
+    default:
+      /* we must be the parent */
+      lib_idle_address[i] = (uint64_t *) ((char *)lib_base_pointer + 
+                                      (netlib_get_page_size() * 
+                                       PAGES_PER_CHILD * i));
+      if (debug) {
+        fprintf(where,"lib_idle_address[%d] is %p\n",
+                i,
+                lib_idle_address[i]);
+        fflush(where);
+      }
+    }
+  }
+#else
+  /* we are compiled -DWIN32 */
+  if ((lib_base_pointer = malloc(file_size)) == NULL) {
+    fprintf(where,
+            "create_looper_process could not malloc %d bytes\n",
+            file_size);
+    fflush(where);
+    exit(1);
+  }
+
+  /* now, create all the threads */
+  for(i = 0; i < (unsigned int)lib_num_loc_cpus; i++) {
+    long place_holder;
+    if ((lib_idle_pids[i] = CreateThread(0,
+                                         0,
+                                         (LPTHREAD_START_ROUTINE)sit_and_spin,
+                                         (LPVOID)(ULONG_PTR)i,
+                                         0,
+                                         &place_holder)) == NULL ) {
+      fprintf(where,
+              "create_looper_process: CreateThread failed\n");
+      fflush(where);
+      /* I wonder if I need to look for other threads to kill? */
+      exit(1);
+    }
+    lib_idle_address[i] = (long *) ((char *)lib_base_pointer + 
+                                    (netlib_get_page_size() * 
+                                     PAGES_PER_CHILD * i));
+    if (debug) {
+      fprintf(where,"lib_idle_address[%d] is %p\n",
+              i,
+              lib_idle_address[i]);
+      fflush(where);
+    }
+  }
+#endif /* WIN32 */
+
+  /* we need to have the looper processes settled-in before we do */
+  /* anything with them, so lets sleep for say 30 seconds. raj 4/95 */
+
+  sleep(30);
+}
+
+void
+cpu_util_init(void) 
+{
+  cpu_method = LOOPER;
+
+  /* we want to get the looper processes going */
+  if (!lib_loopers_running) {
+    start_looper_processes();
+    lib_loopers_running = 1;
+  }
+
+  return;
+}
+
+/* clean-up any left-over CPU util resources - looper processes,
+   files, whatever.  raj 2005-01-26 */
+void
+cpu_util_terminate() {
+
+#ifdef WIN32
+  /* it would seem that if/when the process exits, all the threads */
+  /* will go away too, so I don't think I need any explicit thread */
+  /* killing calls here. raj 1/96 */
+#else
+
+  int i;
+
+  /* now go through and kill-off all the child processes */
+  for (i = 0; i < lib_num_loc_cpus; i++){
+    /* SIGKILL can leave core files behind - thanks to Steinar Haug */
+    /* for pointing that out. */
+    kill(lib_idle_pids[i],SIGTERM);
+  }
+  lib_loopers_running = 0;
+  /* reap the children */
+  while(waitpid(-1, NULL, WNOHANG) > 0) { }
+  
+  /* finally, unlink the mmaped file */
+  munmap((caddr_t)lib_base_pointer,
+         ((netlib_get_page_size() * PAGES_PER_CHILD) * 
+          lib_num_loc_cpus));
+  unlink("/tmp/netperf_cpu");
+#endif
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return LOOPER;
+}
+
+ /* calibrate_looper */
+
+ /* Loop a number of iterations, sleeping interval seconds each and */
+ /* count how high the idle counter gets each time. Return  the */
+ /* measured cpu rate to the calling routine. raj 4/95 */
+
+float
+calibrate_idle_rate (int iterations, int interval)
+{
+
+  uint64_t
+    firstcnt[MAXCPUS],
+    secondcnt[MAXCPUS];
+
+  float 
+    elapsed,
+    temp_rate,
+    rate[MAXTIMES],
+    local_maxrate;
+
+  long  
+    sec,
+    usec;
+
+  int   
+    i,
+    j;
+  
+  struct  timeval time1, time2 ;
+  struct  timezone tz;
+  
+  if (iterations > MAXTIMES) {
+    iterations = MAXTIMES;
+  }
+
+  local_maxrate = (float)-1.0;
+  
+  for(i = 0; i < iterations; i++) {
+    rate[i] = (float)0.0;
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      firstcnt[j] = *(lib_idle_address[j]);
+    }
+    gettimeofday (&time1, &tz);
+    sleep(interval);
+    gettimeofday (&time2, &tz);
+
+    if (time2.tv_usec < time1.tv_usec)
+      {
+        time2.tv_usec += 1000000;
+        time2.tv_sec -=1;
+      }
+    sec = time2.tv_sec - time1.tv_sec;
+    usec = time2.tv_usec - time1.tv_usec;
+    elapsed = (float)sec + ((float)usec/(float)1000000.0);
+    
+    if(debug) {
+      fprintf(where, "Calibration for counter run: %d\n",i);
+      fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
+      fprintf(where,"\telapsed time = %g\n",elapsed);
+    }
+
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      secondcnt[j] = *(lib_idle_address[j]);
+      if(debug) {
+        /* I know that there are situations where compilers know about */
+        /* long long, but the library fucntions do not... raj 4/95 */
+        fprintf(where,
+                "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n",
+                j,
+                (uint32_t)(firstcnt[j]>>32),
+                (uint32_t)(firstcnt[j]&0xffffffff),
+                j,
+                (uint32_t)(secondcnt[j]>>32),
+                (uint32_t)(secondcnt[j]&0xffffffff));
+      }
+      /* we assume that it would wrap no more than once. we also */
+      /* assume that the result of subtracting will "fit" raj 4/95 */
+      temp_rate = (secondcnt[j] >= firstcnt[j]) ?
+        (float)(secondcnt[j] - firstcnt[j])/elapsed : 
+          (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
+      if (temp_rate > rate[i]) rate[i] = temp_rate;
+      if(debug) {
+        fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
+        fflush(where);
+      }
+      if (local_maxrate < rate[i]) local_maxrate = rate[i];
+    }
+  }
+  if(debug) {
+    fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
+    fflush(where);
+  }
+  return local_maxrate;
+}
+
+
+void
+get_cpu_idle (uint64_t *res)
+{
+  int i;
+
+  for (i = 0; i < lib_num_loc_cpus; i++){
+    res[i] = *lib_idle_address[i];
+  }
+
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+  float correction_factor;
+  float actual_rate;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+
+    /* it would appear that on some systems, in loopback, nice is
+     *very* effective, causing the looper process to stop dead in its
+     tracks. if this happens, we need to ensure that the calculation
+     does not go south. raj 6/95 and if we run completely out of idle,
+     the same thing could in theory happen to the USE_KSTAT path. raj
+     8/2000 */ 
+    
+    if (lib_end_count[i] == lib_start_count[i]) {
+      lib_end_count[i]++;
+    }
+    
+    actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
+      (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
+      (float)(lib_end_count[i] - lib_start_count[i] +
+	      MAXLONG)/ lib_elapsed;
+    if (debug) {
+      fprintf(where,
+              "calc_cpu_util: actual_rate on processor %d is %f start 0x%8.8lx%8.8lx end 0x%8.8lx%8.8lx\n",
+              i,
+              actual_rate,
+              (uint32_t)(lib_start_count[i]>>32),
+              (uint32_t)(lib_start_count[i]&0xffffffff),
+              (uint32_t)(lib_end_count[i]>>32),
+              (uint32_t)(lib_end_count[i]&0xffffffff));
+    }
+    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
+      lib_local_maxrate * 100;
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+  }
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  lib_local_cpu_util *= correction_factor;
+  return lib_local_cpu_util;
+
+
+}
+void
+cpu_start_internal(void)
+{
+  get_cpu_idle(lib_start_count);
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_idle(lib_end_count);
+}
diff --git a/netcpu_none.c b/netcpu_none.c
new file mode 100644
index 0000000..f71b240
--- /dev/null
+++ b/netcpu_none.c
@@ -0,0 +1,67 @@
+char   netcpu_none_id[]="\
+@(#)netcpu_none.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#include "netsh.h"
+#include "netlib.h"
+
+void
+cpu_util_init(void) 
+{
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return CPU_UNKNOWN;
+}
+
+void
+get_cpu_idle(uint64_t *res)
+{
+  return;
+}
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  return 0.0;
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  return -1.0;
+}
+
+void
+cpu_start_internal(void)
+{
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  return;
+}
diff --git a/netcpu_ntperf.c b/netcpu_ntperf.c
new file mode 100644
index 0000000..e8d8f76
--- /dev/null
+++ b/netcpu_ntperf.c
@@ -0,0 +1,497 @@
+char   netcpu_ntperf_id[]="\
+@(#)netcpu_ntperf.c (c) Copyright 2005-2007, Hewlett-Packard Company, Version 2.4.3";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if 0
+#include <limits.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#endif
+
+#include <assert.h>
+
+#include <process.h>
+#include <time.h>
+
+#include <windows.h>
+#include <assert.h>
+
+#include <winsock2.h>
+// If you are trying to compile on Windows 2000 or NT 4.0 you may
+// need to define DONT_IPV6 in the "sources" files.
+#ifndef DONT_IPV6
+#include <ws2tcpip.h>
+#endif
+
+#include "netsh.h"
+#include "netlib.h"
+
+//
+// System CPU time information class.
+// Used to get CPU time information.
+//
+//     SDK\inc\ntexapi.h 
+// Function x8:   SystemProcessorPerformanceInformation
+// DataStructure: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 
+//
+
+#define SystemProcessorPerformanceInformation 0x08
+
+typedef struct 
+{
+        LARGE_INTEGER   IdleTime;
+        LARGE_INTEGER   KernelTime;
+        LARGE_INTEGER   UserTime;
+        LARGE_INTEGER   DpcTime;
+        LARGE_INTEGER   InterruptTime;
+        LONG                    InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+//
+// Calls to get the information
+//
+typedef ULONG (__stdcall *NT_QUERY_SYSTEM_INFORMATION)( 
+                                                                                        ULONG SystemInformationClass, 
+                                                                                        PVOID SystemInformation, 
+                                                                                        ULONG SystemInformationLength,
+                                                                                        PULONG ReturnLength 
+                                                                                        );
+
+NT_QUERY_SYSTEM_INFORMATION NtQuerySystemInformation = NULL;
+
+
+static LARGE_INTEGER TickHz = {0,0};
+
+_inline LARGE_INTEGER ReadPerformanceCounter(VOID)
+{
+        LARGE_INTEGER Counter;
+        QueryPerformanceCounter(&Counter);
+
+        return(Counter);
+}       // ReadperformanceCounter
+
+
+/* The NT performance data is accessed through the NtQuerySystemInformation
+   call.  References to the PDH.DLL have been deleted.  This structure
+   is the root for these data structures. */
+
+typedef struct sPerfObj 
+{
+        LARGE_INTEGER   StartTime;
+        LARGE_INTEGER   EndTime;
+        SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION StartInfo[MAXCPUS +1];
+        SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION EndInfo[MAXCPUS +1];
+} PerfObj, *PPerfObj;
+
+static PerfObj *PerfCntrs;
+
+// Forward declarations
+
+PerfObj *InitPerfCntrs();
+void RestartPerfCntrs(PerfObj *PerfCntrs);
+double ReportPerfCntrs(PerfObj *PerfCntrs);  /* returns CPU utilization */
+void ClosePerfCntrs(PerfObj *PerfCntrs);
+
+
+void
+cpu_util_init(void) 
+{
+  if (NtQuerySystemInformation == NULL) {
+    // Open the performance counter interface
+    PerfCntrs = InitPerfCntrs();
+  }
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return NT_METHOD;
+}
+
+typedef unsigned __int64    uint64_t;
+
+void
+get_cpu_idle(uint64_t *res)
+{
+  RestartPerfCntrs(PerfCntrs);
+  return;
+}
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  return (float)0.0;
+}
+
+
+/*
+  InitPerfCntrs() - 
+
+  Changed to no longer access the NT performance registry interfaces.
+  A direct call to NtQuerySystemInformation (an undocumented NT API)
+  is made instead.  Parameters determined by decompilation of ntkrnlmp
+  and ntdll.
+*/
+
+
+PerfObj *InitPerfCntrs()
+{
+  PerfObj *NewPerfCntrs;
+  DWORD NTVersion;
+  DWORD status;
+  SYSTEM_INFO SystemInfo;
+
+  GetSystemInfo(&SystemInfo);
+
+  NewPerfCntrs = (PerfObj *)GlobalAlloc(GPTR, sizeof(PerfObj));
+  assert(NewPerfCntrs != NULL);
+  
+  ZeroMemory((PCHAR)NewPerfCntrs, sizeof(PerfObj));
+  
+  // get NT version
+  NTVersion = GetVersion();
+  if (NTVersion >= 0x80000000) 
+    {
+      fprintf(stderr, "Not running on Windows NT\n");
+      exit(1);
+    }
+  
+  // locate the calls we need in NTDLL
+  //Lint 
+  NtQuerySystemInformation = 
+    (NT_QUERY_SYSTEM_INFORMATION)GetProcAddress( GetModuleHandle("ntdll.dll"),
+						 "NtQuerySystemInformation" );
+
+  if ( !(NtQuerySystemInformation) )
+    {
+      //Lint
+      status = GetLastError();
+      fprintf(stderr, "GetProcAddressFailed, status: %X\n", status);
+      exit(1);
+    }
+  
+  // setup to measure timestamps with the high resolution timers.
+  if (QueryPerformanceFrequency(&TickHz) == FALSE)
+    {
+      fprintf(stderr,"MAIN - QueryPerformanceFrequency Failed!\n");
+      exit(2);   
+    }
+  
+  RestartPerfCntrs(NewPerfCntrs);
+  
+  return(NewPerfCntrs);
+}  /* InitPerfCntrs */
+
+/*
+  RestartPerfCntrs() -
+
+  The Performance counters must be read twice to produce rate and
+  percentage results.  This routine is called before the start of a
+  benchmark to establish the initial counters.  It must be called a
+  second time after the benchmark completes to collect the final state
+  of the performance counters.  ReportPerfCntrs is called to print the
+  results after the benchmark completes.
+*/
+
+void RestartPerfCntrs(PerfObj *PerfCntrs)
+{
+  DWORD returnLength = 0;  //Lint
+  DWORD returnNumCPUs;  //Lint
+  DWORD i;
+  
+  DWORD status;
+  SYSTEM_INFO SystemInfo;
+
+  GetSystemInfo(&SystemInfo);
+  
+  // Move previous data from EndInfo to StartInfo.
+  CopyMemory((PCHAR)&PerfCntrs->StartInfo[0],
+	     (PCHAR)&PerfCntrs->EndInfo[0],
+	     sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*(MAXCPUS +1));
+  
+  PerfCntrs->StartTime = PerfCntrs->EndTime;
+  
+  // get the current CPUTIME information
+  if ( (status = NtQuerySystemInformation( SystemProcessorPerformanceInformation,
+					   (PCHAR)&PerfCntrs->EndInfo[0], sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*MAXCPUS,
+					   &returnLength )) != 0) 
+    {
+      fprintf(stderr, "NtQuery failed, status: %X\n", status);
+      exit(1);
+    }
+  
+  PerfCntrs->EndTime = ReadPerformanceCounter();
+  
+  // Validate that NtQuery returned a reasonable amount of data
+  if ((returnLength % sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) != 0)
+    {
+      fprintf(stderr, "NtQuery didn't return expected amount of data\n");
+      fprintf(stderr, "Expected a multiple of %i, returned %i\n",
+	      sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), returnLength);
+      exit(1);
+    }
+  returnNumCPUs = returnLength / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); 
+  
+  if (returnNumCPUs != (int)SystemInfo.dwNumberOfProcessors)
+    {
+      fprintf(stderr, "NtQuery didn't return expected amount of data\n");
+      fprintf(stderr, "Expected data for %i CPUs, returned %i\n",
+	      (int)SystemInfo.dwNumberOfProcessors, returnNumCPUs);
+      exit(1);
+    }
+  
+  // Zero entries not returned by NtQuery
+  ZeroMemory((PCHAR)&PerfCntrs->EndInfo[returnNumCPUs],
+	     sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*
+	     (MAXCPUS +1 - returnNumCPUs));
+  
+  // Total all of the CPUs
+  //      KernelTime needs to be fixed-up; it includes both idle &
+  // true kernel time 
+  //  Note that kernel time also includes DpcTime & InterruptTime, but
+  // I like this. 
+  for (i=0; i < returnNumCPUs; i++)
+    {
+      PerfCntrs->EndInfo[i].KernelTime.QuadPart         -= PerfCntrs->EndInfo[i].IdleTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].IdleTime.QuadPart     += PerfCntrs->EndInfo[i].IdleTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].KernelTime.QuadPart   += PerfCntrs->EndInfo[i].KernelTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].UserTime.QuadPart     += PerfCntrs->EndInfo[i].UserTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].DpcTime.QuadPart      += PerfCntrs->EndInfo[i].DpcTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].InterruptTime.QuadPart += PerfCntrs->EndInfo[i].InterruptTime.QuadPart;
+      PerfCntrs->EndInfo[MAXCPUS].InterruptCount                += PerfCntrs->EndInfo[i].InterruptCount;
+    }
+  
+}   /* RestartPerfCntrs */
+
+/*
+  ReportPerfCntrs() -
+  This routine reports the results of the various performance
+  counters. 
+*/
+
+double ReportPerfCntrs(PerfObj *PerfCntrs)
+{
+  double tot_CPU_Util;
+  int i;
+  int duration;  // in 100 usecs
+  
+  LARGE_INTEGER ActualDuration;
+  
+  SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION        DeltaInfo[MAXCPUS +1];  
+  
+  LARGE_INTEGER   TotalCPUTime[MAXCPUS +1];         
+  
+  SYSTEM_INFO SystemInfo;
+
+  GetSystemInfo(&SystemInfo);
+
+  for (i=0; i <= MAXCPUS; i++)
+    {
+      DeltaInfo[i].IdleTime.QuadPart    = PerfCntrs->EndInfo[i].IdleTime.QuadPart -
+	PerfCntrs->StartInfo[i].IdleTime.QuadPart;
+      DeltaInfo[i].KernelTime.QuadPart          = PerfCntrs->EndInfo[i].KernelTime.QuadPart -
+	PerfCntrs->StartInfo[i].KernelTime.QuadPart;
+      DeltaInfo[i].UserTime.QuadPart    = PerfCntrs->EndInfo[i].UserTime.QuadPart -
+	PerfCntrs->StartInfo[i].UserTime.QuadPart;
+      DeltaInfo[i].DpcTime.QuadPart     = PerfCntrs->EndInfo[i].DpcTime.QuadPart -
+	PerfCntrs->StartInfo[i].DpcTime.QuadPart;
+      DeltaInfo[i].InterruptTime.QuadPart = PerfCntrs->EndInfo[i].InterruptTime.QuadPart -
+	PerfCntrs->StartInfo[i].InterruptTime.QuadPart;
+      DeltaInfo[i].InterruptCount               = PerfCntrs->EndInfo[i].InterruptCount -
+	PerfCntrs->StartInfo[i].InterruptCount;
+      
+      TotalCPUTime[i].QuadPart =      
+	DeltaInfo[i].IdleTime.QuadPart +
+	DeltaInfo[i].KernelTime.QuadPart +
+	DeltaInfo[i].UserTime.QuadPart;
+      // KernelTime already includes DpcTime & InterruptTime!
+      // + DeltaInfo[i].DpcTime.QuadPart  +
+      //  DeltaInfo[i].InterruptTime.QuadPart;
+    }
+  
+  tot_CPU_Util = 100.0*(1.0 - (double)DeltaInfo[MAXCPUS].IdleTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart);  //Lint
+  
+  // Re-calculate duration, since we may have stoped early due to cntr-C.
+  ActualDuration.QuadPart = PerfCntrs->EndTime.QuadPart - 
+    PerfCntrs->StartTime.QuadPart;
+  
+  // convert to 1/10 milliseconds (100 usec) 
+  ActualDuration.QuadPart = (ActualDuration.QuadPart*10000)/TickHz.QuadPart;
+  duration = ActualDuration.LowPart;
+  
+  if (verbosity > 1)
+    {
+      fprintf(where,"ActualDuration (ms): %d\n", duration/10);
+    }
+  
+  if (verbosity > 1)
+    {
+      fprintf(where, "%% CPU    _Total");
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t CPU %i", i);
+	    }
+	}
+      fprintf(where, "\n");
+      
+      fprintf(where, "Busy      %5.2f", tot_CPU_Util);
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.2f", 
+		      100.0*(1.0 - (double)DeltaInfo[i].IdleTime.QuadPart/(double)TotalCPUTime[i].QuadPart));  //Lint
+	    }
+	}
+      fprintf(where, "\n");
+      
+      fprintf(where, "Kernel    %5.2f", 
+	      100.0*(double)DeltaInfo[MAXCPUS].KernelTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart);  //Lint
+      
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.2f", 
+		      100.0*(double)DeltaInfo[i].KernelTime.QuadPart/(double)TotalCPUTime[i].QuadPart);  //Lint
+	    }
+	}
+      fprintf(where, "\n");
+      
+      fprintf(where, "User      %5.2f", 
+	      100.0*(double)DeltaInfo[MAXCPUS].UserTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart);
+      
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.2f", 
+		      100.0*(double)DeltaInfo[i].UserTime.QuadPart/TotalCPUTime[i].QuadPart);  //Lint
+	    }
+	}
+      fprintf(where, "\n");
+      
+      fprintf(where, "Dpc       %5.2f", 
+	      100.0*(double)DeltaInfo[MAXCPUS].DpcTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart);  //Lint
+      
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.2f", 
+		      100.0*(double)DeltaInfo[i].DpcTime.QuadPart/(double)TotalCPUTime[i].QuadPart);  //Lint
+	    }
+	}
+      fprintf(where, "\n");
+      
+      fprintf(where, "Interrupt %5.2f", 
+	      100.0*(double)DeltaInfo[MAXCPUS].InterruptTime.QuadPart/(double)TotalCPUTime[MAXCPUS].QuadPart);  //Lint
+      
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.2f", 
+		      100.0*(double)DeltaInfo[i].InterruptTime.QuadPart/TotalCPUTime[i].QuadPart);  //Lint
+	    }
+	}
+      fprintf(where, "\n\n");
+      
+      fprintf(where, "Interrupt/Sec. %5.1f", 
+	      (double)DeltaInfo[MAXCPUS].InterruptCount*10000.0/(double)duration);
+      
+      if ((int)SystemInfo.dwNumberOfProcessors > 1)
+	{
+	  for (i=0; i < (int)SystemInfo.dwNumberOfProcessors; i++)
+	    {
+	      fprintf(where, "\t %5.1f", 
+		      (double)DeltaInfo[i].InterruptCount*10000.0/(double)duration);
+	    }
+	}
+      fprintf(where, "\n\n");
+      fflush(where);
+    }
+  
+  return (tot_CPU_Util);
+  
+}  /* ReportPerfCntrs */
+
+/*
+  ClosePerfCntrs() -  
+
+  This routine cleans up the performance counter APIs.
+*/
+
+void ClosePerfCntrs(PerfObj *PerfCntrs)
+{
+        GlobalFree(PerfCntrs);
+
+        NtQuerySystemInformation = NULL;
+}   /* ClosePerfCntrs */
+
+void
+cpu_start_internal(void)
+{
+  RestartPerfCntrs(PerfCntrs);

+}
+
+void
+cpu_stop_internal(void)
+{
+  RestartPerfCntrs(PerfCntrs);

+}
+
+float
+calc_cpu_util_internal(float elapsed_time) 
+{
+  float correction_factor;
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  if (debug) {
+    fprintf(where, "correction factor: %f\n", correction_factor);
+  }
+
+  lib_local_cpu_util = (float)ReportPerfCntrs(PerfCntrs);
+  lib_local_cpu_util *= correction_factor;
+  return lib_local_cpu_util;
+
+}
diff --git a/netcpu_osx.c b/netcpu_osx.c
new file mode 100644
index 0000000..2132be1
--- /dev/null
+++ b/netcpu_osx.c
@@ -0,0 +1,149 @@
+char   netcpu_sysctl_id[]="\
+@(#)netcpu_osx.c  Version 2.4.3";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#if HAVE_LIMITS_H
+# include <limits.h>
+# ifndef LONG_LONG_MAX
+#  define LONG_LONG_MAX LLONG_MAX
+# endif /* LONG_LONG_MAX */
+#endif
+
+
+#include <errno.h>
+
+#include <mach/host_info.h>
+#include <mach/mach_types.h>
+/* it would seem that on 10.3.9 mach_msg_type_number_t is in
+   <mach/message.h> so we'll see about including that one too.
+   hopefully it still exists in 10.4. if not, we will need to add some
+   .h file checks in configure so we can use "HAVE_mumble" ifdefs
+   here */
+#include <mach/message.h>
+
+#include "netsh.h"
+#include "netlib.h"
+
+#define UNSIGNED_DIFFERENCE(x,y) (x >= y ? x - y : (0 - y) + x )
+
+static host_cpu_load_info_data_t lib_start_ticks;
+static host_cpu_load_info_data_t lib_end_ticks;
+
+static mach_port_t lib_host_port;
+
+void
+cpu_util_init(void) 
+{
+  lib_host_port = mach_host_self();
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  mach_port_deallocate(lib_host_port);
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return OSX;
+}
+
+void
+get_cpu_idle(uint64_t *res)
+{
+    return;
+}
+
+void
+get_host_ticks(host_cpu_load_info_t info)
+{
+  mach_msg_type_number_t count;
+
+  count = HOST_CPU_LOAD_INFO_COUNT;
+  host_statistics(lib_host_port, HOST_CPU_LOAD_INFO, (host_info_t)info, &count);
+  return;
+}
+
+/* calibrate_sysctl  - perform the idle rate calculation using the
+   sysctl call - typically on BSD */
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+    return (float)0.0;   
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  float correction_factor;
+  natural_t	userticks, systicks, idleticks, totalticks;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  if (debug) {
+    fprintf(where, "correction factor: %f\n", correction_factor);
+  }
+
+  userticks = UNSIGNED_DIFFERENCE((lib_end_ticks.cpu_ticks[CPU_STATE_USER] + lib_end_ticks.cpu_ticks[CPU_STATE_NICE]),
+				  (lib_start_ticks.cpu_ticks[CPU_STATE_USER] + lib_start_ticks.cpu_ticks[CPU_STATE_NICE]));
+  systicks = UNSIGNED_DIFFERENCE(lib_end_ticks.cpu_ticks[CPU_STATE_SYSTEM], lib_start_ticks.cpu_ticks[CPU_STATE_SYSTEM]);
+  idleticks = UNSIGNED_DIFFERENCE(lib_end_ticks.cpu_ticks[CPU_STATE_IDLE], lib_start_ticks.cpu_ticks[CPU_STATE_IDLE]);
+  totalticks = userticks + systicks + idleticks;
+
+  lib_local_cpu_util = ((float)userticks + (float)systicks)/(float)totalticks * 100.0f;
+  lib_local_cpu_util *= correction_factor;
+
+  return lib_local_cpu_util;
+
+}
+void
+cpu_start_internal(void)
+{
+    get_host_ticks(&lib_start_ticks);
+}
+
+void
+cpu_stop_internal(void)
+{
+    get_host_ticks(&lib_end_ticks);
+}
diff --git a/netcpu_perfstat.c b/netcpu_perfstat.c
new file mode 100644
index 0000000..f928a25
--- /dev/null
+++ b/netcpu_perfstat.c
@@ -0,0 +1,351 @@
+char   netcpu_perfstat_id[]="\
+@(#)netcpu_perfstat.c Version 2.4.0";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+# ifndef LONG_LONG_MAX
+#  define LONG_LONG_MAX LLONG_MAX
+# endif /* LONG_LONG_MAX */
+#endif 
+
+#include <errno.h>
+
+#include "netsh.h"
+#include "netlib.h"
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibration to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+static uint64_t  lib_start_count[MAXCPUS];
+static uint64_t  lib_end_count[MAXCPUS];
+
+
+void
+cpu_util_init(void) 
+{
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return PERFSTAT;
+}
+
+void
+get_cpu_idle(uint64_t *res)
+{
+  perfstat_cpu_t *perfstat_buffer;
+  perfstat_cpu_t *per_cpu_pointer;
+  perfstat_id_t  name;
+  int i,ret;
+  
+  /* a name of "" will cause us to start from the beginning */
+  strcpy(name.name,"");
+  perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus *
+					     sizeof(perfstat_cpu_t));
+  if (perfstat_buffer == NULL) {
+    fprintf(where,
+	    "cpu_start: malloc failed errno %d\n",
+	    errno);
+    fflush(where);
+    exit(-1);
+  }
+  
+  /* happiness and joy, keep going */
+  ret = perfstat_cpu(&name,
+		     perfstat_buffer,
+		     sizeof(perfstat_cpu_t),
+		     lib_num_loc_cpus);
+  
+  if ((ret == -1) || 
+      (ret != lib_num_loc_cpus)) {
+    fprintf(where,
+	    "cpu_start: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
+	    errno,
+	    lib_num_loc_cpus,
+	    ret);
+    fflush(where);
+    exit(-1);
+  }
+  
+  per_cpu_pointer = perfstat_buffer;
+  for (i = 0; i < lib_num_loc_cpus; i++){
+    res[i] = per_cpu_pointer->idle;
+    per_cpu_pointer++;
+  }
+  free(perfstat_buffer);
+  
+  return;
+}
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  unsigned long long
+    firstcnt[MAXCPUS],
+    secondcnt[MAXCPUS];
+
+  float 
+    elapsed,
+    temp_rate,
+    rate[MAXTIMES],
+    local_maxrate;
+
+  long  
+    sec,
+    usec;
+
+  int   
+    i,
+    j;
+  
+  struct  timeval time1, time2 ;
+  struct  timezone tz;
+
+  perfstat_cpu_t  *perfstat_buffer;
+  perfstat_cpu_t  *per_cpu_pointer;
+  perfstat_id_t   name;
+  int ret;
+  
+  if (debug) {
+    fprintf(where,"enter calibrate_perfstat\n");
+    fflush(where);
+  }
+
+  if (iterations > MAXTIMES) {
+    iterations = MAXTIMES;
+  }
+
+  local_maxrate = (float)-1.0;
+  
+  perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus *
+                                             sizeof(perfstat_cpu_t));
+  if (perfstat_buffer == NULL) {
+    fprintf(where,
+            "calibrate_perfstat: malloc failed errno %d\n",
+            errno);
+    fflush(where);
+    exit(-1);
+  }
+
+  for(i = 0; i < iterations; i++) {
+    rate[i] = (float)0.0;
+    /* a name of "" will cause us to start from the beginning */
+    strcpy(name.name,"");
+     
+    /* happiness and joy, keep going */
+    ret = perfstat_cpu(&name,
+                       perfstat_buffer,
+                       sizeof(perfstat_cpu_t),
+                       lib_num_loc_cpus);
+    
+    if ((ret == -1) || 
+        (ret != lib_num_loc_cpus)) {
+      fprintf(where,
+              "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
+              errno,
+              lib_num_loc_cpus,
+              ret);
+      fflush(where);
+      exit(-1);
+    }
+
+    per_cpu_pointer = perfstat_buffer;
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      firstcnt[j] = per_cpu_pointer->idle;
+      per_cpu_pointer++;
+    }
+    gettimeofday (&time1, &tz);
+    sleep(interval);
+    gettimeofday (&time2, &tz);
+
+    if (time2.tv_usec < time1.tv_usec)
+      {
+        time2.tv_usec += 1000000;
+        time2.tv_sec -=1;
+      }
+    sec = time2.tv_sec - time1.tv_sec;
+    usec = time2.tv_usec - time1.tv_usec;
+    elapsed = (float)sec + ((float)usec/(float)1000000.0);
+
+    /* happiness and joy, keep going */
+    ret = perfstat_cpu(&name,
+                       perfstat_buffer,
+                       sizeof(perfstat_cpu_t),
+                       lib_num_loc_cpus);
+    
+    if ((ret == -1) || 
+        (ret != lib_num_loc_cpus)) {
+      fprintf(where,
+              "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
+              errno,
+              lib_num_loc_cpus,
+              ret);
+      fflush(where);
+      exit(-1);
+    }
+
+    per_cpu_pointer = perfstat_buffer;
+    
+    if(debug) {
+      fprintf(where, "Calibration for perfstat counter run: %d\n",i);
+      fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
+      fprintf(where,"\telapsed time = %g\n",elapsed);
+    }
+
+    for (j = 0; j < lib_num_loc_cpus; j++) {
+      secondcnt[j] = per_cpu_pointer->idle;
+      per_cpu_pointer++;
+      if(debug) {
+        /* I know that there are situations where compilers know about */
+        /* long long, but the library functions do not... raj 4/95 */
+        fprintf(where,
+                "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n",
+                j,
+                firstcnt[j],
+                firstcnt[j],
+                j,
+                secondcnt[j],
+                secondcnt[j]);
+      }
+      /* we assume that it would wrap no more than once. we also */
+      /* assume that the result of subtracting will "fit" raj 4/95 */
+      temp_rate = (secondcnt[j] >= firstcnt[j]) ?
+        (float)(secondcnt[j] - firstcnt[j])/elapsed : 
+          (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
+      if (temp_rate > rate[i]) rate[i] = temp_rate;
+      if(debug) {
+        fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
+        fflush(where);
+      }
+      if (local_maxrate < rate[i]) local_maxrate = rate[i];
+    }
+  }
+  if(debug) {
+    fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
+    fflush(where);
+  }
+  free(perfstat_buffer);
+  return local_maxrate;
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+
+  float actual_rate;
+  float correction_factor;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 +
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  /* this looks just like the looper case. at least I think it */
+  /* should :) raj 4/95 */
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+
+    /* we assume that the two are not more than a long apart. I */
+    /* know that this is bad, but trying to go from long longs to */
+    /* a float (perhaps a double) is boggling my mind right now. */
+    /* raj 4/95 */
+
+    long long
+      diff;
+
+    if (lib_end_count[i] >= lib_start_count[i]) {
+      diff = lib_end_count[i] - lib_start_count[i];
+    }
+    else {
+      diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
+    }
+    actual_rate = (float) diff / lib_elapsed;
+    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
+      lib_local_maxrate * 100;
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+    if (debug) {
+      fprintf(where,
+              "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n",
+              i,
+              actual_rate,
+              lib_local_maxrate,
+              lib_local_per_cpu_util[i]);
+    }
+  }
+
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  if (debug) {
+    fprintf(where,
+            "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util);
+  }
+
+  lib_local_cpu_util *= correction_factor;
+
+  if (debug) {
+    fprintf(where,
+            "calc_cpu_util: returning %g\n",lib_local_cpu_util);
+  }
+
+  return lib_local_cpu_util;
+
+}
+void
+cpu_start_internal(void)
+{
+  get_cpu_idle(lib_start_count);
+  return;
+}
+ 
+void
+cpu_stop_internal(void)
+{
+  get_cpu_idle(lib_end_count);
+}
+
diff --git a/netcpu_procstat.c b/netcpu_procstat.c
new file mode 100644
index 0000000..5bdadea
--- /dev/null
+++ b/netcpu_procstat.c
@@ -0,0 +1,265 @@
+char   netcpu_procstat_id[]="\
+@(#)netcpu_procstat.c (c) Copyright 2005-2007 Version 2.4.3";
+
+/* netcpu_procstat.c
+  
+   Implement the /proc/stat specific portions of netperf CPU
+   utilization measurements. These are broken-out into a separate file
+   to make life much nicer over in netlib.c which had become a maze of
+   twisty, CPU-util-related, #ifdefs, all different.  raj 2005-01-26
+   */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+
+#include <string.h>
+
+#include "netsh.h"
+#include "netlib.h"
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibrarion to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+static uint64_t  lib_start_count[MAXCPUS];
+static uint64_t  lib_end_count[MAXCPUS];
+
+
+/* The max. length of one line of /proc/stat cpu output */
+#define CPU_LINE_LENGTH ((8 * sizeof (long) / 3 + 1) * 4 + 8)
+#define PROC_STAT_FILE_NAME "/proc/stat"
+#define N_CPU_LINES(nr) (nr == 1 ? 1 : 1 + nr)
+
+static int proc_stat_fd = -1;
+static char *proc_stat_buf = NULL;
+static int proc_stat_buflen = 0;
+
+void
+cpu_util_init(void) 
+{
+
+  if (debug) {
+    fprintf(where,
+	    "cpu_util_init enter, proc_stat_fd %d proc_stat_buf %p\n",
+	    proc_stat_fd,
+	    proc_stat_buf);
+    fflush(where);
+  }
+  if (proc_stat_fd < 0) {
+    proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL);
+    if (proc_stat_fd < 0) {
+      fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME);
+      exit (1);
+    };
+  };
+
+  if (!proc_stat_buf) {
+    proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH;
+    if (debug) {
+      fprintf(where,
+	      "lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n",
+	      lib_num_loc_cpus,
+	      N_CPU_LINES(lib_num_loc_cpus),
+	      CPU_LINE_LENGTH,
+	      proc_stat_buflen);
+      fflush(where);
+    }
+    proc_stat_buf = (char *)malloc (proc_stat_buflen);
+    if (!proc_stat_buf) {
+      fprintf (stderr, "Cannot allocate buffer memory!\n");
+      exit (1);
+    }
+  }
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  close(proc_stat_fd);
+  proc_stat_fd = -1;
+  free(proc_stat_buf);
+  proc_stat_buf = NULL;
+  return;
+}
+
+int
+get_cpu_method()
+{
+  return PROC_STAT;
+}
+
+float
+calibrate_idle_rate (int iterations, int interval)
+{
+  if (proc_stat_fd < 0) {
+    proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL);
+    if (proc_stat_fd < 0) {
+      fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME);
+      exit (1);
+    };
+  };
+
+  if (!proc_stat_buf) {
+    proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH;
+    if (debug) {
+      fprintf(where,
+	      "calibrate: lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n",
+	      lib_num_loc_cpus,
+	      N_CPU_LINES(lib_num_loc_cpus),
+	      CPU_LINE_LENGTH,
+	      proc_stat_buflen);
+      fflush(where);
+    }
+    proc_stat_buf = (char *)malloc (proc_stat_buflen);
+    if (!proc_stat_buf) {
+      fprintf (stderr, "Cannot allocate buffer memory!\n");
+      exit (1);
+    };
+  };
+
+  return sysconf (_SC_CLK_TCK);
+}
+
+void
+get_cpu_idle (uint64_t *res)
+{
+  int space;
+  int i;
+  int n = lib_num_loc_cpus;
+  char *p = proc_stat_buf;
+
+  lseek (proc_stat_fd, 0, SEEK_SET);
+  read (proc_stat_fd, p, proc_stat_buflen);
+
+  if (debug) {
+    fprintf(where,"proc_stat_buf '%.*s'\n",proc_stat_buflen,p);
+    fflush(where);
+  }
+  /* Skip first line (total) on SMP */
+  if (n > 1) p = strchr (p, '\n');
+
+  /* Idle time is the 4th space-separated token */
+  for (i = 0; i < n; i++) {
+    for (space = 0; space < 4; space ++) {
+      p = strchr (p, ' ');
+      while (*++p == ' ');
+    };
+    res[i] = strtoul (p, &p, 10);
+    if (debug) {
+      fprintf(where,"res[%d] is %llu\n",i,res[i]);
+      fflush(where);
+    }
+    p = strchr (p, '\n');
+  };
+
+}
+
+/* take the initial timestamp and start collecting CPU utilization if
+   requested */
+
+void
+measure_cpu_start()
+{
+  cpu_method = PROC_STAT;
+  get_cpu_idle(lib_start_count);
+}
+
+/* collect final CPU utilization raw data */
+void
+measure_cpu_stop()
+{
+  get_cpu_idle(lib_end_count);
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+
+  float actual_rate;
+  float correction_factor;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+
+    /* it would appear that on some systems, in loopback, nice is
+     *very* effective, causing the looper process to stop dead in its
+     tracks. if this happens, we need to ensure that the calculation
+     does not go south. raj 6/95 and if we run completely out of idle,
+     the same thing could in theory happen to the USE_KSTAT path. raj
+     8/2000 */ 
+    
+    if (lib_end_count[i] == lib_start_count[i]) {
+      lib_end_count[i]++;
+    }
+    
+    actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
+      (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
+      (float)(lib_end_count[i] - lib_start_count[i] +
+	      MAXLONG)/ lib_elapsed;
+    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
+      lib_local_maxrate * 100;
+    if (debug) {
+      fprintf(where,
+              "calc_cpu_util: actual_rate on processor %d is %f start %llx end %llx util %f\n",
+              i,
+              actual_rate,
+              lib_start_count[i],
+              lib_end_count[i],
+	      lib_local_per_cpu_util[i]);
+    }
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+  }
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  lib_local_cpu_util *= correction_factor;
+  return lib_local_cpu_util;
+}
+
+void
+cpu_start_internal(void)
+{
+  get_cpu_idle(lib_start_count);
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_idle(lib_end_count);
+}
diff --git a/netcpu_pstat.c b/netcpu_pstat.c
new file mode 100644
index 0000000..08f27c1
--- /dev/null
+++ b/netcpu_pstat.c
@@ -0,0 +1,307 @@
+char   netcpu_pstat_id[]="\
+@(#)netcpu_pstat.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif 
+
+#include <sys/dk.h>
+#include <sys/pstat.h>
+
+#ifndef PSTAT_IPCINFO
+# error Sorry, pstat() CPU utilization on 10.0 and later only
+#endif
+
+#include "netsh.h"
+#include "netlib.h"
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibrarion to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+static uint64_t  lib_start_count[MAXCPUS];
+static uint64_t  lib_end_count[MAXCPUS];
+
+void
+cpu_util_init(void) 
+{
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return HP_IDLE_COUNTER;
+}
+
+void
+get_cpu_idle(uint64_t *res)
+{
+      /* get the idle sycle counter for each processor */
+      struct pst_processor *psp;
+      union overlay_u {
+        long long full;
+        long      word[2];
+      } *overlay;
+      
+      psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
+      if (psp == NULL) {
+        printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
+        exit(1);
+	  }
+      if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
+        int i;
+        for (i = 0; i < lib_num_loc_cpus; i++) {
+          overlay = (union overlay_u *)&(res[i]);
+          overlay->word[0] = psp[i].psp_idlecycles.psc_hi;
+          overlay->word[1] = psp[i].psp_idlecycles.psc_lo;
+          if(debug) {
+            fprintf(where,
+                    "\tres[%d] = 0x%8.8x%8.8x\n",
+                    i,
+                    hi_32(&res[i]),
+                    lo_32(&res[i]));
+            fflush(where);
+          }
+        }
+        free(psp);
+      }
+}
+
+/* calibrate_pstat
+   Loop a number of iterations, sleeping wait_time seconds each and
+   count how high the idle counter gets each time. Return  the measured
+   cpu rate to the calling routine.  */
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+
+  uint64_t
+    firstcnt[MAXCPUS],
+    secondcnt[MAXCPUS];
+
+  float 
+    elapsed, 
+    temp_rate,
+    rate[MAXTIMES],
+    local_maxrate;
+
+  long  
+    sec,
+    usec;
+
+  int   
+    i,
+    j;
+  
+  long  count;
+
+  struct  timeval time1, time2;
+  struct  timezone tz;
+
+  struct pst_processor *psp;
+  
+  if (iterations > MAXTIMES) {
+    iterations = MAXTIMES;
+  }
+  
+  local_maxrate = -1.0;
+
+  psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
+  if (psp == NULL) {
+    printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
+    exit(1);
+  }
+
+  for(i = 0; i < iterations; i++) {
+    rate[i] = 0.0;
+    /* get the idle sycle counter for each processor */
+    if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
+      for (j = 0; j < lib_num_loc_cpus; j++) {
+        union overlay_u {
+          long long full;
+          long      word[2];
+        } *overlay;
+        overlay = (union overlay_u *)&(firstcnt[j]);
+        overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
+        overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
+      }
+    }
+    else {
+      fprintf(where,"pstat_getprocessor failure errno %d\n",errno);
+      fflush(where);
+      exit(1);
+    }
+
+    gettimeofday (&time1, &tz);
+    sleep(interval);
+    gettimeofday (&time2, &tz);
+    
+    if (time2.tv_usec < time1.tv_usec)
+      {
+        time2.tv_usec += 1000000;
+        time2.tv_sec -=1;
+      }
+    sec = time2.tv_sec - time1.tv_sec;
+    usec = time2.tv_usec - time1.tv_usec;
+    elapsed = (float)sec + ((float)usec/(float)1000000.0);
+
+    if(debug) {
+      fprintf(where, "Calibration for counter run: %d\n",i);
+      fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
+      fprintf(where,"\telapsed time = %g\n",elapsed);
+    }
+
+    if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
+      for (j = 0; j < lib_num_loc_cpus; j++) {
+        union overlay_u {
+          long long full;
+          long      word[2];
+        } *overlay;
+        overlay = (union overlay_u *)&(secondcnt[j]);
+        overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
+        overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
+        if(debug) {
+          /* I know that there are situations where compilers know about */
+          /* long long, but the library fucntions do not... raj 4/95 */
+          fprintf(where,
+                  "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n",
+                  j,
+                  hi_32(&firstcnt[j]),
+                  lo_32(&firstcnt[j]),
+                  j,
+                  hi_32(&secondcnt[j]),
+                  lo_32(&secondcnt[j]));
+        }
+        temp_rate = (secondcnt[j] >= firstcnt[j]) ? 
+          (float)(secondcnt[j] - firstcnt[j] )/elapsed : 
+            (float)(secondcnt[j] - firstcnt[j] + LONG_LONG_MAX)/elapsed;
+        if (temp_rate > rate[i]) rate[i] = temp_rate;
+        if(debug) {
+          fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
+          fflush(where);
+        }
+        if (local_maxrate < rate[i]) local_maxrate = rate[i];
+      }
+    }
+    else {
+      fprintf(where,"pstat failure; errno %d\n",errno);
+      fflush(where);
+      exit(1);
+    }
+  }
+  if(debug) {
+    fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
+    fflush(where);
+  }
+  return local_maxrate;
+
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+
+  float actual_rate;
+  float correction_factor;
+
+  lib_local_cpu_util = (float)0.0;
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  /* this looks just like the looper case. at least I think it */
+  /* should :) raj 4/95 */
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+    
+    /* we assume that the two are not more than a long apart. I */
+    /* know that this is bad, but trying to go from long longs to */
+    /* a float (perhaps a double) is boggling my mind right now. */
+    /* raj 4/95 */
+    
+    long long 
+      diff;
+    
+    if (lib_end_count[i] >= lib_start_count[i]) {
+      diff = lib_end_count[i] - lib_start_count[i];
+    }
+    else {
+      diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
+    }
+    actual_rate = (float) diff / lib_elapsed;
+    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
+      lib_local_maxrate * 100;
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+    if (debug) {
+      fprintf(where,
+	      "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n",
+	      i,
+	      actual_rate,
+	      lib_local_maxrate,
+	      lib_local_per_cpu_util[i]);
+    }
+  }
+  
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+  
+  if (debug) {
+    fprintf(where,
+	    "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util);
+  }
+
+  lib_local_cpu_util *= correction_factor;
+
+  if (debug) {
+    fprintf(where,
+	    "calc_cpu_util: returning %g\n",lib_local_cpu_util);
+  }
+
+  return lib_local_cpu_util;
+
+}
+void
+cpu_start_internal(void)
+{
+  get_cpu_idle(lib_start_count);
+  return;
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_idle(lib_end_count);
+}
diff --git a/netcpu_pstatnew.c b/netcpu_pstatnew.c
new file mode 100644
index 0000000..fd2d036
--- /dev/null
+++ b/netcpu_pstatnew.c
@@ -0,0 +1,398 @@
+char   netcpu_pstatnew_id[]="\
+@(#)netcpu_pstatnew.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.1";
+
+/* since we "know" that this interface is available only on 11.23 and
+   later, and that 11.23 and later are strictly 64-bit kernels, we can
+   arbitrarily set _PSTAT64 here and not have to worry about it up in
+   the configure script and makefiles. raj 2005/09/06 */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#include <unistd.h>
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif 
+
+#include <sys/dk.h>
+#include <sys/pstat.h>
+
+/* HP-UX 11.23 seems to have added three other cycle counters to the
+   original psp_idlecycles - one for user, one for kernel and one for
+   interrupt. so, we can now use those to calculate CPU utilization
+   without requiring any calibration phase.  raj 2005-02-16 */ 
+
+#ifndef PSTAT_IPCINFO
+# error Sorry, pstat() CPU utilization on 10.0 and later only
+#endif
+
+typedef struct cpu_time_counters {
+  uint64_t idle;
+  uint64_t user;
+  uint64_t kernel;
+  uint64_t interrupt;
+} cpu_time_counters_t;
+
+uint64_t lib_iticksperclktick;
+
+#include "netsh.h"
+#include "netlib.h"
+
+/* the lib_start_count and lib_end_count arrays hold the starting
+   and ending values of whatever is counting when the system is
+   idle. The rate at which this increments during a test is compared
+   with a previous calibrarion to arrive at a CPU utilization
+   percentage. raj 2005-01-26 */
+
+static cpu_time_counters_t  starting_cpu_counters[MAXCPUS];
+static cpu_time_counters_t  ending_cpu_counters[MAXCPUS];
+static cpu_time_counters_t  delta_cpu_counters[MAXCPUS];
+
+void
+cpu_util_init(void) 
+{
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return HP_IDLE_COUNTER;
+}
+
+void
+get_cpu_counters(cpu_time_counters_t *res)
+{
+      /* get the idle sycle counter for each processor. now while on a
+	 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits,
+	 only the bottom 32-bits are actually valid.  don't ask me
+	 why, that is just the way it is.  soo, we shift the psc_hi
+	 value by 32 bits and then just sum-in the psc_lo value.  raj
+	 2005/09/06 */ 
+      struct pst_processor *psp;
+
+      psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
+      if (psp == NULL) {
+        printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
+        exit(1);
+	  }
+      if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
+        int i;
+	/* we use lib_iticksperclktick in our sanity checking. we
+	   ass-u-me it is the same value for each CPU - famous last
+	   words no doubt. raj 2005/09/06 */
+	lib_iticksperclktick = psp[0].psp_iticksperclktick;
+        for (i = 0; i < lib_num_loc_cpus; i++) {
+          res[i].idle = (((uint64_t)psp[i].psp_idlecycles.psc_hi << 32) +
+			 psp[i].psp_idlecycles.psc_lo);
+          if(debug) {
+            fprintf(where,
+                    "\tidle[%d] = 0x%"PRIx64" ",
+                    i,
+                    res[i].idle);
+            fflush(where);
+          }
+          res[i].user = (((uint64_t)psp[i].psp_usercycles.psc_hi << 32) +
+			 psp[i].psp_usercycles.psc_lo);
+          if(debug) {
+            fprintf(where,
+                    "user[%d] = 0x%"PRIx64" ",
+                    i,
+                    res[i].user);
+            fflush(where);
+          }
+          res[i].kernel = (((uint64_t)psp[i].psp_systemcycles.psc_hi << 32) +
+			    psp[i].psp_systemcycles.psc_lo);
+          if(debug) {
+            fprintf(where,
+                    "kern[%d] = 0x%"PRIx64" ",
+                    i,
+                    res[i].kernel);
+            fflush(where);
+          }
+          res[i].interrupt = (((uint64_t)psp[i].psp_interruptcycles.psc_hi << 32) +
+			      psp[i].psp_interruptcycles.psc_lo);
+          if(debug) {
+            fprintf(where,
+                    "intr[%d] = 0x%"PRIx64"\n",
+                    i,
+                    res[i].interrupt);
+            fflush(where);
+          }
+        }
+        free(psp);
+      }
+}
+
+/* calibrate_pstatnew
+   there really isn't anything much to do here since we have all the
+   counters and use their ratios for CPU util measurement. raj
+   2005-02-16 */
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  return 0.0;
+}
+
+static void
+print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters) 
+{
+  fprintf(where,"%s[%d]:\n",name,instance);
+  fprintf(where,
+	  "\t idle %llu\n",counters[instance].idle);
+  fprintf(where,
+	  "\t user %llu\n",counters[instance].user);
+  fprintf(where,
+	  "\t kernel %llu\n",counters[instance].kernel);
+  fprintf(where,
+	  "\t interrupt %llu\n",counters[instance].interrupt);
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  int i;
+
+  uint64_t total_cpu_cycles;
+  uint64_t sanity_cpu_cycles;
+
+#ifndef USE_INTEGER_MATH
+  double fraction_idle;
+  double fraction_user;
+  double fraction_kernel;
+  double fraction_interrupt;
+  double estimated_fraction_interrupt;
+#else
+  uint64_t fraction_idle;
+  uint64_t fraction_user;
+  uint64_t fraction_kernel;
+  uint64_t fraction_interrupt;
+  uint64_t estimated_fraction_interrupt;
+
+#define CALC_PERCENT 100
+#define CALC_TENTH_PERCENT 1000
+#define CALC_HUNDREDTH_PERCENT 10000
+#define CALC_THOUSANDTH_PERCENT 100000
+#define CALC_ACCURACY CALC_THOUSANDTH_PERCENT
+
+#endif /* USE_INTEGER_MATH */
+  float actual_rate;
+  float correction_factor;
+
+  lib_local_cpu_util = (float)0.0;
+
+  /* It is possible that the library measured a time other than */
+  /* the one that the user want for the cpu utilization */
+  /* calculations - for example, tests that were ended by */
+  /* watchdog timers such as the udp stream test. We let these */
+  /* tests tell up what the elapsed time should be. */
+  
+  if (elapsed_time != 0.0) {
+    correction_factor = (float) 1.0 + 
+      ((lib_elapsed - elapsed_time) / elapsed_time);
+  }
+  else {
+    correction_factor = (float) 1.0;
+  }
+
+  /* calculate our sanity check on cycles */
+  if (debug) {
+    fprintf(where,
+	    "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n",
+	    lib_elapsed,
+	    sysconf(_SC_CLK_TCK),
+	    lib_iticksperclktick);
+  }
+
+  /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right"
+     thing in measuring user, kernel, interrupt and idle all together
+     instead of overlapping interrupt with the others like an OS that
+     shall not be named.  However.... it seems there is a bug in the
+     accounting for interrupt cycles, whereby the cycles do not get
+     properly accounted.  The sum of user, kernel, interrupt and idle
+     does not equal the clock rate multiplied by the elapsed time.
+     Some cycles go missing.
+
+     Since we see agreement between netperf and glance/vsar with the
+     old "pstat" mechanism, we can presume that the accounting for
+     idle cycles is sufficiently accurate.  So, while we will still do
+     math with user, kernel and interrupt cycles, we will only
+     caculate CPU utilization based on the ratio of idle to _real_
+     total cycles.  I am told that a "future release" of HP-UX will
+     fix the interupt cycle accounting.  raj 2005/09/14 */
+
+  /* calculate what the sum of CPU cycles _SHOULD_ be */
+  sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed * 
+    (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick);
+
+  /* this looks just like the looper case. at least I think it */
+  /* should :) raj 4/95 */
+  for (i = 0; i < lib_num_loc_cpus; i++) {
+    
+    /* we ass-u-me that these counters will never wrap during a
+       netperf run.  this may not be a particularly safe thing to
+       do. raj 2005-01-28 */
+    delta_cpu_counters[i].idle = ending_cpu_counters[i].idle -
+      starting_cpu_counters[i].idle;
+    delta_cpu_counters[i].user = ending_cpu_counters[i].user -
+      starting_cpu_counters[i].user;
+    delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel -
+      starting_cpu_counters[i].kernel;
+    delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt -
+      starting_cpu_counters[i].interrupt;
+    
+    if (debug) {
+      print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters);
+    }
+
+    /* now get the sum, which we ass-u-me does not overflow a 64-bit
+       counter. raj 2005-02-16 */
+    total_cpu_cycles = 
+      delta_cpu_counters[i].idle +
+      delta_cpu_counters[i].user +
+      delta_cpu_counters[i].kernel +
+      delta_cpu_counters[i].interrupt;
+
+    if (debug) {
+      fprintf(where,
+	      "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64" missing %"PRIu64"\n",
+	      total_cpu_cycles,
+	      sanity_cpu_cycles,
+	      sanity_cpu_cycles - total_cpu_cycles);
+    }
+
+    /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel
+       does _NOT_ overlap with interrupt, we do not have to apply any
+       correction kludge. raj 2005-02-16 */
+
+#ifndef USE_INTEGER_MATH
+    /* when the accounting for interrupt time gets its act together,
+       we can use total_cpu_cycles rather than sanity_cpu_cycles, but
+       until then, use sanity_cpu_ccles. raj 2005/09/14 */
+
+    fraction_idle = (double)delta_cpu_counters[i].idle / 
+      (double)sanity_cpu_cycles;
+
+    fraction_user = (double)delta_cpu_counters[i].user / 
+      (double)sanity_cpu_cycles;
+
+    fraction_kernel = (double) delta_cpu_counters[i].kernel / 
+      (double)sanity_cpu_cycles;
+
+    fraction_interrupt = (double)delta_cpu_counters[i].interrupt / 
+      (double)sanity_cpu_cycles;
+
+    /* ass-u-me that it is only interrupt that is bogus, and assign
+       all the "missing" cycles to it. raj 2005/09/14 */
+    estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt +
+				    (sanity_cpu_cycles - total_cpu_cycles)) / 
+      (double)sanity_cpu_cycles;
+
+    if (debug) {
+      fprintf(where,"\tfraction_idle %g\n",fraction_idle);
+      fprintf(where,"\tfraction_user %g\n",fraction_user);
+      fprintf(where,"\tfraction_kernel %g\n",fraction_kernel);
+      fprintf(where,"\tfraction_interrupt %g WARNING, possibly under-counted!\n",fraction_interrupt);
+      fprintf(where,"\testimated_fraction_interrupt %g\n",
+	      estimated_fraction_interrupt);
+    }
+
+    /* and finally, what is our CPU utilization? */
+    lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0);
+#else
+    /* and now some fun with integer math.  i initially tried to
+       promote things to long doubled but that didn't seem to result
+       in happiness and joy. raj 2005-01-28 */
+
+    /* multiply by 100 and divide by total and you get whole
+       percentages. multiply by 1000 and divide by total and you get
+       tenths of percentages.  multiply by 10000 and divide by total
+       and you get hundredths of percentages. etc etc etc raj
+       2005-01-28 */
+
+    /* when the accounting for interrupt time gets its act together,
+       we can use total_cpu_cycles rather than sanity_cpu_cycles, but
+       until then, use sanity_cpu_ccles. raj 2005/09/14 */
+
+    fraction_idle = 
+      (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles;
+
+    fraction_user = 
+      (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles;
+
+    fraction_kernel = 
+      (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles;
+
+    fraction_interrupt = 
+      (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles;
+
+
+    estimated_fraction_interrupt = 
+      ((delta_cpu_counters[i].interrupt + 
+	(sanity_cpu_cycles - total_cpu_cycles)) * 
+       CALC_ACCURACY) / sanity_cpu_cycles;
+
+    if (debug) {
+      fprintf(where,"\tfraction_idle %"PRIu64"\n",fraction_idle);
+      fprintf(where,"\tfraction_user %"PRIu64"\n",fraction_user);
+      fprintf(where,"\tfraction_kernel %"PRIu64"\n",fraction_kernel);
+      fprintf(where,"\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n",fraction_interrupt);
+      fprintf(where,"\testimated_fraction_interrupt %"PRIu64"\n",
+	      estimated_fraction_interrupt);
+    }
+
+    /* and finally, what is our CPU utilization? */
+    lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle / 
+					  (float)CALC_ACCURACY) * 100.0);
+#endif
+    if (debug) {
+      fprintf(where,
+	      "lib_local_per_cpu_util[%d] %g\n",
+	      i,
+	      lib_local_per_cpu_util[i]);
+    }
+    lib_local_cpu_util += lib_local_per_cpu_util[i];
+  }
+  /* we want the average across all n processors */
+  lib_local_cpu_util /= (float)lib_num_loc_cpus;
+
+  lib_local_cpu_util *= correction_factor;
+
+  if (debug) {
+    fprintf(where,
+	    "calc_cpu_util: returning %g\n",lib_local_cpu_util);
+  }
+
+  return lib_local_cpu_util;
+
+}
+void
+cpu_start_internal(void)
+{
+  get_cpu_counters(starting_cpu_counters);
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_counters(ending_cpu_counters);
+}
diff --git a/netcpu_sysctl.c b/netcpu_sysctl.c
new file mode 100644
index 0000000..919f62c
--- /dev/null
+++ b/netcpu_sysctl.c
@@ -0,0 +1,127 @@
+char   netcpu_sysctl_id[]="\
+@(#)netcpu_sysctl.c  Version 2.4.3";
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#if HAVE_LIMITS_H
+# include <limits.h>
+# ifndef LONG_LONG_MAX
+#  define LONG_LONG_MAX LLONG_MAX
+# endif /* LONG_LONG_MAX */
+#endif
+
+
+#include <errno.h>
+
+/* need to have some sort of check for sys/sysctl.h versus sysctl.h */
+#include <sys/sysctl.h>
+
+
+/* this has been liberally cut and pasted from <sys/resource.h> on
+   FreeBSD. in general, this would be a bad idea, but I don't want to
+   have to do a _KERNEL define to get these and that is what
+   sys/resource.h seems to want. raj 2002-03-03 */
+#define CP_USER         0
+#define CP_NICE         1
+#define CP_SYS          2
+#define CP_INTR         3
+#define CP_IDLE         4
+#define CPUSTATES       5
+
+
+#include "netsh.h"
+#include "netlib.h"
+
+static long lib_start_count[CPUSTATES];
+static long lib_end_count[CPUSTATES];
+
+void
+cpu_util_init(void) 
+{
+  return;
+}
+
+void
+cpu_util_terminate(void)
+{
+  return;
+}
+
+int
+get_cpu_method(void)
+{
+  return SYSCTL;
+}
+
+static void
+get_cpu_time(long *cpu_time)
+{
+  size_t cpu_time_len = CPUSTATES * sizeof (cpu_time[0]);
+
+  if (sysctlbyname("kern.cp_time", cpu_time, &cpu_time_len, NULL, 0) == -1) {
+      fprintf (stderr, "Cannot get CPU time!\n");
+      exit (1);
+  }
+}
+
+/* calibrate_sysctl  - perform the idle rate calculation using the
+   sysctl call - typically on BSD */
+
+float
+calibrate_idle_rate(int iterations, int interval)
+{
+  return sysconf (_SC_CLK_TCK);
+}
+
+float
+calc_cpu_util_internal(float elapsed_time)
+{
+  long sum_idle, sum_busy;
+  int i;
+
+  for (sum_busy = 0, i = 0; i < CPUSTATES; i++) {
+    if (i != CP_IDLE)
+      sum_busy += lib_end_count[i] - lib_start_count[i];
+  }
+
+  sum_idle = lib_end_count[CP_IDLE] - lib_start_count[CP_IDLE];
+  lib_local_cpu_util = (float)sum_busy / (float)(sum_busy + sum_idle);
+  lib_local_cpu_util *= 100.0;
+
+  return lib_local_cpu_util;
+
+}
+void
+cpu_start_internal(void)
+{
+  get_cpu_time(lib_start_count);
+}
+
+void
+cpu_stop_internal(void)
+{
+  get_cpu_time(lib_end_count);
+}
diff --git a/netlib.c b/netlib.c
new file mode 100644
index 0000000..bee93c8
--- /dev/null
+++ b/netlib.c
@@ -0,0 +1,4161 @@
+char    netlib_id[]="\
+@(#)netlib.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3";
+
+
+/****************************************************************/
+/*                                                              */
+/*      netlib.c                                                */
+/*                                                              */
+/*      the common utility routines available to all...         */
+/*                                                              */
+/*      establish_control()     establish the control socket    */
+/*      calibrate_local_cpu()   do local cpu calibration        */
+/*      calibrate_remote_cpu()  do remote cpu calibration       */
+/*      send_request()          send a request to the remote    */
+/*      recv_response()         receive a response from remote  */
+/*      send_response()         send a response to the remote   */
+/*      recv_request()          recv a request from the remote  */
+/*      dump_request()          dump request contents           */
+/*      dump_response()         dump response contents          */
+/*      cpu_start()             start measuring cpu             */
+/*      cpu_stop()              stop measuring cpu              */
+/*      calc_cpu_util()         calculate the cpu utilization   */
+/*      calc_service_demand()   calculate the service demand    */
+/*      calc_thruput()          calulate the tput in units      */
+/*      calibrate()             really calibrate local cpu      */
+/*      identify_local()        print local host information    */
+/*      identify_remote()       print remote host information   */
+/*      format_number()         format the number (KB, MB,etc)  */
+/*      format_units()          return the format in english    */
+/*      msec_sleep()            sleep for some msecs            */
+/*      start_timer()           start a timer                   */
+/*                                                              */
+/*      the routines you get when WANT_DLPI is defined...         */
+/*                                                              */
+/*      dl_open()               open a file descriptor and      */
+/*                              attach to the card              */
+/*      dl_mtu()                find the MTU of the card        */
+/*      dl_bind()               bind the sap do the card        */
+/*      dl_connect()            sender's have of connect        */
+/*      dl_accpet()             receiver's half of connect      */
+/*      dl_set_window()         set the window size             */
+/*      dl_stats()              retrieve statistics             */
+/*      dl_send_disc()          initiate disconnect (sender)    */
+/*      dl_recv_disc()          accept disconnect (receiver)    */
+/****************************************************************/
+
+/****************************************************************/
+/*                                                              */
+/*      Global include files                                    */
+/*                                                              */
+/****************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+ /* It would seem that most of the includes being done here from */
+ /* "sys/" actually have higher-level wrappers at just /usr/include. */
+ /* This is based on a spot-check of a couple systems at my disposal. */
+ /* If you have trouble compiling you may want to add "sys/" raj 10/95 */
+#include <limits.h>
+#include <signal.h>
+#ifdef MPE
+#  define NSIG _NSIG
+#endif /* MPE */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
+
+#ifndef WIN32
+ /* at some point, I would like to get rid of all these "sys/" */
+ /* includes where appropriate. if you have a system that requires */
+ /* them, speak now, or your system may not comile later revisions of */
+ /* netperf. raj 1/96 */
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#ifndef MPE
+#include <time.h>
+#include <sys/time.h>
+#endif /* MPE */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#if !defined(MPE) && !defined(__VMS)
+#include <sys/param.h>
+#endif /* MPE */
+
+#else /* WIN32 */
+
+#include <process.h>
+#include <time.h>
+#include <winsock2.h>
+#define netperf_socklen_t socklen_t
+#include <windows.h>
+
+/* the only time someone should need to define DONT_IPV6 in the
+   "sources" file is if they are trying to compile on Windows 2000 or
+   NT4 and I suspect this may not be their only problem :) */
+#ifndef DONT_IPV6
+#include <ws2tcpip.h>
+#endif
+
+#include <windows.h>
+
+#define SIGALRM (14)
+#define sleep(x) Sleep((x)*1000)
+
+#endif /* WIN32 */
+
+#ifdef _AIX
+#include <sys/select.h>
+#include <sys/sched.h>
+#include <sys/pri.h>
+#define PRIORITY PRI_LOW
+#else/* _AIX */
+#ifdef __sgi 
+#include <sys/prctl.h>
+#include <sys/schedctl.h>
+#define PRIORITY NDPLOMIN
+#endif /* __sgi */
+#endif /* _AIX */
+
+#ifdef WANT_DLPI
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/poll.h>
+#ifdef __osf__
+#include <sys/dlpihdr.h>
+#else /* __osf__ */
+#include <sys/dlpi.h>
+#ifdef __hpux
+#include <sys/dlpi_ext.h>
+#endif /* __hpux */
+#endif /* __osf__ */
+#endif /* WANT_DLPI */
+
+#ifdef HAVE_MPCTL
+#include <sys/mpctl.h>
+#endif
+
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
+# include "missing/getaddrinfo.h"
+#endif
+
+
+#ifdef WANT_HISTOGRAM
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+/****************************************************************/
+/*                                                              */
+/*      Local Include Files                                     */
+/*                                                              */
+/****************************************************************/
+#define NETLIB
+#include "netlib.h"
+#include "netsh.h"
+#include "netcpu.h"
+
+/****************************************************************/
+/*                                                              */
+/*      Global constants, macros and variables                  */
+/*                                                              */
+/****************************************************************/
+
+#if defined(WIN32) || defined(__VMS)
+struct  timezone {
+        int     dummy ;
+        } ;
+#ifndef __VMS
+SOCKET     win_kludge_socket = INVALID_SOCKET;
+SOCKET     win_kludge_socket2 = INVALID_SOCKET;
+#endif /* __VMS */
+#endif /* WIN32 || __VMS */
+
+#ifndef LONG_LONG_MAX
+#define LONG_LONG_MAX 9223372036854775807LL
+#endif /* LONG_LONG_MAX */
+
+ /* older versions of netperf knew about the HP kernel IDLE counter. */
+ /* this is now obsolete - in favor of either pstat(), times, or a */
+ /* process-level looper process. we also now require support for the */
+ /* "long" integer type. raj 4/95.  */
+
+int 
+  lib_num_loc_cpus,    /* the number of cpus in the system */
+  lib_num_rem_cpus;    /* how many we think are in the remote */
+
+#define PAGES_PER_CHILD 2
+
+int     lib_use_idle;
+int     cpu_method;
+
+struct  timeval         time1, time2;
+struct  timezone        tz;
+float   lib_elapsed,
+        lib_local_maxrate,
+        lib_remote_maxrate,
+        lib_local_cpu_util,
+        lib_remote_cpu_util;
+
+float   lib_local_per_cpu_util[MAXCPUS];
+int     lib_cpu_map[MAXCPUS];
+
+int     *request_array;
+int     *response_array;
+
+/* INVALID_SOCKET == INVALID_HANDLE_VALUE == (unsigned int)(~0) == -1 */
+SOCKET  netlib_control = INVALID_SOCKET;  
+SOCKET  server_sock = INVALID_SOCKET;
+
+/* global variables to hold the value for processor affinity */
+int     local_proc_affinity,remote_proc_affinity = -1;
+
+/* these are to allow netperf to be run easily through those evil,
+   end-to-end breaking things known as firewalls */
+char local_data_port[10];
+char remote_data_port[10];
+
+char *local_data_address=NULL;
+char *remote_data_address=NULL;
+
+int local_data_family=AF_UNSPEC;
+int remote_data_family=AF_UNSPEC;
+
+ /* in the past, I was overlaying a structure on an array of ints. now */
+ /* I am going to have a "real" structure, and point an array of ints */
+ /* at it. the real structure will be forced to the same alignment as */
+ /* the type "double." this change will mean that pre-2.1 netperfs */
+ /* cannot be mixed with 2.1 and later. raj 11/95 */
+
+union   netperf_request_struct  netperf_request;
+union   netperf_response_struct netperf_response;
+
+FILE    *where;
+
+char    libfmt = '?';
+        
+#ifdef WANT_DLPI
+/* some stuff for DLPI control messages */
+#define DLPI_DATA_SIZE 2048
+
+unsigned long control_data[DLPI_DATA_SIZE];
+struct strbuf control_message = {DLPI_DATA_SIZE, 0, (char *)control_data};
+
+#endif /* WANT_DLPI */
+
+#ifdef WIN32
+HANDLE hAlarm = INVALID_HANDLE_VALUE;
+#endif
+
+int     times_up;
+
+#ifdef WIN32
+ /* we use a getopt implementation from net.sources */
+/*
+ * get option letter from argument vector
+ */
+int
+        opterr = 1,             /* should error messages be printed? */
+        optind = 1,             /* index into parent argv vector */
+        optopt;                 /* character checked for validity */
+char
+        *optarg;                /* argument associated with option */
+
+#define EMSG    ""
+
+#endif /* WIN32 */
+
+static int measuring_cpu;
+int
+netlib_get_page_size(void) {
+
+ /* not all systems seem to have the sysconf for page size. for
+    those  which do not, we will assume that the page size is 8192
+    bytes.  this should be more than enough to be sure that there is
+    no page  or cache thrashing by looper processes on MP
+    systems. otherwise  that's really just too bad - such systems
+    should define  _SC_PAGE_SIZE - raj 4/95 */ 
+
+#ifndef _SC_PAGE_SIZE
+#ifdef WIN32
+
+SYSTEM_INFO SystemInfo;
+
+ GetSystemInfo(&SystemInfo);
+
+ return SystemInfo.dwPageSize;
+#else
+ return(8192L);
+#endif  /* WIN32 */
+#else
+ return(sysconf(_SC_PAGE_SIZE));
+#endif /* _SC_PAGE_SIZE */
+
+}
+
+
+#ifdef WANT_INTERVALS
+static unsigned int usec_per_itvl;
+
+
+void
+stop_itimer()
+
+{
+
+  struct itimerval new_interval;
+  struct itimerval old_interval;
+
+  new_interval.it_interval.tv_sec = 0;
+  new_interval.it_interval.tv_usec = 0;  
+  new_interval.it_value.tv_sec = 0;
+  new_interval.it_value.tv_usec = 0;  
+  if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) {
+    /* there was a problem arming the interval timer */ 
+    perror("netperf: setitimer");
+    exit(1);
+  }
+  return;
+}
+#endif /* WANT_INTERVALS */
+
+
+
+#ifdef WIN32
+static void
+error(char *pch)
+{
+  if (!opterr) {
+    return;             /* without printing */
+    }
+  fprintf(stderr, "%s: %s: %c\n",
+          (NULL != program) ? program : "getopt", pch, optopt);
+}
+
+int
+getopt(int argc, char **argv, char *ostr)
+{
+  static char *place = EMSG;    /* option letter processing */
+  register char *oli;                   /* option letter list index */
+  
+  if (!*place) {
+    /* update scanning pointer */
+      if (optind >= argc || *(place = argv[optind]) != '-' || !*++place) {
+        return EOF; 
+      }
+    if (*place == '-') {
+      /* found "--" */
+        ++optind;
+      place = EMSG ;    /* Added by shiva for Netperf */
+        return EOF;
+    }
+  }
+  
+  /* option letter okay? */
+  if ((optopt = (int)*place++) == (int)':'
+      || !(oli = strchr(ostr, optopt))) {
+    if (!*place) {
+      ++optind;
+    }
+    error("illegal option");
+    return BADCH;
+  }
+  if (*++oli != ':') {  
+    /* don't need argument */
+    optarg = NULL;
+    if (!*place)
+      ++optind;
+  } else {
+    /* need an argument */
+    if (*place) {
+      optarg = place;           /* no white space */
+    } else  if (argc <= ++optind) {
+      /* no arg */
+      place = EMSG;
+      error("option requires an argument");
+      return BADCH;
+    } else {
+      optarg = argv[optind];            /* white space */
+    }
+    place = EMSG;
+    ++optind;
+  }
+  return optopt;                        /* return option letter */
+}
+#endif /* WIN32 */
+
+/*----------------------------------------------------------------------------
+ * WIN32 implementation of perror, does not deal very well with WSA errors
+ * The stdlib.h version of perror only deals with the ancient XENIX error codes.
+ *
+ * +*+SAF Why can't all WSA errors go through GetLastError?  Most seem to...
+ *--------------------------------------------------------------------------*/
+
+#ifdef WIN32
+void PrintWin32Error(FILE *stream, LPSTR text)
+{
+    LPSTR    szTemp;
+    DWORD    dwResult;
+    DWORD    dwError;
+
+    dwError = GetLastError();
+    dwResult = FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
+        NULL, 
+        dwError, 
+        LANG_NEUTRAL, 
+        (LPTSTR)&szTemp, 
+        0, 
+        NULL );
+
+    if (dwResult)
+        fprintf(stream, "%s: %s\n", text, szTemp);
+    else
+        fprintf(stream, "%s: error 0x%x\n", text, dwError);
+	fflush(stream);
+
+    if (szTemp)
+        LocalFree((HLOCAL)szTemp);
+}
+#endif /* WIN32 */
+
+
+char *
+inet_ttos(int type) 
+{
+  switch (type) {
+  case SOCK_DGRAM:
+    return("SOCK_DGRAM");
+    break;
+  case SOCK_STREAM:
+    return("SOCK_STREAM");
+    break;
+  default:
+    return("SOCK_UNKNOWN");
+  }
+}
+
+
+
+char unknown[32];
+
+char *
+inet_ptos(int protocol) {
+  switch (protocol) {
+  case IPPROTO_TCP:
+    return("IPPROTO_TCP");
+    break;
+  case IPPROTO_UDP:
+    return("IPPROTO_UDP");
+    break;
+#if defined(IPPROTO_SCTP)
+  case IPPROTO_SCTP:
+    return("IPPROTO_SCTP");
+    break;
+#endif
+  default:
+    snprintf(unknown,sizeof(unknown),"IPPROTO_UNKNOWN(%d)",protocol);
+    return(unknown);
+  }
+}
+
+/* one of these days, this should not be required */
+#ifndef AF_INET_SDP
+#define AF_INET_SDP 27
+#define PF_INET_SDP AF_INET_SDP
+#endif 
+
+char *
+inet_ftos(int family) 
+{
+  switch(family) {
+  case AF_INET:
+    return("AF_INET");
+    break;
+#if defined(AF_INET6)
+  case AF_INET6:
+    return("AF_INET6");
+    break;
+#endif
+#if defined(AF_INET_SDP)
+  case AF_INET_SDP:
+    return("AF_INET_SDP");
+    break;
+#endif
+  default:
+    return("AF_UNSPEC");
+  }
+}
+
+int
+inet_nton(int af, const void *src, char *dst, int cnt) 
+
+{
+
+  switch (af) {
+  case AF_INET:
+    /* magic constants again... :) */
+    if (cnt >= 4) {
+      memcpy(dst,src,4);
+      return 4;
+    }
+    else {
+      Set_errno(ENOSPC);
+      return(-1);
+    }
+    break;
+#if defined(AF_INET6)
+  case AF_INET6:
+    if (cnt >= 16) {
+      memcpy(dst,src,16);
+      return(16);
+    }
+    else {
+      Set_errno(ENOSPC);
+      return(-1);
+    }
+    break;
+#endif
+  default:
+    Set_errno(EAFNOSUPPORT);
+    return(-1);
+  }
+}
+
+double
+ntohd(double net_double)
+
+{
+  /* we rely on things being nicely packed */
+  union {
+    double whole_thing;
+    unsigned int words[2];
+    unsigned char bytes[8];
+  } conv_rec;
+
+  unsigned char scratch;
+  int i;
+
+  /* on those systems where ntohl is a no-op, we want to return the */
+  /* original value, unchanged */
+
+  if (ntohl(1L) == 1L) {
+    return(net_double);
+  }
+
+  conv_rec.whole_thing = net_double;
+
+  /* we know that in the message passing routines that ntohl will have */
+  /* been called on the 32 bit quantities. we need to put those back */
+  /* the way they belong before we swap */
+  conv_rec.words[0] = htonl(conv_rec.words[0]);
+  conv_rec.words[1] = htonl(conv_rec.words[1]);
+  
+  /* now swap */
+  for (i=0; i<= 3; i++) {
+    scratch = conv_rec.bytes[i];
+    conv_rec.bytes[i] = conv_rec.bytes[7-i];
+    conv_rec.bytes[7-i] = scratch;
+  }
+
+#if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER)
+  if (__FLOAT_WORD_ORDER != __BYTE_ORDER) {
+    /* Fixup mixed endian floating point machines */
+    unsigned int scratch = conv_rec.words[0];
+    conv_rec.words[0] = conv_rec.words[1];
+    conv_rec.words[1] = scratch;
+  }
+#endif
+
+  return(conv_rec.whole_thing);
+  
+}
+
+double
+htond(double host_double)
+
+{
+  /* we rely on things being nicely packed */
+  union {
+    double whole_thing;
+    unsigned int words[2];
+    unsigned char bytes[8];
+  } conv_rec;
+
+  unsigned char scratch;
+  int i;
+
+  /* on those systems where ntohl is a no-op, we want to return the */
+  /* original value, unchanged */
+
+  if (ntohl(1L) == 1L) {
+    return(host_double);
+  }
+
+  conv_rec.whole_thing = host_double;
+
+  /* now swap */
+  for (i=0; i<= 3; i++) {
+    scratch = conv_rec.bytes[i];
+    conv_rec.bytes[i] = conv_rec.bytes[7-i];
+    conv_rec.bytes[7-i] = scratch;
+  }
+  
+#if defined(__FLOAT_WORD_ORDER) && defined(__BYTE_ORDER)
+  if (__FLOAT_WORD_ORDER != __BYTE_ORDER) {
+    /* Fixup mixed endian floating point machines */
+    unsigned int scratch = conv_rec.words[0];
+    conv_rec.words[0] = conv_rec.words[1];
+    conv_rec.words[1] = scratch;
+  }
+#endif
+
+  /* we know that in the message passing routines htonl will */
+  /* be called on the 32 bit quantities. we need to set things up so */
+  /* that when this happens, the proper order will go out on the */
+  /* network */
+  conv_rec.words[0] = htonl(conv_rec.words[0]);
+  conv_rec.words[1] = htonl(conv_rec.words[1]);
+  
+  return(conv_rec.whole_thing);
+  
+}
+
+
+/* one of these days, this should be abstracted-out just like the CPU
+   util stuff.  raj 2005-01-27 */
+int
+get_num_cpus()
+
+{
+
+  /* on HP-UX, even when we use the looper procs we need the pstat */
+  /* call */ 
+
+  int temp_cpus;
+
+#ifdef __hpux
+#include <sys/pstat.h>
+
+  struct pst_dynamic psd;
+
+  if (pstat_getdynamic((struct pst_dynamic *)&psd, 
+                       (size_t)sizeof(psd), (size_t)1, 0) != -1) {
+    temp_cpus = psd.psd_proc_cnt;
+  }
+  else {
+    temp_cpus = 1;
+  }
+
+#else
+  /* MW: <unistd.h> was included for non-Windows systems above. */
+  /* Thus if _SC_NPROC_ONLN is defined, we should be able to use sysconf. */
+#ifdef _SC_NPROCESSORS_ONLN
+  temp_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+#ifdef USE_PERFSTAT
+  temp_cpus = perfstat_cpu(NULL,NULL, sizeof(perfstat_cpu_t), 0);
+#endif /* USE_PERFSTAT */
+
+#else /* no _SC_NPROCESSORS_ONLN */
+
+#ifdef WIN32
+  SYSTEM_INFO SystemInfo;
+  GetSystemInfo(&SystemInfo);
+  
+  temp_cpus = SystemInfo.dwNumberOfProcessors;
+#else
+  /* we need to know some other ways to do this, or just fall-back on */
+  /* a global command line option - raj 4/95 */
+  temp_cpus = shell_num_cpus;
+#endif  /* WIN32 */
+#endif /* _SC_NPROCESSORS_ONLN */
+#endif /*  __hpux */
+
+  if (temp_cpus > MAXCPUS) {
+    fprintf(where,
+            "Sorry, this system has more CPUs (%d) than I can handle (%d).\n",
+            temp_cpus,
+            MAXCPUS);
+    fprintf(where,
+            "Please alter MAXCPUS in netlib.h and recompile.\n");
+    fflush(where);
+    exit(1);
+  }
+
+  return(temp_cpus);
+  
+}  
+
+#ifdef WIN32
+#ifdef __GNUC__
+  #define S64_SUFFIX(x) x##LL
+#else
+  #define S64_SUFFIX(x) x##i64
+#endif
+
+/*
+ * Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
+ */
+#define EPOCH_BIAS  S64_SUFFIX(116444736000000000)
+
+/*
+ * Union to facilitate converting from FILETIME to unsigned __int64
+ */
+typedef union {
+        unsigned __int64 ft_scalar;
+        FILETIME ft_struct;
+} FT;
+
+void
+gettimeofday( struct timeval *tv , struct timezone *not_used )
+{
+        FT nt_time;
+        __int64 UnixTime;  /* microseconds since 1/1/1970 */
+
+        GetSystemTimeAsFileTime( &(nt_time.ft_struct) );
+
+        UnixTime = ((nt_time.ft_scalar - EPOCH_BIAS) / S64_SUFFIX(10));
+        tv->tv_sec = (long)(time_t)(UnixTime / S64_SUFFIX(1000000));
+        tv->tv_usec = (unsigned long)(UnixTime % S64_SUFFIX(1000000));
+}
+#endif /* WIN32 */
+
+     
+
+/************************************************************************/
+/*                                                                      */
+/*      signal catcher                                                  */
+/*                                                                      */
+/************************************************************************/
+
+void
+#if defined(__hpux) 
+catcher(sig, code, scp)
+     int sig;
+     int code;
+     struct sigcontext *scp;
+#else 
+catcher(int sig)
+#endif /* __hpux || __VMS */
+{
+
+#ifdef __hpux
+  if (debug > 2) {
+    fprintf(where,"caught signal %d ",sig);
+    if (scp) {
+      fprintf(where,"while in syscall %d\n",
+              scp->sc_syscall);
+    }
+    else {
+      fprintf(where,"null scp\n");
+    }
+    fflush(where);
+  }
+#endif /* RAJ_DEBUG */
+
+  switch(sig) {
+    
+  case SIGINT:
+    fprintf(where,"netperf: caught SIGINT\n");
+    fflush(where);
+    exit(1);
+    break;
+  case SIGALRM: 
+   if (--test_len_ticks == 0) {
+      /* the test is over */
+      if (times_up != 0) {
+        fprintf(where,"catcher: timer popped with times_up != 0\n");
+        fflush(where);
+      }
+      times_up = 1;
+#if defined(WANT_INTERVALS) && !defined(WANT_SPIN)
+      stop_itimer();
+#endif /* WANT_INTERVALS */
+      break;
+    }
+    else {
+#ifdef WANT_INTERVALS
+#ifdef __hpux
+      /* the test is not over yet and we must have been using the */
+      /* interval timer. if we were in SYS_SIGSUSPEND we want to */
+      /* re-start the system call. Otherwise, we want to get out of */
+      /* the sigsuspend call. I NEED TO KNOW HOW TO DO THIS FOR OTHER */
+      /* OPERATING SYSTEMS. If you know how, please let me know. rick */
+      /* jones <raj@cup.hp.com> */
+      if (scp->sc_syscall != SYS_SIGSUSPEND) {
+        if (debug > 2) {
+          fprintf(where,
+                  "catcher: Time to send burst > interval!\n");
+          fflush(where);
+        }
+        scp->sc_syscall_action = SIG_RESTART;
+      }
+#endif /* __hpux */
+#else /* WANT_INTERVALS */
+      fprintf(where,
+              "catcher: interval timer running unexpectedly!\n");
+      fflush(where);
+      times_up = 1;
+#endif /* WANT_INTERVALS */      
+      break;
+    }
+  }
+  return;
+}
+
+
+void
+install_signal_catchers()
+
+{
+  /* just a simple little routine to catch a bunch of signals */
+
+#ifndef WIN32
+  struct sigaction action;
+  int i;
+
+  fprintf(where,"installing catcher for all signals\n");
+  fflush(where);
+
+  sigemptyset(&(action.sa_mask));
+  action.sa_handler = catcher;
+
+#ifdef SA_INTERRUPT
+  action.sa_flags = SA_INTERRUPT;
+#else /* SA_INTERRUPT */
+  action.sa_flags = 0;
+#endif /* SA_INTERRUPT */
+
+
+  for (i = 1; i <= NSIG; i++) {
+    if (i != SIGALRM) {
+      if (sigaction(i,&action,NULL) != 0) {
+        fprintf(where,
+                "Could not install signal catcher for sig %d, errno %d\n",
+                i,
+                errno);
+        fflush(where);
+
+      }
+    }
+  }
+#else
+  return;
+#endif /* WIN32 */ 
+}
+
+
+#ifdef WIN32
+#define SIGALRM (14)
+void
+emulate_alarm( int seconds )
+{
+	DWORD ErrorCode;
+
+	/* Wait on this event for parm seconds. */
+
+	ErrorCode = WaitForSingleObject(hAlarm, seconds*1000);
+	if (ErrorCode == WAIT_FAILED)
+	{
+		perror("WaitForSingleObject failed");
+		exit(1);
+	}
+
+	if (ErrorCode == WAIT_TIMEOUT)
+	{
+	  /* WaitForSingleObject timed out; this means the timer
+	     wasn't canceled. */
+
+        times_up = 1;
+
+        /* We have yet to find a good way to fully emulate the effects */
+        /* of signals and getting EINTR from system calls under */
+        /* winsock, so what we do here is close the socket out from */
+        /* under the other thread.  It is rather kludgy, but should be */
+        /* sufficient to get this puppy shipped.  The concept can be */
+        /* attributed/blamed :) on Robin raj 1/96 */
+
+        if (win_kludge_socket != INVALID_SOCKET) {
+          closesocket(win_kludge_socket);
+        }
+        if (win_kludge_socket2 != INVALID_SOCKET) {
+          closesocket(win_kludge_socket2);
+        }
+	}
+}
+
+#endif /* WIN32 */
+
+void
+start_timer(int time)
+{
+
+#ifdef WIN32
+	/*+*+SAF What if StartTimer is called twice without the first timer */
+	/*+*+SAF expiring? */
+
+	DWORD  thread_id ;
+	HANDLE tHandle;
+
+	if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE)
+	{
+		/* Create the Alarm event object */
+		hAlarm = CreateEvent( 
+			(LPSECURITY_ATTRIBUTES) NULL,	  /* no security */
+			FALSE,	 /* auto reset event */
+			FALSE,   /* init. state = reset */
+			(void *)NULL);  /* unnamed event object */
+		if (hAlarm == (HANDLE) INVALID_HANDLE_VALUE)
+		{
+			perror("CreateEvent failure");
+			exit(1);
+		}
+	}
+	else
+	{
+		ResetEvent(hAlarm);
+	}
+
+
+	tHandle = CreateThread(0,
+					       0,
+						   (LPTHREAD_START_ROUTINE)emulate_alarm,
+						   (LPVOID)(ULONG_PTR)time,
+						   0,		
+						   &thread_id ) ;
+	CloseHandle(tHandle);
+
+#else /* not WIN32 */
+
+struct sigaction action;
+
+if (debug) {
+  fprintf(where,"About to start a timer for %d seconds.\n",time);
+  fflush(where);
+}
+
+  action.sa_handler = catcher;
+  sigemptyset(&(action.sa_mask));
+  sigaddset(&(action.sa_mask),SIGALRM);
+
+#ifdef SA_INTERRUPT
+  /* on some systems (SunOS 4.blah), system calls are restarted. we do */
+  /* not want that */
+  action.sa_flags = SA_INTERRUPT;
+#else /* SA_INTERRUPT */
+  action.sa_flags = 0;
+#endif /* SA_INTERRUPT */
+
+  if (sigaction(SIGALRM, &action, NULL) < 0) {
+    fprintf(where,"start_timer: error installing alarm handler ");
+    fprintf(where,"errno %d\n",errno);
+    fflush(where);
+    exit(1);
+  }
+
+  /* this is the easy case - just set the timer for so many seconds */ 
+  if (alarm(time) != 0) {
+    fprintf(where,
+            "error starting alarm timer, errno %d\n",
+            errno);
+    fflush(where);
+  }
+#endif /* WIN32 */
+
+  test_len_ticks = 1;
+
+} 
+
+
+ /* this routine will disable any running timer */
+void
+stop_timer()
+{
+#ifndef WIN32
+  alarm(0);
+#else
+  /* at some point we may need some win32 equivalent */
+  	if (hAlarm != (HANDLE) INVALID_HANDLE_VALUE)
+	{
+		SetEvent(hAlarm);
+	}
+#endif /* WIN32 */
+
+}
+
+
+#ifdef WANT_INTERVALS
+ /* this routine will enable the interval timer and set things up so */
+ /* that for a timed test the test will end at the proper time. it */
+ /* should detect the presence of POSIX.4 timer_* routines one of */
+ /* these days */
+void
+start_itimer(unsigned int interval_len_msec )
+{
+
+  unsigned int ticks_per_itvl;
+
+  struct itimerval new_interval;
+  struct itimerval old_interval;
+
+  /* if -DWANT_INTERVALS was used, we will use the ticking of the itimer to */
+  /* tell us when the test is over. while the user will be specifying */
+  /* some number of milliseconds, we know that the interval timer is */
+  /* really in units of 1/HZ. so, to prevent the test from running */
+  /* "long" it would be necessary to keep this in mind when calculating */
+  /* the number of itimer events */
+
+  ticks_per_itvl = ((interval_wate * sysconf(_SC_CLK_TCK) * 1000) / 
+                    1000000);
+
+  if (ticks_per_itvl == 0) ticks_per_itvl = 1;
+
+  /* how many usecs in each interval? */
+  usec_per_itvl = ticks_per_itvl * (1000000 / sysconf(_SC_CLK_TCK));
+
+  /* how many times will the timer pop before the test is over? */
+  if (test_time > 0) {
+    /* this was a timed test */
+    test_len_ticks = (test_time * 1000000) / usec_per_itvl;
+  }
+  else {
+    /* this was not a timed test, use MAXINT */
+    test_len_ticks = INT_MAX;
+  }
+
+  if (debug) {
+    fprintf(where,"setting the interval timer to %d sec %d usec ",
+            usec_per_itvl / 1000000,
+            usec_per_itvl % 1000000);
+    fprintf(where,"test len %d ticks\n",
+            test_len_ticks);
+    fflush(where);
+  }
+
+  /* if this was not a timed test, then we really aught to enable the */
+  /* signal catcher raj 2/95 */
+
+  new_interval.it_interval.tv_sec = usec_per_itvl / 1000000;
+  new_interval.it_interval.tv_usec = usec_per_itvl % 1000000;  
+  new_interval.it_value.tv_sec = usec_per_itvl / 1000000;
+  new_interval.it_value.tv_usec = usec_per_itvl % 1000000;  
+  if (setitimer(ITIMER_REAL,&new_interval,&old_interval) != 0) {
+    /* there was a problem arming the interval timer */ 
+    perror("netperf: setitimer");
+    exit(1);
+  }
+}
+#endif /* WANT_INTERVALS */
+
+void
+netlib_init_cpu_map() {
+
+  int i;
+#ifdef HAVE_MPCTL
+  int num;
+  i = 0;
+  /* I go back and forth on whether this should be the system-wide set
+     of calls, or if the processor set versions (sans the _SYS) should
+     be used.  at the moment I believe that the system-wide version
+     should be used. raj 2006-04-03 */
+  num = mpctl(MPC_GETNUMSPUS_SYS,0,0);
+  lib_cpu_map[i] = mpctl(MPC_GETFIRSTSPU_SYS,0,0);
+  for (i = 1;((i < num) && (i < MAXCPUS)); i++) {
+    lib_cpu_map[i] = mpctl(MPC_GETNEXTSPU_SYS,lib_cpu_map[i-1],0);
+  }
+  /* from here, we set them all to -1 because if we launch more
+     loopers than actual CPUs, well, I'm not sure why :) */
+  for (; i < MAXCPUS; i++) {
+    lib_cpu_map[i] = -1;
+  }
+
+#else
+  /* we assume that there is indeed a contiguous mapping */
+  for (i = 0; i < MAXCPUS; i++) {
+    lib_cpu_map[i] = i;
+  }
+#endif
+}
+
+
+/****************************************************************/
+/*                                                              */
+/*      netlib_init()                                           */
+/*                                                              */
+/*      initialize the performance library...                   */
+/*                                                              */
+/****************************************************************/
+
+void
+netlib_init()
+{
+  int i;
+
+  where            = stdout;
+
+  request_array = (int *)(&netperf_request);
+  response_array = (int *)(&netperf_response);
+
+  for (i = 0; i < MAXCPUS; i++) {
+    lib_local_per_cpu_util[i] = 0.0;
+  }
+
+  /* on those systems where we know that CPU numbers may not start at
+     zero and be contiguous, we provide a way to map from a
+     contiguous, starting from 0 CPU id space to the actual CPU ids.
+     at present this is only used for the netcpu_looper stuff because
+     we ass-u-me that someone setting processor affinity from the
+     netperf commandline will provide a "proper" CPU identifier. raj
+     2006-04-03 */
+
+  netlib_init_cpu_map();
+
+  if (debug) {
+    fprintf(where,
+            "netlib_init: request_array at %p\n",
+            request_array);
+    fprintf(where,
+            "netlib_init: response_array at %p\n",
+            response_array);
+
+    fflush(where);
+  }
+
+}
+
+ /* this routine will conver the string into an unsigned integer. it */
+ /* is used primarily for the command-line options taking a number */
+ /* (such as the socket size) which could be rather large. If someone */
+ /* enters 32M, then the number will be converted to 32 * 1024 * 1024. */
+ /* If they inter 32m, the number will be converted to 32 * 1000 * */
+ /* 1000 */
+unsigned int
+convert(char *string)
+
+{
+  unsigned int base;
+  base = atoi(string);
+  if (strstr(string,"K")) {
+    base *= 1024;
+  }
+  if (strstr(string,"M")) {
+    base *= (1024 * 1024);
+  }
+  if (strstr(string,"G")) {
+    base *= (1024 * 1024 * 1024);
+  }
+  if (strstr(string,"k")) {
+    base *= (1000);
+  }
+  if (strstr(string,"m")) {
+    base *= (1000 * 1000);
+  }
+  if (strstr(string,"g")) {
+    base *= (1000 * 1000 * 1000);
+  }
+  return(base);
+}
+
+/* this routine is like convert, but it is used for an interval time
+   specification instead of stuff like socket buffer or send sizes.
+   it converts everything to microseconds for internal use.  if there
+   is an 'm' at the end it assumes the user provided milliseconds, s
+   will imply seconds, u will imply microseconds.  in the future n
+   will imply nanoseconds but for now it will be ignored. if there is
+   no suffix or an unrecognized suffix, it will be assumed the user
+   provided milliseconds, which was the long-time netperf default. one
+   of these days, we should probably revisit that nanosecond business
+   wrt the return value being just an int rather than a uint64_t or
+   something.  raj 2006-02-06 */
+
+unsigned int
+convert_timespec(char *string) {
+
+  unsigned int base;
+  base = atoi(string);
+  if (strstr(string,"m")) {
+    base *= 1000;
+  }
+  else if (strstr(string,"u")) {
+    base *= (1);
+  }
+  else if (strstr(string,"s")) {
+    base *= (1000 * 1000);
+  }
+  else {
+    base *= (1000);
+  }
+  return(base);
+}
+
+
+ /* this routine will allocate a circular list of buffers for either */
+ /* send or receive operations. each of these buffers will be aligned */
+ /* and offset as per the users request. the circumference of this */
+ /* ring will be controlled by the setting of send_width. the buffers */
+ /* will be filled with data from the file specified in fill_file. if */
+ /* fill_file is an empty string, the buffers will not be filled with */
+ /* any particular data */
+
+struct ring_elt *
+allocate_buffer_ring(int width, int buffer_size, int alignment, int offset)
+{
+
+  struct ring_elt *first_link = NULL;
+  struct ring_elt *temp_link  = NULL;
+  struct ring_elt *prev_link;
+
+  int i;
+  int malloc_size;
+  int bytes_left;
+  int bytes_read;
+  int do_fill;
+
+  FILE *fill_source;
+  char default_fill[] = "netperf";
+  int  fill_cursor = 0;
+
+  malloc_size = buffer_size + alignment + offset;
+
+  /* did the user wish to have the buffers pre-filled with data from a */
+  /* particular source? */
+  if (strcmp(fill_file,"") == 0) {
+    do_fill = 0;
+    fill_source = NULL;
+  }
+  else {
+    do_fill = 1;
+    fill_source = (FILE *)fopen(fill_file,"r");
+    if (fill_source == (FILE *)NULL) {
+      perror("Could not open requested fill file");
+      exit(1);
+    }
+  }
+
+  assert(width >= 1);
+
+  prev_link = NULL;
+  for (i = 1; i <= width; i++) {
+    /* get the ring element */
+    temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt));
+    if (temp_link == NULL) {
+      printf("malloc(%u) failed!\n", sizeof(struct ring_elt));
+      exit(1);
+    }
+    /* remember the first one so we can close the ring at the end */
+    if (i == 1) {
+      first_link = temp_link;
+    }
+    temp_link->buffer_base = (char *)malloc(malloc_size);
+    if (temp_link == NULL) {
+      printf("malloc(%d) failed!\n", malloc_size);
+      exit(1);
+	}
+
+#ifndef WIN32
+    temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) + 
+                          (long)alignment - 1) &        
+                         ~((long)alignment - 1));
+#else
+    temp_link->buffer_ptr = (char *)(( (ULONG_PTR)(temp_link->buffer_base) + 
+                          (ULONG_PTR)alignment - 1) &   
+                         ~((ULONG_PTR)alignment - 1));
+#endif
+    temp_link->buffer_ptr += offset;
+    /* is where the buffer fill code goes. */
+    if (do_fill) {
+      char *bufptr = temp_link->buffer_ptr;
+      bytes_left = buffer_size;
+      while (bytes_left) {
+        if (((bytes_read = (int)fread(bufptr,
+				      1,
+				      bytes_left,
+				      fill_source)) == 0) &&
+            (feof(fill_source))){
+          rewind(fill_source);
+        }
+	bufptr += bytes_read;
+        bytes_left -= bytes_read;
+      }
+    }
+    else {
+      /* use the default fill to ID our data traffic on the
+	 network. it ain't exactly pretty, but it should work */
+      int j;
+      char *bufptr = temp_link->buffer_ptr;
+      for (j = 0; j < buffer_size; j++) {
+	bufptr[j] = default_fill[fill_cursor];
+	fill_cursor += 1;
+	/* the Windows DDK compiler with an x86_64 target wants a cast
+	   here */
+	if (fill_cursor >  (int)strlen(default_fill)) {
+	  fill_cursor = 0;
+	}
+      }
+
+    }
+    temp_link->next = prev_link;
+    prev_link = temp_link;
+  }
+  if (first_link) {  /* SAF Prefast made me do it... */
+    first_link->next = temp_link;
+  }
+
+  return(first_link); /* it's a circle, doesn't matter which we return */
+}
+
+/* this routine will dirty the first dirty_count bytes of the
+   specified buffer and/or read clean_count bytes from the buffer. it
+   will go N bytes at a time, the only question is how large should N
+   be and if we should be going continguously, or based on some
+   assumption of cache line size */
+
+void
+access_buffer(char *buffer_ptr,int length, int dirty_count, int clean_count) {
+
+  char *temp_buffer;
+  char *limit;
+  int  i, dirty_totals;
+
+  temp_buffer = buffer_ptr;
+  limit = temp_buffer + length;
+  dirty_totals = 0;
+
+  for (i = 0; 
+       ((i < dirty_count) && (temp_buffer < limit));
+       i++) {
+    *temp_buffer += (char)i;
+    dirty_totals += *temp_buffer;
+    temp_buffer++;
+  }
+
+  for (i = 0; 
+       ((i < clean_count) && (temp_buffer < limit));
+       i++) {
+    dirty_totals += *temp_buffer;
+    temp_buffer++;
+  }
+
+  if (debug > 100) {
+    fprintf(where,
+	    "This was here to try to avoid dead-code elimination %d\n",
+	    dirty_totals);
+    fflush(where);
+  }
+}
+
+
+#ifdef HAVE_ICSC_EXS
+
+#include <sys/mman.h>
+#include <sys/exs.h>
+
+ /* this routine will allocate a circular list of buffers for either */
+ /* send or receive operations. each of these buffers will be aligned */
+ /* and offset as per the users request. the circumference of this */
+ /* ring will be controlled by the setting of send_width. the buffers */
+ /* will be filled with data from the file specified in fill_file. if */
+ /* fill_file is an empty string, the buffers will not be filled with */
+ /* any particular data */
+
+struct ring_elt *
+allocate_exs_buffer_ring (int width, int buffer_size, int alignment, int offset, exs_mhandle_t *mhandlep)
+{
+
+    struct ring_elt *first_link;
+    struct ring_elt *temp_link;
+    struct ring_elt *prev_link;
+
+    int i;
+    int malloc_size;
+    int bytes_left;
+    int bytes_read;
+    int do_fill;
+
+    FILE *fill_source;
+
+    int mmap_size;
+    char *mmap_buffer, *mmap_buffer_aligned;
+
+    malloc_size = buffer_size + alignment + offset;
+
+    /* did the user wish to have the buffers pre-filled with data from a */
+    /* particular source? */
+    if (strcmp (fill_file, "") == 0) {
+        do_fill = 0;
+        fill_source = NULL;
+    } else {
+        do_fill = 1;
+        fill_source = (FILE *) fopen (fill_file, "r");
+        if (fill_source == (FILE *) NULL) {
+            perror ("Could not open requested fill file");
+            exit (1);
+        }
+    }
+
+    assert (width >= 1);
+
+    if (debug) {
+        fprintf (where, "allocate_exs_buffer_ring: "
+                 "width=%d buffer_size=%d alignment=%d offset=%d\n",
+                 width, buffer_size, alignment, offset);
+    }
+
+    /* allocate shared memory */
+    mmap_size = width * malloc_size;
+    mmap_buffer = (char *) mmap ((caddr_t)NULL, mmap_size+NBPG-1,
+                                 PROT_READ|PROT_WRITE,
+                                 MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+    if (mmap_buffer == NULL) {
+        perror ("allocate_exs_buffer_ring: mmap failed");
+        exit (1);
+    }
+    mmap_buffer_aligned = (char *) ((uintptr_t)mmap_buffer & ~(NBPG-1));
+    if (debug) {
+        fprintf (where, "allocate_exs_buffer_ring: "
+                 "mmap buffer size=%d address=0x%p aligned=0x%p\n",
+                 mmap_size, mmap_buffer, mmap_buffer_aligned);
+    }
+
+    /* register shared memory */
+    *mhandlep = exs_mregister ((void *)mmap_buffer_aligned, (size_t)mmap_size, 0);
+    if (*mhandlep == EXS_MHANDLE_INVALID) {
+        perror ("allocate_exs_buffer_ring: exs_mregister failed");
+        exit (1);
+    }
+    if (debug) {
+        fprintf (where, "allocate_exs_buffer_ring: mhandle=%d\n",
+                 *mhandlep);
+    }
+
+    /* allocate ring elements */
+    first_link = (struct ring_elt *) malloc (width * sizeof (struct ring_elt));
+    if (first_link == NULL) {
+        printf ("malloc(%d) failed!\n", width * sizeof (struct ring_elt));
+        exit (1);
+    }
+
+    /* initialize buffer ring */
+    prev_link = first_link + width - 1;
+
+    for (i = 0, temp_link = first_link; i < width; i++, temp_link++) {
+
+        temp_link->buffer_base = (char *) mmap_buffer_aligned + (i*malloc_size);
+#ifndef WIN32
+        temp_link->buffer_ptr = (char *)
+            (((long)temp_link->buffer_base + (long)alignment - 1) &
+             ~((long)alignment - 1));
+#else
+        temp_link->buffer_ptr = (char *)
+            (((ULONG_PTR)temp_link->buffer_base + (ULONG_PTR)alignment - 1) &
+             ~((ULONG_PTR)alignment - 1));
+#endif
+        temp_link->buffer_ptr += offset;
+
+        if (debug) {
+            fprintf (where, "allocate_exs_buffer_ring: "
+                     "buffer: index=%d base=0x%p ptr=0x%p\n",
+                     i, temp_link->buffer_base, temp_link->buffer_ptr);
+        }
+
+        /* is where the buffer fill code goes. */
+        if (do_fill) {
+            bytes_left = buffer_size;
+            while (bytes_left) {
+                if (((bytes_read = (int) fread (temp_link->buffer_ptr,
+                                                1,
+                                                bytes_left,
+                                                fill_source)) == 0) &&
+                    (feof (fill_source))) {
+                    rewind (fill_source);
+                }
+                bytes_left -= bytes_read;
+            }
+        }
+
+        /* do linking */
+        prev_link->next = temp_link;
+        prev_link = temp_link;
+    }
+
+    return (first_link);        /* it's a circle, doesn't matter which we return */
+}
+
+#endif /* HAVE_ICSC_EXS */
+
+
+
+#ifdef HAVE_SENDFILE
+/* this routine will construct a ring of sendfile_ring_elt structs
+   that the routine sendfile_tcp_stream() will use to get parameters
+   to its calls to sendfile(). It will setup the ring to point at the
+   file specified in the global -F option that is already used to
+   pre-fill buffers in the send() case. 08/2000
+
+   if there is no file specified in a global -F option, we will create
+   a tempoarary file and fill it with random data and use that
+   instead.  raj 2007-08-09 */
+
+struct sendfile_ring_elt *
+alloc_sendfile_buf_ring(int width,
+                        int buffer_size,
+                        int alignment,
+                        int offset)
+
+{
+
+  struct sendfile_ring_elt *first_link = NULL;
+  struct sendfile_ring_elt *temp_link  = NULL;
+  struct sendfile_ring_elt *prev_link;
+  
+  int i;
+  int fildes;
+  struct stat statbuf;
+
+  /* if the user has not specified a file with the -F option, we will
+     fail the test. otherwise, go ahead and try to open the
+     file. 08/2000 */
+  if (strcmp(fill_file,"") == 0) {
+    /* use an temp file for the fill file */
+    char *temp_file;
+    int *temp_buffer;
+    
+    /* make sure we have at least an ints worth, even if the user is
+       using an insane buffer size for a sendfile test. we are
+       ass-u-me-ing that malloc will return something at least aligned
+       on an int boundary... */
+    temp_buffer = (int *) malloc(buffer_size + sizeof(int));
+    if (temp_buffer) {
+      /* ok, we have the buffer we are going to write, lets get a
+	 temporary filename */
+      temp_file = tmpnam(NULL);
+      if (NULL != temp_file) {
+	fildes = open(temp_file,O_RDWR | O_EXCL | O_CREAT,0600);
+	if (-1 != fildes) {
+	  int count;
+	  int *int_ptr;
+
+	  /* initialize the random number generator */
+	  srand(getpid());
+
+	  /* unlink the file so it goes poof when we
+	     exit. unless/until shown to be a problem we will
+	     blissfully ignore the return value. raj 2007-08-09 */
+	  unlink(temp_file);
+
+	  /* now fill-out the file with at least buffer_size * width bytes */
+	  for (count = 0; count < width; count++) {
+	    /* fill the buffer with random data.  it doesn't have to be
+	       really random, just "random enough" :) we do this here rather
+	       than up above because we want each write to the file to be
+	       different random data */
+	    int_ptr = temp_buffer;
+	    for (i = 0; i <= buffer_size/sizeof(int); i++) {
+	      *int_ptr = rand();
+	      int_ptr++;
+	    }
+	    if (write(fildes,temp_buffer,buffer_size+sizeof(int)) !=
+		buffer_size + sizeof(int)) {
+	      perror("allocate_sendfile_buf_ring: incomplete write");
+	      exit(-1);
+	    }
+	  }
+	}
+	else {
+	  perror("allocate_sendfile_buf_ring: could not open tempfile");
+	  exit(-1);
+	}
+      }
+      else {
+	perror("allocate_sendfile_buf_ring: could not allocate temp name");
+	exit(-1);
+      }
+    }
+    else {
+      perror("alloc_sendfile_buf_ring: could not allocate buffer for file");
+      exit(-1);
+    }
+  }
+  else {
+    /* the user pointed us at a file, so try it */
+    fildes = open(fill_file , O_RDONLY);
+    if (fildes == -1){
+      perror("alloc_sendfile_buf_ring: Could not open requested file");
+      exit(1);
+    }
+    /* make sure there is enough file there to allow us to make a
+       complete ring. that way we do not need additional logic in the
+       ring setup to deal with wrap-around issues. we might want that
+       someday, but not just now. 08/2000 */
+    if (stat(fill_file,&statbuf) != 0) {
+      perror("alloc_sendfile_buf_ring: could not stat file");
+      exit(1);
+    }
+    if (statbuf.st_size < (width * buffer_size)) {
+      /* the file is too short */
+      fprintf(stderr,"alloc_sendfile_buf_ring: specified file too small.\n");
+      fprintf(stderr,"file must be larger than send_width * send_size\n");
+      fflush(stderr);
+      exit(1);
+    }
+  }
+  
+  /* so, at this point we know that fildes is a descriptor which
+     references a file of sufficient size for our nefarious
+     porpoises. raj 2007-08-09 */
+
+  prev_link = NULL;
+  for (i = 1; i <= width; i++) {
+    /* get the ring element. we should probably make sure the malloc() 
+     was successful, but for now we'll just let the code bomb
+     mysteriously. 08/2000 */
+
+    temp_link = (struct sendfile_ring_elt *)
+      malloc(sizeof(struct sendfile_ring_elt));
+    if (temp_link == NULL) {
+      printf("malloc(%u) failed!\n", sizeof(struct sendfile_ring_elt));
+      exit(1);
+	}
+
+    /* remember the first one so we can close the ring at the end */
+
+    if (i == 1) {
+      first_link = temp_link;
+    }
+
+    /* now fill-in the fields of the structure with the apropriate
+       stuff. just how should we deal with alignment and offset I
+       wonder? until something better comes-up, I think we will just
+       ignore them. 08/2000 */
+
+    temp_link->fildes = fildes;      /* from which file do we send? */
+    temp_link->offset = offset;      /* starting at which offset? */
+    offset += buffer_size;           /* get ready for the next elt */
+    temp_link->length = buffer_size; /* how many bytes to send */
+    temp_link->hdtrl = NULL;         /* no header or trailer */
+    temp_link->flags = 0;            /* no flags */
+
+    /* is where the buffer fill code went. */
+
+    temp_link->next = prev_link;
+    prev_link = temp_link;
+  }
+  /* close the ring */
+  first_link->next = temp_link;
+  
+  return(first_link); /* it's a dummy ring */
+}
+
+#endif /* HAVE_SENDFILE */
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     dump_request()                                                  */
+ /*                                                                     */
+ /* display the contents of the request array to the user. it will      */
+ /* display the contents in decimal, hex, and ascii, with four bytes    */
+ /* per line.                                                           */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+dump_request()
+{
+int counter = 0;
+fprintf(where,"request contents:\n");
+for (counter = 0; counter < ((sizeof(netperf_request)/4)-3); counter += 4) {
+  fprintf(where,"%d:\t%8x %8x %8x %8x \t|%4.4s| |%4.4s| |%4.4s| |%4.4s|\n",
+          counter,
+          request_array[counter],
+          request_array[counter+1],
+          request_array[counter+2],
+          request_array[counter+3],
+          (char *)&request_array[counter],
+          (char *)&request_array[counter+1],
+          (char *)&request_array[counter+2],
+          (char *)&request_array[counter+3]);
+}
+fflush(where);
+}
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     dump_response()                                                 */
+ /*                                                                     */
+ /* display the content of the response array to the user. it will      */
+ /* display the contents in decimal, hex, and ascii, with four bytes    */
+ /* per line.                                                           */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+dump_response()
+{
+int counter = 0;
+
+fprintf(where,"response contents\n");
+for (counter = 0; counter < ((sizeof(netperf_response)/4)-3); counter += 4) {
+  fprintf(where,"%d:\t%8x %8x %8x %8x \t>%4.4s< >%4.4s< >%4.4s< >%4.4s<\n",
+          counter,
+          response_array[counter],
+          response_array[counter+1],
+          response_array[counter+2],
+          response_array[counter+3],
+          (char *)&response_array[counter],
+          (char *)&response_array[counter+1],
+          (char *)&response_array[counter+2],
+          (char *)&response_array[counter+3]);
+}
+fflush(where);
+}
+
+ /*
+
+      format_number()                                                 
+                                                                    
+  return a pointer to a formatted string containing the value passed
+  translated into the units specified. It assumes that the base units
+  are bytes. If the format calls for bits, it will use SI units (10^)
+  if the format calls for bytes, it will use CS units (2^)...  This
+  routine should look familiar to uses of the latest ttcp...
+
+  we would like to use "t" or "T" for transactions, but probably
+  should leave those for terabits and terabytes respectively, so for
+  transactions, we will use "x" which will, by default, do absolutely
+  nothing to the result.  why?  so we don't have to special case code
+  elsewhere such as in the TCP_RR-as-bidirectional test case.
+
+ */
+ 
+
+char *
+format_number(double number)
+{
+  static  char    fmtbuf[64];
+        
+  switch (libfmt) {
+  case 'K':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f" , number / 1024.0);
+    break;
+  case 'M':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number / 1024.0 / 1024.0);
+    break;
+  case 'G':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number / 1024.0 / 1024.0 / 1024.0);
+    break;
+  case 'k':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number * 8 / 1000.0);
+    break;
+  case 'm':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number * 8 / 1000.0 / 1000.0);
+    break;
+  case 'g':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number * 8 / 1000.0 / 1000.0 / 1000.0);
+    break;
+  case 'x':
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number);
+    break;
+  default:
+    snprintf(fmtbuf, sizeof(fmtbuf),  "%-7.2f", number / 1024.0);
+  }
+
+  return fmtbuf;
+}
+
+char
+format_cpu_method(int method)
+{
+
+  char method_char;
+
+  switch (method) {
+  case CPU_UNKNOWN:
+    method_char = 'U';
+    break;
+  case HP_IDLE_COUNTER:
+    method_char = 'I';
+    break;
+  case PSTAT:
+    method_char = 'P';
+    break;
+  case KSTAT:
+    method_char = 'K';
+    break;
+  case KSTAT_10:
+    method_char = 'M';
+    break;
+  case PERFSTAT:
+    method_char = 'E';
+    break;
+  case TIMES:             /* historical only, completely unsuitable
+			     for netperf's purposes */
+    method_char = 'T';
+    break;
+  case GETRUSAGE:         /* historical only, completely unsuitable
+			     for netperf;s purposes */
+    method_char = 'R';
+    break;
+  case LOOPER:
+    method_char = 'L';
+    break;
+  case NT_METHOD:
+    method_char = 'N';
+    break;
+  case PROC_STAT:
+    method_char = 'S';
+    break;
+  case SYSCTL:
+    method_char = 'C';
+    break;
+  case OSX:
+    method_char = 'O';
+    break;
+  default:
+    method_char = '?';
+  }
+  
+  return method_char;
+
+}
+
+char *
+format_units()
+{
+  static        char    unitbuf[64];
+  
+  switch (libfmt) {
+  case 'K':
+    strcpy(unitbuf, "KBytes");
+    break;
+  case 'M':
+    strcpy(unitbuf, "MBytes");
+    break;
+  case 'G':
+    strcpy(unitbuf, "GBytes");
+    break;
+  case 'k':
+    strcpy(unitbuf, "10^3bits");
+    break;
+  case 'm':
+    strcpy(unitbuf, "10^6bits");
+    break;
+  case 'g':
+    strcpy(unitbuf, "10^9bits");
+    break;
+  case 'x':
+    strcpy(unitbuf, "Trans");
+    break;
+    
+  default:
+    strcpy(unitbuf, "KBytes");
+  }
+  
+  return unitbuf;
+}
+
+
+/****************************************************************/
+/*                                                              */
+/*      shutdown_control()                                      */
+/*                                                              */
+/* tear-down the control connection between me and the server.  */
+/****************************************************************/
+
+void 
+shutdown_control()
+{
+
+  char  *buf = (char *)&netperf_response;
+  int   buflen = sizeof(netperf_response);
+
+  /* stuff for select, use fd_set for better compliance */
+  fd_set        readfds;
+  struct        timeval timeout;
+
+  if (debug) {
+    fprintf(where,
+            "shutdown_control: shutdown of control connection requested.\n");
+    fflush(where);
+  }
+
+  /* first, we say that we will be sending no more data on the */
+  /* connection */
+  if (shutdown(netlib_control,1) == SOCKET_ERROR) {
+    Print_errno(where,
+            "shutdown_control: error in shutdown");
+    fflush(where);
+    exit(1);
+  }
+
+  /* Now, we hang on a select waiting for the socket to become */
+  /* readable to receive the shutdown indication from the remote. this */
+  /* will be "just" like the recv_response() code */
+
+  /* we only select once. it is assumed that if the response is split */
+  /* (which should not be happening, that we will receive the whole */
+  /* thing and not have a problem ;-) */
+
+  FD_ZERO(&readfds);
+  FD_SET(netlib_control,&readfds);
+  timeout.tv_sec  = 60; /* wait one minute then punt */
+  timeout.tv_usec = 0;
+
+  /* select had better return one, or there was either a problem or a */
+  /* timeout... */
+  if (select(FD_SETSIZE,
+             &readfds,
+             0,
+             0,
+             &timeout) != 1) {
+    Print_errno(where,
+            "shutdown_control: no response received");
+    fflush(where);
+    exit(1);
+  }
+
+  /* we now assume that the socket has come ready for reading */
+  recv(netlib_control, buf, buflen,0);
+
+}
+
+/* 
+  bind_to_specific_processor will bind the calling process to the
+  processor in "processor"  It has lots of ugly ifdefs to deal with
+  all the different ways systems do processor affinity.  this is a
+  generalization of work initially done by stephen burger.  raj
+  2004/12/13 */
+
+void
+bind_to_specific_processor(int processor_affinity, int use_cpu_map)
+{
+
+  int mapped_affinity;
+
+  /* this is in place because the netcpu_looper processor affinity
+     ass-u-me-s a contiguous CPU id space starting with 0. for the
+     regular netperf/netserver affinity, we ass-u-me the user has used
+     a suitable CPU id even when the space is not contiguous and
+     starting from zero */
+  if (use_cpu_map) {
+    mapped_affinity = lib_cpu_map[processor_affinity];
+  }
+  else {
+    mapped_affinity = processor_affinity;
+  }
+
+#ifdef HAVE_MPCTL
+  /* indeed, at some point it would be a good idea to check the return
+     status and pass-along notification of error... raj 2004/12/13 */
+  mpctl(MPC_SETPROCESS_FORCE, mapped_affinity, getpid());
+#elif HAVE_PROCESSOR_BIND
+#include <sys/types.h>
+#include <sys/processor.h>
+#include <sys/procset.h>
+  processor_bind(P_PID,P_MYID,mapped_affinity,NULL);
+#elif HAVE_BINDPROCESSOR
+#include <sys/processor.h>
+  /* this is the call on AIX.  It takes a "what" of BINDPROCESS or
+     BINDTHRAD, then "who" and finally "where" which is a CPU number
+     or it seems PROCESSOR_CLASS_ANY there also seems to be a mycpu()
+     call to return the current CPU assignment.  this is all based on
+     the sys/processor.h include file.  from empirical testing, it
+     would seem that the my_cpu() call returns the current CPU on
+     which we are running rather than the CPU binding, so it's return
+     value will not tell you if you are bound vs unbound. */
+  bindprocessor(BINDPROCESS,getpid(),(cpu_t)mapped_affinity);
+#elif HAVE_SCHED_SETAFFINITY
+#include <sched.h>
+  /* in theory this should cover systems with more CPUs than bits in a
+     long, without having to specify __USE_GNU.  we "cheat" by taking
+     defines from /usr/include/bits/sched.h, which we ass-u-me is
+     included by <sched.h>.  If they are not there we will just
+     fall-back on what we had before, which is to use just the size of
+     an unsigned long. raj 2006-09-14 */
+
+#if defined(__CPU_SETSIZE)
+#define NETPERF_CPU_SETSIZE __CPU_SETSIZE
+#define NETPERF_CPU_SET(cpu, cpusetp)  __CPU_SET(cpu, cpusetp)
+#define NETPERF_CPU_ZERO(cpusetp)      __CPU_ZERO (cpusetp)
+  typedef cpu_set_t netperf_cpu_set_t;
+#else
+#define NETPERF_CPU_SETSIZE sizeof(unsigned long)
+#define NETPERF_CPU_SET(cpu, cpusetp) *cpusetp = 1 << cpu
+#define NETPERF_CPU_ZERO(cpusetp) *cpusetp = (unsigned long)0
+  typedef unsigned long netperf_cpu_set_t;
+#endif
+
+  netperf_cpu_set_t   netperf_cpu_set;
+  unsigned int        len = sizeof(netperf_cpu_set);
+
+  if (mapped_affinity < 8*sizeof(netperf_cpu_set)) {
+    NETPERF_CPU_ZERO(&netperf_cpu_set);
+    NETPERF_CPU_SET(mapped_affinity,&netperf_cpu_set);
+    
+    if (sched_setaffinity(getpid(), len, &netperf_cpu_set)) {
+      if (debug) {
+	fprintf(stderr, "failed to set PID %d's CPU affinity errno %d\n",
+		getpid(),errno);
+	fflush(stderr);
+      }
+    }
+  }
+  else {
+    if (debug) {
+	fprintf(stderr,
+		"CPU number larger than pre-compiled limits. Consider a recompile.\n");
+	fflush(stderr);
+      }
+  }
+      
+#elif HAVE_BIND_TO_CPU_ID
+  /* this is the one for Tru64 */
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/processor.h>
+
+  /* really should be checking a return code one of these days. raj
+     2005/08/31 */ 
+
+  bind_to_cpu_id(getpid(), mapped_affinity,0);
+
+#elif WIN32
+
+  {
+    ULONG_PTR AffinityMask;
+    ULONG_PTR ProcessAffinityMask;
+    ULONG_PTR SystemAffinityMask;
+    
+    if ((mapped_affinity < 0) || 
+	(mapped_affinity > MAXIMUM_PROCESSORS)) {
+      fprintf(where,
+	      "Invalid processor_affinity specified: %d\n", mapped_affinity);      fflush(where);
+      return;
+    }
+    
+    if (!GetProcessAffinityMask(
+				GetCurrentProcess(), 
+				&ProcessAffinityMask, 
+				&SystemAffinityMask))
+      {
+	perror("GetProcessAffinityMask failed");
+	fflush(stderr);
+	exit(1);
+      }
+    
+    AffinityMask = (ULONG_PTR)1 << mapped_affinity;
+    
+    if (AffinityMask & ProcessAffinityMask) {
+      if (!SetThreadAffinityMask( GetCurrentThread(), AffinityMask)) {
+	perror("SetThreadAffinityMask failed");
+	fflush(stderr);
+      }
+    } else if (debug) {
+      fprintf(where,
+	      "Processor affinity set to CPU# %d\n", mapped_affinity);
+      fflush(where);
+    }
+  }
+
+#else
+  if (debug) {
+    fprintf(where,
+	    "Processor affinity not available for this platform!\n");
+    fflush(where);
+  }
+#endif
+}
+
+
+/*
+ * Sets a socket to non-blocking operation.
+ */
+int
+set_nonblock (SOCKET sock)
+{
+#ifdef WIN32
+  unsigned long flags = 1;
+  return (ioctlsocket(sock, FIONBIO, &flags) != SOCKET_ERROR);
+#else
+  return (fcntl(sock, F_SETFL, O_NONBLOCK) != -1);
+#endif
+}
+
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     send_request()                                                  */
+ /*                                                                     */
+ /* send a netperf request on the control socket to the remote half of  */
+ /* the connection. to get us closer to intervendor interoperability,   */
+ /* we will call htonl on each of the int that compose the message to   */
+ /* be sent. the server-half of the connection will call the ntohl      */
+ /* routine to undo any changes that may have been made...              */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+send_request()
+{
+  int   counter=0;
+  
+  /* display the contents of the request if the debug level is high */
+  /* enough. otherwise, just send the darned thing ;-) */
+  
+  if (debug > 1) {
+    fprintf(where,"entered send_request...contents before htonl:\n");
+    dump_request();
+  }
+
+  /* pass the processor affinity request value to netserver */
+  /* this is a kludge and I know it.  sgb 8/11/04           */
+
+  netperf_request.content.dummy = remote_proc_affinity;
+
+  /* put the entire request array into network order. We do this */
+  /* arbitrarily rather than trying to figure-out just how much */
+  /* of the request array contains real information. this should */
+  /* be simpler, and at any rate, the performance of sending */
+  /* control messages for this benchmark is not of any real */
+  /* concern. */ 
+  
+  for (counter=0;counter < sizeof(netperf_request)/4; counter++) {
+    request_array[counter] = htonl(request_array[counter]);
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"send_request...contents after htonl:\n");
+    dump_request();
+
+    fprintf(where,
+            "\nsend_request: about to send %u bytes from %p\n",
+            sizeof(netperf_request),
+            &netperf_request);
+    fflush(where);
+  }
+
+  if (send(netlib_control,
+           (char *)&netperf_request,
+           sizeof(netperf_request),
+           0) != sizeof(netperf_request)) {
+    perror("send_request: send call failure");
+    
+    exit(1);
+  }
+}
+
+/***********************************************************************/
+ /*                                                                     */
+ /*     send_response()                                                 */
+ /*                                                                     */
+ /* send a netperf response on the control socket to the remote half of */
+ /* the connection. to get us closer to intervendor interoperability,   */
+ /* we will call htonl on each of the int that compose the message to   */
+ /* be sent. the other half of the connection will call the ntohl       */
+ /* routine to undo any changes that may have been made...              */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+send_response()
+{
+  int   counter=0;
+  int	bytes_sent;
+
+  /* display the contents of the request if the debug level is high */
+  /* enough. otherwise, just send the darned thing ;-) */
+
+  if (debug > 1) {
+    fprintf(where,
+            "send_response: contents of %u ints before htonl\n",
+            sizeof(netperf_response)/4);
+    dump_response();
+  }
+
+  /* put the entire response_array into network order. We do this */
+  /* arbitrarily rather than trying to figure-out just how much of the */
+  /* request array contains real information. this should be simpler, */
+  /* and at any rate, the performance of sending control messages for */
+  /* this benchmark is not of any real concern. */
+  
+  for (counter=0;counter < sizeof(netperf_response)/4; counter++) {
+    response_array[counter] = htonl(response_array[counter]);
+  }
+  
+  if (debug > 1) {
+    fprintf(where,
+            "send_response: contents after htonl\n");
+    dump_response();
+    fprintf(where,
+            "about to send %u bytes from %p\n",
+            sizeof(netperf_response),
+            &netperf_response);
+    fflush(where);
+  }
+
+  /*KC*/
+  if ((bytes_sent = send(server_sock,
+           (char *)&netperf_response,
+           sizeof(netperf_response),
+           0)) != sizeof(netperf_response)) {
+    perror("send_response: send call failure");
+	fprintf(where, "BytesSent: %d\n", bytes_sent);
+    exit(1);
+  }
+  
+}
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     recv_request()                                                  */
+ /*                                                                     */
+ /* receive the remote's request on the control socket. we will put     */
+ /* the entire response into host order before giving it to the         */
+ /* calling routine. hopefully, this will go most of the way to         */
+ /* insuring intervendor interoperability. if there are any problems,   */
+ /* we will just punt the entire situation.                             */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+recv_request()
+{
+int     tot_bytes_recvd,
+        bytes_recvd, 
+        bytes_left;
+char    *buf = (char *)&netperf_request;
+int     buflen = sizeof(netperf_request);
+int     counter;
+
+tot_bytes_recvd = 0;    
+ bytes_recvd = 0;     /* nt_lint; bytes_recvd uninitialized if buflen == 0 */
+bytes_left      = buflen;
+while ((tot_bytes_recvd != buflen) &&
+       ((bytes_recvd = recv(server_sock, buf, bytes_left,0)) > 0 )) {
+  tot_bytes_recvd += bytes_recvd;
+  buf             += bytes_recvd;
+  bytes_left      -= bytes_recvd;
+}
+
+/* put the request into host order */
+
+for (counter = 0; counter < sizeof(netperf_request)/sizeof(int); counter++) {
+  request_array[counter] = ntohl(request_array[counter]);
+}
+
+if (debug) {
+  fprintf(where,
+          "recv_request: received %d bytes of request.\n",
+          tot_bytes_recvd);
+  fflush(where);
+}
+
+if (bytes_recvd == SOCKET_ERROR) {
+  Print_errno(where,
+          "recv_request: error on recv");
+  fflush(where);
+  exit(1);
+}
+
+if (bytes_recvd == 0) {
+  /* the remote has shutdown the control connection, we should shut it */
+  /* down as well and exit */
+
+  if (debug) {
+    fprintf(where,
+            "recv_request: remote requested shutdown of control\n");
+    fflush(where);
+  }
+
+  if (netlib_control != INVALID_SOCKET) {
+        shutdown_control();
+  }
+  exit(0);
+}
+
+if (tot_bytes_recvd < buflen) {
+  if (debug > 1)
+    dump_request();
+
+  fprintf(where,
+          "recv_request: partial request received of %d bytes\n",
+          tot_bytes_recvd);
+  fflush(where);
+  exit(1);
+}
+
+ if (debug > 1) {
+   dump_request();
+ } 
+
+  /* get the processor affinity request value from netperf */
+  /* this is a kludge and I know it.  sgb 8/11/04          */
+
+  local_proc_affinity = netperf_request.content.dummy;
+
+  if (local_proc_affinity != -1) {
+    bind_to_specific_processor(local_proc_affinity,0);
+  } 
+
+}
+
+ /*
+
+      recv_response_timed()                                           
+                                                                    
+ receive the remote's response on the control socket. we will put the
+ entire response into host order before giving it to the calling
+ routine. hopefully, this will go most of the way to insuring
+ intervendor interoperability. if there are any problems, we will just
+ punt the entire situation.
+                                                                    
+ The call to select at the beginning is to get us out of hang
+ situations where the remote gives-up but we don't find-out about
+ it. This seems to happen only rarely, but it would be nice to be
+ somewhat robust ;-)
+
+ The "_timed" part is to allow the caller to add (or I suppose
+ subtract) from the length of timeout on the select call. this was
+ added since not all the CPU utilization mechanisms require a 40
+ second calibration, and we used to have an aribtrary 40 second sleep
+ in "calibrate_remote_cpu" - since we don't _always_ need that, we
+ want to simply add 40 seconds to the select() timeout from that call,
+ but don't want to change all the "recv_response" calls in the code
+ right away.  sooo, we push the functionality of the old
+ recv_response() into a new recv_response_timed(addl_timout) call, and
+ have recv_response() call recv_response_timed(0).  raj 2005-05-16
+
+ */
+
+
+void
+recv_response_timed(int addl_time)
+{
+int     tot_bytes_recvd,
+        bytes_recvd = 0, 
+        bytes_left;
+char    *buf = (char *)&netperf_response;
+int     buflen = sizeof(netperf_response);
+int     counter;
+
+ /* stuff for select, use fd_set for better compliance */
+fd_set  readfds;
+struct  timeval timeout;
+
+tot_bytes_recvd = 0;    
+bytes_left      = buflen;
+
+/* zero out the response structure */
+
+/* BUG FIX SJB 2/4/93 - should be < not <= */
+for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) {
+        response_array[counter] = 0;
+}
+
+ /* we only select once. it is assumed that if the response is split */
+ /* (which should not be happening, that we will receive the whole */
+ /* thing and not have a problem ;-) */
+
+FD_ZERO(&readfds);
+FD_SET(netlib_control,&readfds);
+timeout.tv_sec  = 120 + addl_time;  /* wait at least two minutes
+                                      before punting - the USE_LOOPER
+                                      CPU stuff may cause remote's to
+                                      have a bit longer time of it
+                                      than 60 seconds would allow.
+                                      triggered by fix from Jeff
+                                      Dwork. */
+timeout.tv_usec = 0;
+
+ /* select had better return one, or there was either a problem or a */
+ /* timeout... */
+
+if ((counter = select(FD_SETSIZE,
+                      &readfds,
+                      0,
+                      0,
+                      &timeout)) != 1) {
+  fprintf(where,
+          "netperf: receive_response: no response received. errno %d counter %d\n",
+          errno,
+          counter);
+  exit(1);
+}
+
+while ((tot_bytes_recvd != buflen) &&
+       ((bytes_recvd = recv(netlib_control, buf, bytes_left,0)) > 0 )) {
+  tot_bytes_recvd += bytes_recvd;
+  buf             += bytes_recvd;
+  bytes_left      -= bytes_recvd;
+}
+
+if (debug) {
+  fprintf(where,"recv_response: received a %d byte response\n",
+          tot_bytes_recvd);
+  fflush(where);
+}
+
+/* put the response into host order */
+
+for (counter = 0; counter < sizeof(netperf_response)/sizeof(int); counter++) {
+  response_array[counter] = ntohl(response_array[counter]);
+}
+
+if (bytes_recvd == SOCKET_ERROR) {
+        perror("recv_response");
+        exit(1);
+}
+if (tot_bytes_recvd < buflen) {
+  fprintf(stderr,
+          "recv_response: partial response received: %d bytes\n",
+          tot_bytes_recvd);
+  fflush(stderr);
+  if (debug > 1)
+    dump_response();
+  exit(1);
+}
+if (debug > 1) {
+  dump_response();
+}
+}
+
+void
+recv_response() 
+{
+  recv_response_timed(0);
+}
+
+
+
+#if defined(USE_PSTAT) || defined (USE_SYSCTL)
+int
+hi_32(big_int)
+     long long *big_int;
+{
+  union overlay_u {
+    long long  dword;
+    long       words[2];
+  } *overlay;
+
+  overlay = (union overlay_u *)big_int;
+  /* on those systems which are byte swapped, we really wish to */
+  /* return words[1] - at least I think so - raj 4/95 */
+  if (htonl(1L) == 1L) {
+    /* we are a "normal" :) machine */
+    return(overlay->words[0]);
+  }
+  else {
+    return(overlay->words[1]);
+  }
+}
+
+int
+lo_32(big_int)
+     long long *big_int;
+{
+  union overlay_u {
+    long long  dword;
+    long       words[2];
+  } *overlay;
+
+  overlay = (union overlay_u *)big_int;
+  /* on those systems which are byte swapped, we really wish to */
+  /* return words[0] - at least I think so - raj 4/95 */
+  if (htonl(1L) == 1L) {
+    /* we are a "normal" :) machine */
+    return(overlay->words[1]);
+  }
+  else {
+    return(overlay->words[0]);
+  }
+}
+
+#endif /* USE_PSTAT || USE_SYSCTL */
+
+
+void libmain()
+{
+fprintf(where,"hello world\n");
+fprintf(where,"debug: %d\n",debug);
+}
+
+
+void
+set_sock_buffer (SOCKET sd, enum sock_buffer which, int requested_size, int *effective_sizep)
+{
+#ifdef SO_SNDBUF
+  int optname = (which == SEND_BUFFER) ? SO_SNDBUF : SO_RCVBUF;
+  netperf_socklen_t sock_opt_len;
+
+  /* seems that under Windows, setting a value of zero is how one
+     tells the stack you wish to enable copy-avoidance. Knuth only
+     knows what it will do on other stacks, but it might be
+     interesting to find-out, so we won't bother #ifdef'ing the change
+     to allow asking for 0 bytes. Courtesy of SAF, 2007-05  raj
+     2007-05-31 */
+  if (requested_size >= 0) {
+    if (setsockopt(sd, SOL_SOCKET, optname,
+		   (char *)&requested_size, sizeof(int)) < 0) {
+      fprintf(where, "netperf: set_sock_buffer: %s option: errno %d\n",
+	      (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+    if (debug > 1) {
+      fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n",
+	      (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF",
+	      requested_size);
+      fflush(where);
+    }
+  }
+
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+
+  sock_opt_len = sizeof(netperf_socklen_t);
+  if (getsockopt(sd, SOL_SOCKET, optname, (char *)effective_sizep,
+		 &sock_opt_len) < 0) {
+    fprintf(where, "netperf: set_sock_buffer: getsockopt %s: errno %d\n",
+	    (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF", errno);
+    fflush(where);
+    *effective_sizep = -1;
+  }
+
+  if (debug) {
+    fprintf(where, "netperf: set_sock_buffer: "
+	    "%s socket size determined to be %d\n",
+	    (which == SEND_BUFFER) ? "send" : "receive", *effective_sizep);
+    fflush(where);
+  }
+#else /* SO_SNDBUF */
+  *effective_size = -1;
+#endif /* SO_SNDBUF */
+}
+
+void
+dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+              char *host, char *port, int family)
+{
+  struct sockaddr *ai_addr;
+  struct addrinfo *temp;
+  temp=info;
+
+  fprintf(dumploc, "getaddrinfo returned the following for host '%s' ", host);
+  fprintf(dumploc, "port '%s' ", port);
+  fprintf(dumploc, "family %s\n", inet_ftos(family));
+  while (temp) {
+    /* seems that Solaris 10 GA bits will not give a canonical name
+       for ::0 or 0.0.0.0, and their fprintf() cannot deal with a null
+       pointer, so we have to check for a null pointer.  probably a
+       safe thing to do anyway, eventhough it was not necessary on
+       linux or hp-ux. raj 2005-02-09 */
+    if (temp->ai_canonname) {
+      fprintf(dumploc,
+	      "\tcannonical name: '%s'\n",temp->ai_canonname);
+    }
+    else {
+      fprintf(dumploc,
+	      "\tcannonical name: '%s'\n","(nil)");
+    }
+    fprintf(dumploc,
+            "\tflags: %x family: %s: socktype: %s protocol %s addrlen %d\n",
+            temp->ai_flags,
+            inet_ftos(temp->ai_family),
+            inet_ttos(temp->ai_socktype),
+            inet_ptos(temp->ai_protocol),
+            temp->ai_addrlen);
+    ai_addr = temp->ai_addr;
+    if (ai_addr != NULL) {
+      fprintf(dumploc,
+              "\tsa_family: %s sadata: %d %d %d %d %d %d\n",
+              inet_ftos(ai_addr->sa_family),
+              (u_char)ai_addr->sa_data[0],
+              (u_char)ai_addr->sa_data[1],
+              (u_char)ai_addr->sa_data[2],
+              (u_char)ai_addr->sa_data[3],
+              (u_char)ai_addr->sa_data[4],
+              (u_char)ai_addr->sa_data[5]);
+    }
+    temp = temp->ai_next;
+  }
+  fflush(dumploc);
+}
+
+/*
+  establish_control()
+
+set-up the control connection between netperf and the netserver so we
+can actually run some tests. if we cannot establish the control
+connection, that may or may not be a good thing, so we will let the
+caller decide what to do.
+
+to assist with pesky end-to-end-unfriendly things like firewalls, we
+allow the caller to specify both the remote hostname and port, and the
+local addressing info.  i believe that in theory it is possible to
+have an IPv4 endpoint and an IPv6 endpoint communicate with one
+another, but for the time being, we are only going to take-in one
+requested address family parameter. this means that the only way
+(iirc) that we might get a mixed-mode connection would be if the
+address family is specified as AF_UNSPEC, and getaddrinfo() returns
+different families for the local and server names.
+
+the "names" can also be IP addresses in ASCII string form.
+
+raj 2003-02-27 */
+
+SOCKET
+establish_control_internal(char *hostname,
+			   char *port,
+			   int   remfam,
+			   char *localhost,
+			   char *localport,
+			   int   locfam)
+{
+  int not_connected;
+  SOCKET control_sock;
+  int count;
+  int error;
+
+  struct addrinfo   hints;
+  struct addrinfo  *local_res;
+  struct addrinfo  *remote_res;
+  struct addrinfo  *local_res_temp;
+  struct addrinfo  *remote_res_temp;
+
+  if (debug) {
+    fprintf(where,
+            "establish_control called with host '%s' port '%s' remfam %s\n",
+            hostname,
+            port,
+            inet_ftos(remfam));
+    fprintf(where,
+            "\t\tlocal '%s' port '%s' locfam %s\n",
+            localhost,
+            localport,
+            inet_ftos(locfam));
+    fflush(where);
+  }
+
+  /* first, we do the remote */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = remfam;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = IPPROTO_TCP;
+  hints.ai_flags = 0|AI_CANONNAME;
+  count = 0;
+  do {
+    error = getaddrinfo((char *)hostname,
+                        (char *)port,
+                        &hints,
+                        &remote_res);
+    count += 1;
+    if (error == EAI_AGAIN) {
+      if (debug) {
+        fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n");
+        fflush(where);
+      }
+      sleep(1);
+    }
+  } while ((error == EAI_AGAIN) && (count <= 5));
+
+  if (error) {
+    printf("establish control: could not resolve remote '%s' port '%s' af %s",
+           hostname,
+           port,
+           inet_ftos(remfam));
+    printf("\n\tgetaddrinfo returned %d %s\n",
+           error,
+           gai_strerror(error));
+    return(INVALID_SOCKET);
+  }
+
+  if (debug) {
+    dump_addrinfo(where, remote_res, hostname, port, remfam);
+  }
+
+  /* now we do the local */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = locfam;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = IPPROTO_TCP;
+  hints.ai_flags = AI_PASSIVE|AI_CANONNAME;
+  count = 0;
+  do {
+    count += 1;
+    error = getaddrinfo((char *)localhost,
+                           (char *)localport,
+                           &hints,
+                           &local_res);
+    if (error == EAI_AGAIN) {
+      if (debug) {
+        fprintf(where,
+                "Sleeping on getaddrinfo(%s,%s) EAI_AGAIN count %d \n",
+                localhost,
+                localport,
+                count);
+        fflush(where);
+      }
+      sleep(1);
+    }
+  } while ((error == EAI_AGAIN) && (count <= 5));
+
+  if (error) {
+    printf("establish control: could not resolve local '%s' port '%s' af %s",
+           localhost,
+           localport,
+           inet_ftos(locfam));
+    printf("\n\tgetaddrinfo returned %d %s\n",
+           error,
+           gai_strerror(error));
+    return(INVALID_SOCKET);
+  }
+
+  if (debug) {
+    dump_addrinfo(where, local_res, localhost, localport, locfam);
+  }
+
+  not_connected = 1;
+  local_res_temp = local_res;
+  remote_res_temp = remote_res;
+  /* we want to loop through all the possibilities. looping on the
+     local addresses will be handled within the while loop.  I suppose
+     these is some more "C-expert" way to code this, but it has not
+     lept to mind just yet :)  raj 2003-02024 */
+
+  while (remote_res_temp != NULL) {
+
+    /* I am guessing that we should use the address family of the
+       local endpoint, and we will not worry about mixed family types
+       - presumeably the stack or other transition mechanisms will be
+       able to deal with that for us. famous last words :)  raj 2003-02-26 */
+    control_sock = socket(local_res_temp->ai_family,
+                          SOCK_STREAM,
+                          0);
+    if (control_sock == INVALID_SOCKET) {
+      /* at some point we'll need a more generic "display error"
+         message for when/if we use GUIs and the like. unlike a bind
+         or connect failure, failure to allocate a socket is
+         "immediately fatal" and so we return to the caller. raj 2003-02-24 */
+      if (debug) {
+        perror("establish_control: unable to allocate control socket");
+      }
+      return(INVALID_SOCKET);
+    }
+
+    /* if we are going to control the local enpoint addressing, we
+       need to call bind. of course, we should probably be setting one
+       of the SO_REUSEmumble socket options? raj 2005-02-04 */
+    if (bind(control_sock,
+	     local_res_temp->ai_addr,
+	     local_res_temp->ai_addrlen) == 0) {
+      if (debug) {
+	fprintf(where,
+		"bound control socket to %s and %s\n",
+		localhost,
+		localport);
+      }
+
+      if (connect(control_sock,
+		  remote_res_temp->ai_addr,
+		  remote_res_temp->ai_addrlen) == 0) {
+	/* we have successfully connected to the remote netserver */
+	if (debug) {
+	  fprintf(where,
+		  "successful connection to remote netserver at %s and %s\n",
+		  hostname,
+		  port);
+	}
+	not_connected = 0;
+	/* this should get us out of the while loop */
+	break;
+      } else {
+	/* the connect call failed */
+	if (debug) {
+	  fprintf(where,
+		  "establish_control: connect failed, errno %d %s\n",
+		  errno,
+		  strerror(errno));
+	  fprintf(where, "    trying next address combination\n");
+	  fflush(where);
+	}
+      }
+    }
+    else {
+      /* the bind failed */
+      if (debug) {
+	fprintf(where,
+		"establish_control: bind failed, errno %d %s\n",
+		errno,
+		strerror(errno));
+	fprintf(where, "    trying next address combination\n");
+	fflush(where);
+      }
+    }
+
+    if ((local_res_temp = local_res_temp->ai_next) == NULL) {
+      /* wrap the local and move to the next server, don't forget to
+         close the current control socket. raj 2003-02-24 */
+      local_res_temp = local_res;
+      /* the outer while conditions will deal with the case when we
+         get to the end of all the possible remote addresses. */
+      remote_res_temp = remote_res_temp->ai_next;
+      /* it is simplest here to just close the control sock. since
+         this is not a performance critical section of code, we
+         don't worry about overheads for socket allocation or
+         close. raj 2003-02-24 */
+    }
+    close(control_sock);
+  }
+
+  /* we no longer need the addrinfo stuff */
+  freeaddrinfo(local_res);
+  freeaddrinfo(remote_res);
+
+  /* so, we are either connected or not */
+  if (not_connected) {
+    fprintf(where, "establish control: are you sure there is a netserver listening on %s at port %s?\n",hostname,port);
+    fflush(where);
+    return(INVALID_SOCKET);
+  }
+  /* at this point, we are connected.  we probably want some sort of
+     version check with the remote at some point. raj 2003-02-24 */
+  return(control_sock);
+}
+
+void
+establish_control(char *hostname,
+		  char *port,
+		  int   remfam,
+		  char *localhost,
+		  char *localport,
+		  int   locfam)
+
+{
+
+  netlib_control = establish_control_internal(hostname,
+					      port,
+					      remfam,
+					      localhost,
+					      localport,
+					      locfam);
+  if (netlib_control == INVALID_SOCKET) {
+    fprintf(where,
+	    "establish_control could not establish the control connection from %s port %s address family %s to %s port %s address family %s\n",
+	    localhost,localport,inet_ftos(locfam),
+	    hostname,port,inet_ftos(remfam));
+    fflush(where);
+    exit(INVALID_SOCKET);
+  }
+}
+
+
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     get_id()                                                        */
+ /*                                                                     */
+ /* Return a string to the calling routine that contains the            */
+ /* identifying information for the host we are running on. This        */
+ /* information will then either be displayed locally, or returned to   */
+ /* a remote caller for display there.                                  */
+ /*                                                                     */
+ /***********************************************************************/
+
+char *
+get_id()
+{
+	static char id_string[80];
+#ifdef WIN32
+char                    system_name[MAX_COMPUTERNAME_LENGTH+1] ;
+DWORD                   name_len = MAX_COMPUTERNAME_LENGTH + 1 ;
+#else
+struct  utsname         system_name;
+#endif /* WIN32 */
+
+#ifdef WIN32
+ SYSTEM_INFO SystemInfo;
+ GetSystemInfo( &SystemInfo ) ;
+ if ( !GetComputerName(system_name , &name_len) )
+   strcpy(system_name , "no_name") ;
+#else
+ if (uname(&system_name) <0) {
+   perror("identify_local: uname");
+   exit(1);
+ }
+#endif /* WIN32 */
+
+ snprintf(id_string, sizeof(id_string),
+#ifdef WIN32
+	  "%-15s%-15s%d.%d%d",
+	  "Windows NT",
+	  system_name ,
+	  GetVersion() & 0xFF ,
+	  GetVersion() & 0xFF00 ,
+	  SystemInfo.dwProcessorType
+	  
+#else
+	  "%-15s%-15s%-15s%-15s%-15s",
+	  system_name.sysname,
+	  system_name.nodename,
+	  system_name.release,
+	  system_name.version,
+	  system_name.machine
+#endif /* WIN32 */
+	  );
+ return (id_string);
+}
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     identify_local()                                                */
+ /*                                                                     */
+ /* Display identifying information about the local host to the user.   */
+ /* At first release, this information will be the same as that which   */
+ /* is returned by the uname -a command, with the exception of the      */
+ /* idnumber field, which seems to be a non-POSIX item, and hence       */
+ /* non-portable.                                                       */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+identify_local()
+{
+
+char *local_id;
+
+local_id = get_id();
+
+fprintf(where,"Local Information \n\
+Sysname       Nodename       Release        Version        Machine\n");
+
+fprintf(where,"%s\n",
+       local_id);
+
+}
+
+
+ /***********************************************************************/
+ /*                                                                     */
+ /*     identify_remote()                                               */
+ /*                                                                     */
+ /* Display identifying information about the remote host to the user.  */
+ /* At first release, this information will be the same as that which   */
+ /* is returned by the uname -a command, with the exception of the      */
+ /* idnumber field, which seems to be a non-POSIX item, and hence       */
+ /* non-portable. A request is sent to the remote side, which will      */
+ /* return a string containing the utsname information in a             */
+ /* pre-formatted form, which is then displayed after the header.       */
+ /*                                                                     */
+ /***********************************************************************/
+
+void
+identify_remote()
+{
+
+char    *remote_id="";
+
+/* send a request for node info to the remote */
+netperf_request.content.request_type = NODE_IDENTIFY;
+
+send_request();
+
+/* and now wait for the reply to come back */
+
+recv_response();
+
+if (netperf_response.content.serv_errno) {
+        Set_errno(netperf_response.content.serv_errno);
+        perror("identify_remote: on remote");
+        exit(1);
+}
+
+fprintf(where,"Remote Information \n\
+Sysname       Nodename       Release        Version        Machine\n");
+
+fprintf(where,"%s",
+       remote_id);
+}
+
+void
+cpu_start(int measure_cpu)
+{
+
+  gettimeofday(&time1,
+               &tz);
+  
+  if (measure_cpu) {
+    cpu_util_init();
+    measuring_cpu = 1;
+    cpu_method = get_cpu_method();
+    cpu_start_internal();
+  }
+}
+
+
+void
+cpu_stop(int measure_cpu, float *elapsed)
+
+{
+
+  int     sec,
+    usec;
+
+  if (measure_cpu) {
+    cpu_stop_internal();
+    cpu_util_terminate();
+  }
+  
+  gettimeofday(&time2,
+	       &tz);
+  
+  if (time2.tv_usec < time1.tv_usec) {
+    time2.tv_usec += 1000000;
+    time2.tv_sec  -= 1;
+  }
+  
+  sec     = time2.tv_sec - time1.tv_sec;
+  usec    = time2.tv_usec - time1.tv_usec;
+  lib_elapsed     = (float)sec + ((float)usec/(float)1000000.0);
+  
+  *elapsed = lib_elapsed;
+  
+}
+
+
+double
+calc_thruput_interval(double units_received,double elapsed)
+
+{
+  double        divisor;
+
+  /* We will calculate the thruput in libfmt units/second */
+  switch (libfmt) {
+  case 'K':
+    divisor = 1024.0;
+    break;
+  case 'M':
+    divisor = 1024.0 * 1024.0;
+    break;
+  case 'G':
+    divisor = 1024.0 * 1024.0 * 1024.0;
+    break;
+  case 'k':
+    divisor = 1000.0 / 8.0;
+    break;
+  case 'm':
+    divisor = 1000.0 * 1000.0 / 8.0;
+    break;
+  case 'g':
+    divisor = 1000.0 * 1000.0 * 1000.0 / 8.0;
+    break;
+    
+  default:
+    divisor = 1024.0;
+  }
+  
+  return (units_received / divisor / elapsed);
+
+}
+
+double
+calc_thruput(double units_received)
+
+{
+  return(calc_thruput_interval(units_received,lib_elapsed));
+}
+
+/* these "_omni" versions are ones which understand 'x' as a unit,
+   meaning transactions/s.  we have a separate routine rather than
+   convert the existing routine so we don't have to go and change
+   _all_ the nettest_foo.c files at one time.  raj 2007-06-08 */
+
+double
+calc_thruput_interval_omni(double units_received,double elapsed)
+
+{
+  double        divisor;
+
+  /* We will calculate the thruput in libfmt units/second */
+  switch (libfmt) {
+  case 'K':
+    divisor = 1024.0;
+    break;
+  case 'M':
+    divisor = 1024.0 * 1024.0;
+    break;
+  case 'G':
+    divisor = 1024.0 * 1024.0 * 1024.0;
+    break;
+  case 'k':
+    divisor = 1000.0 / 8.0;
+    break;
+  case 'm':
+    divisor = 1000.0 * 1000.0 / 8.0;
+    break;
+  case 'g':
+    divisor = 1000.0 * 1000.0 * 1000.0 / 8.0;
+    break;
+  case 'x':
+    divisor = 1.0;
+    break;
+
+  default:
+    fprintf(where,
+	    "WARNING calc_throughput_internal_omni: unknown units %c\n",
+	    libfmt);
+    fflush(where);
+    divisor = 1024.0;
+  }
+  
+  return (units_received / divisor / elapsed);
+
+}
+
+double
+calc_thruput_omni(double units_received)
+
+{
+  return(calc_thruput_interval_omni(units_received,lib_elapsed));
+}
+
+
+
+
+
+float 
+calc_cpu_util(float elapsed_time)
+{
+  return(calc_cpu_util_internal(elapsed_time));
+}
+
+float 
+calc_service_demand_internal(double unit_divisor,
+			     double units_sent,
+			     float elapsed_time,
+			     float cpu_utilization,
+			     int num_cpus)
+
+{
+
+  double service_demand;
+  double thruput;
+
+  if (debug) {
+    fprintf(where,"calc_service_demand called:  units_sent = %f\n",
+            units_sent);
+    fprintf(where,"                             elapsed_time = %f\n",
+            elapsed_time);
+    fprintf(where,"                             cpu_util = %f\n",
+            cpu_utilization);
+    fprintf(where,"                             num cpu = %d\n",
+            num_cpus);
+    fflush(where);
+  }
+
+  if (num_cpus == 0) num_cpus = lib_num_loc_cpus;
+  
+  if (elapsed_time == 0.0) {
+    elapsed_time = lib_elapsed;
+  }
+  if (cpu_utilization == 0.0) {
+    cpu_utilization = lib_local_cpu_util;
+  }
+  
+  thruput = (units_sent / 
+             (double) unit_divisor / 
+             (double) elapsed_time);
+
+  /* on MP systems, it is necessary to multiply the service demand by */
+  /* the number of CPU's. at least, I believe that to be the case:) */
+  /* raj 10/95 */
+
+  /* thruput has a "per second" component. if we were using 100% ( */
+  /* 100.0) of the CPU in a second, that would be 1 second, or 1 */
+  /* millisecond, so we multiply cpu_utilization by 10 to go to */
+  /* milliseconds, or 10,000 to go to micro seconds. With revision */
+  /* 2.1, the service demand measure goes to microseconds per unit. */
+  /* raj 12/95 */ 
+  service_demand = (cpu_utilization*10000.0/thruput) * 
+    (float) num_cpus;
+  
+  if (debug) {
+    fprintf(where,"calc_service_demand using:   units_sent = %f\n",
+            units_sent);
+    fprintf(where,"                             elapsed_time = %f\n",
+            elapsed_time);
+    fprintf(where,"                             cpu_util = %f\n",
+            cpu_utilization);
+    fprintf(where,"                             num cpu = %d\n",
+            num_cpus);
+    fprintf(where,"calc_service_demand got:     thruput = %f\n",
+            thruput);
+    fprintf(where,"                             servdem = %f\n",
+            service_demand);
+    fflush(where);
+  }
+  return (float)service_demand;
+}
+
+float calc_service_demand(double units_sent,
+                          float elapsed_time,
+                          float cpu_utilization,
+                          int num_cpus)
+
+{
+
+  double unit_divisor = (double)1024.0;
+
+  return(calc_service_demand_internal(unit_divisor,
+				      units_sent,
+				      elapsed_time,
+				      cpu_utilization,
+				      num_cpus));
+}
+
+float calc_service_demand_trans(double units_sent,
+				float elapsed_time,
+				float cpu_utilization,
+				int num_cpus)
+
+{
+
+  double unit_divisor = (double)1.0;
+
+  return(calc_service_demand_internal(unit_divisor,
+				      units_sent,
+				      elapsed_time,
+				      cpu_utilization,
+				      num_cpus));
+}
+
+
+
+float
+calibrate_local_cpu(float local_cpu_rate)
+{
+  
+  lib_num_loc_cpus = get_num_cpus();
+
+  lib_use_idle = 0;
+#ifdef USE_LOOPER
+  cpu_util_init();
+  lib_use_idle = 1;
+#endif /* USE_LOOPER */
+
+  if (local_cpu_rate > 0) {
+    /* The user think that he knows what the cpu rate is. We assume */
+    /* that all the processors of an MP system are essentially the */
+    /* same - for this reason we do not have a per processor maxrate. */
+    /* if the machine has processors which are different in */
+    /* performance, the CPU utilization will be skewed. raj 4/95 */
+    lib_local_maxrate = local_cpu_rate;
+  }
+  else {
+    /* if neither USE_LOOPER nor USE_PSTAT are defined, we return a */
+    /* 0.0 to indicate that times or getrusage should be used. raj */
+    /* 4/95 */
+    lib_local_maxrate = (float)0.0;
+#if defined(USE_PROC_STAT) || defined(USE_LOOPER) || defined(USE_PSTAT) || defined(USE_KSTAT) || defined(USE_PERFSTAT) || defined(USE_SYSCTL)
+    lib_local_maxrate = calibrate_idle_rate(4,10);
+#endif
+  }
+  return lib_local_maxrate;
+}
+
+
+float
+calibrate_remote_cpu()
+{
+  float remrate;
+
+  netperf_request.content.request_type = CPU_CALIBRATE;
+  send_request();
+  /* we know that calibration will last at least 40 seconds, so go to */
+  /* sleep for that long so the 60 second select in recv_response will */
+  /* not pop. raj 7/95 */
+
+  /* we know that CPU calibration may last as long as 40 seconds, so
+     make sure we "select" for at least that long while looking for
+     the response. raj 2005-05-16 */
+  recv_response_timed(40);
+
+  if (netperf_response.content.serv_errno) {
+    /* initially, silently ignore remote errors and pass */
+    /* back a zero to the caller this should allow us to */
+    /* mix rev 1.0 and rev 1.1 netperfs... */
+    return((float)0.0);
+  }
+  else {
+    /* the rate is the first word of the test_specific data */
+    bcopy((char *)netperf_response.content.test_specific_data,
+          (char *)&remrate,
+          sizeof(remrate));
+    bcopy((char *)netperf_response.content.test_specific_data + sizeof(remrate),
+	  (char *)&lib_num_rem_cpus,
+	  sizeof(lib_num_rem_cpus));
+/*    remrate = (float) netperf_response.content.test_specific_data[0]; */
+    return(remrate);
+  }     
+}
+
+#ifndef WIN32
+/* WIN32 requires that at least one of the file sets to select be non-null. */
+/* Since msec_sleep routine is only called by nettest_dlpi & nettest_unix,  */
+/* let's duck this issue. */
+
+int
+msec_sleep( int msecs )
+{
+  int           rval ;
+
+  struct timeval timeout;
+
+  timeout.tv_sec = msecs / 1000;
+  timeout.tv_usec = (msecs - (msecs/1000) *1000) * 1000;
+  if ((rval = select(0,
+             0,
+             0,
+             0,
+             &timeout))) {
+    if ( SOCKET_EINTR(rval) ) {
+      return(1);
+    }
+    perror("msec_sleep: select");
+    exit(1);
+  }
+  return(0);
+}
+#endif /* WIN32 */
+
+#ifdef WANT_HISTOGRAM
+/* hist.c
+
+   Given a time difference in microseconds, increment one of 61
+   different buckets: 
+
+   0 - 9 in increments of 1 usec
+   0 - 9 in increments of 10 usecs
+   0 - 9 in increments of 100 usecs
+   1 - 9 in increments of 1 msec
+   1 - 9 in increments of 10 msecs
+   1 - 9 in increments of 100 msecs
+   1 - 9 in increments of 1 sec
+   1 - 9 in increments of 10 sec
+   > 100 secs
+   
+   This will allow any time to be recorded to within an accuracy of
+   10%, and provides a compact  representation for capturing the
+   distribution of a large number of time differences (e.g.
+   request-response latencies).
+   
+   Colin Low  10/6/93
+   Rick Jones 2004-06-15 extend to unit and ten usecs
+*/
+
+/* #include "sys.h" */
+
+/*#define HIST_TEST*/
+
+HIST 
+HIST_new(void){
+   HIST h;
+   if((h = (HIST) malloc(sizeof(struct histogram_struct))) == NULL) {
+     perror("HIST_new - malloc failed");
+     exit(1);
+   }
+   HIST_clear(h);
+   return h;
+}
+
+void 
+HIST_clear(HIST h){
+   int i;
+   for(i = 0; i < 10; i++){
+      h->unit_usec[i] = 0;
+      h->ten_usec[i] = 0;
+      h->hundred_usec[i] = 0;
+      h->unit_msec[i] = 0;
+      h->ten_msec[i] = 0;
+      h->hundred_msec[i] = 0;
+      h->unit_sec[i] = 0;
+      h->ten_sec[i] = 0;
+   }
+   h->ridiculous = 0;
+   h->total = 0;
+}
+
+void 
+HIST_add(register HIST h, int time_delta){
+   register int val;
+   h->total++;
+   val = time_delta;
+   if(val <= 9) h->unit_usec[val]++;
+   else {
+     val = val/10;
+     if(val <= 9) h->ten_usec[val]++;
+     else {
+       val = val/10;
+       if(val <= 9) h->hundred_usec[val]++;
+       else {
+	 val = val/10;
+	 if(val <= 9) h->unit_msec[val]++;
+	 else {
+	   val = val/10;
+	   if(val <= 9) h->ten_msec[val]++;
+	   else {
+	     val = val/10;
+	     if(val <= 9) h->hundred_msec[val]++;
+	     else {
+               val = val/10;
+               if(val <= 9) h->unit_sec[val]++;
+               else {
+		 val = val/10;
+		 if(val <= 9) h->ten_sec[val]++;
+		 else h->ridiculous++;
+               }
+	     }
+	   }
+	 }
+       }
+     }
+   }
+}
+
+#define RB_printf printf
+
+void 
+output_row(FILE *fd, char *title, int *row){
+   register int i;
+   RB_printf("%s", title);
+   for(i = 0; i < 10; i++) RB_printf(": %4d", row[i]);
+   RB_printf("\n");
+}
+
+int
+sum_row(int *row) {
+  int sum = 0;
+  int i;
+  for (i = 0; i < 10; i++) sum += row[i];
+  return(sum);
+}
+
+void 
+HIST_report(HIST h){
+#ifndef OLD_HISTOGRAM
+   output_row(stdout, "UNIT_USEC     ", h->unit_usec);
+   output_row(stdout, "TEN_USEC      ", h->ten_usec);
+   output_row(stdout, "HUNDRED_USEC  ", h->hundred_usec);
+#else
+   h->hundred_usec[0] += sum_row(h->unit_usec);
+   h->hundred_usec[0] += sum_row(h->ten_usec);
+   output_row(stdout, "TENTH_MSEC    ", h->hundred_usec);
+#endif
+   output_row(stdout, "UNIT_MSEC     ", h->unit_msec);
+   output_row(stdout, "TEN_MSEC      ", h->ten_msec);
+   output_row(stdout, "HUNDRED_MSEC  ", h->hundred_msec);
+   output_row(stdout, "UNIT_SEC      ", h->unit_sec);
+   output_row(stdout, "TEN_SEC       ", h->ten_sec);
+   RB_printf(">100_SECS: %d\n", h->ridiculous);
+   RB_printf("HIST_TOTAL:      %d\n", h->total);
+}
+
+#endif
+
+/* with the advent of sit-and-spin intervals support, we might as well
+   make these things available all the time, not just for demo or
+   histogram modes. raj 2006-02-06 */
+#ifdef HAVE_GETHRTIME
+
+void
+HIST_timestamp(hrtime_t *timestamp)
+{
+  *timestamp = gethrtime();
+}
+
+int
+delta_micro(hrtime_t *begin, hrtime_t *end)
+{
+  long nsecs;
+  nsecs = (*end) - (*begin);
+  return(nsecs/1000);
+}
+
+#elif defined(HAVE_GET_HRT)
+#include "hrt.h"
+
+void
+HIST_timestamp(hrt_t *timestamp)
+{
+  *timestamp = get_hrt();
+}
+
+int
+delta_micro(hrt_t *begin, hrt_t *end)
+{
+
+  return((int)get_hrt_delta(*end,*begin));
+
+}
+#elif defined(WIN32)
+void HIST_timestamp(LARGE_INTEGER *timestamp)
+{
+	QueryPerformanceCounter(timestamp);
+}
+
+int delta_micro(LARGE_INTEGER *begin, LARGE_INTEGER *end)
+{
+	LARGE_INTEGER DeltaTimestamp;
+	static LARGE_INTEGER TickHz = {0,0};
+
+	if (TickHz.QuadPart == 0) 
+	{
+		QueryPerformanceFrequency(&TickHz);
+	}
+
+	/*+*+ Rick; this will overflow after ~2000 seconds, is that
+	  good enough? Spencer: Yes, that should be more than good
+	  enough for histogram support */
+
+	DeltaTimestamp.QuadPart = (end->QuadPart - begin->QuadPart) * 
+	  1000000/TickHz.QuadPart;
+	assert((DeltaTimestamp.HighPart == 0) && 
+	       ((int)DeltaTimestamp.LowPart >= 0));
+
+	return (int)DeltaTimestamp.LowPart;
+}
+
+#else
+
+void
+HIST_timestamp(struct timeval *timestamp)
+{
+  gettimeofday(timestamp,NULL);
+}
+
+ /* return the difference (in micro seconds) between two timeval */
+ /* timestamps */
+int
+delta_micro(struct timeval *begin,struct timeval *end)
+
+{
+
+  int usecs, secs;
+
+  if (end->tv_usec < begin->tv_usec) {
+    /* borrow a second from the tv_sec */
+    end->tv_usec += 1000000;
+    end->tv_sec--;
+  }
+  usecs = end->tv_usec - begin->tv_usec;
+  secs  = end->tv_sec - begin->tv_sec;
+
+  usecs += (secs * 1000000);
+
+  return(usecs);
+
+}
+#endif /* HAVE_GETHRTIME */
+
+
+#ifdef WANT_DLPI
+
+int
+put_control(fd, len, pri, ack)
+     int fd, len, pri, ack;
+{
+  int error;
+  int flags = 0;
+  dl_error_ack_t *err_ack = (dl_error_ack_t *)control_data;
+
+  control_message.len = len;
+
+  if ((error = putmsg(fd, &control_message, 0, pri)) < 0 ) {
+    fprintf(where,"put_control: putmsg error %d\n",error);
+    fflush(where);
+    return(-1);
+  }
+  if ((error = getmsg(fd, &control_message, 0, &flags)) < 0) {
+    fprintf(where,"put_control: getsmg error %d\n",error);
+    fflush(where);
+    return(-1);
+  }
+  if (err_ack->dl_primitive != ack) {
+    fprintf(where,"put_control: acknowledgement error wanted %u got %u \n",
+            ack,err_ack->dl_primitive);
+    if (err_ack->dl_primitive == DL_ERROR_ACK) {
+      fprintf(where,"             dl_error_primitive: %u\n",
+              err_ack->dl_error_primitive);
+      fprintf(where,"             dl_errno:           %u\n",
+              err_ack->dl_errno);
+      fprintf(where,"             dl_unix_errno       %u\n",
+              err_ack->dl_unix_errno);
+    }
+    fflush(where);
+    return(-1);
+  }
+
+  return(0);
+}
+    
+int
+dl_open(char devfile[], int ppa)
+{
+  int fd;
+  dl_attach_req_t *attach_req = (dl_attach_req_t *)control_data;
+
+  if ((fd = open(devfile, O_RDWR)) == -1) {
+    fprintf(where,"netperf: dl_open: open of %s failed, errno = %d\n",
+            devfile,
+            errno);
+    return(-1);
+  }
+
+  attach_req->dl_primitive = DL_ATTACH_REQ;
+  attach_req->dl_ppa = ppa;
+
+  if (put_control(fd, sizeof(dl_attach_req_t), 0, DL_OK_ACK) < 0) {
+    fprintf(where,
+            "netperf: dl_open: could not send control message, errno = %d\n",
+            errno);
+    return(-1);
+  }
+  return(fd);
+}
+
+int
+dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len)
+{
+  dl_bind_req_t *bind_req = (dl_bind_req_t *)control_data;
+  dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)control_data;
+
+  bind_req->dl_primitive = DL_BIND_REQ;
+  bind_req->dl_sap = sap;
+  bind_req->dl_max_conind = 1;
+  bind_req->dl_service_mode = mode;
+  bind_req->dl_conn_mgmt = 0;
+  bind_req->dl_xidtest_flg = 0;
+
+  if (put_control(fd, sizeof(dl_bind_req_t), 0, DL_BIND_ACK) < 0) {
+    fprintf(where,
+            "netperf: dl_bind: could not send control message, errno = %d\n",
+            errno);
+    return(-1);
+  }
+
+  /* at this point, the control_data portion of the control message */
+  /* structure should contain a DL_BIND_ACK, which will have a full */
+  /* DLSAP in it. we want to extract this and pass it up so that    */
+  /* it can be passed around. */
+  if (*dlsap_len >= bind_ack->dl_addr_length) {
+    bcopy((char *)bind_ack+bind_ack->dl_addr_offset,
+          dlsap_ptr,
+          bind_ack->dl_addr_length);
+    *dlsap_len = bind_ack->dl_addr_length;
+    return(0);
+  }
+  else { 
+    return (-1); 
+  }
+}
+
+int
+dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len)
+{
+  dl_connect_req_t *connection_req = (dl_connect_req_t *)control_data;
+  dl_connect_con_t *connection_con = (dl_connect_con_t *)control_data;
+  struct pollfd pinfo;
+
+  int flags = 0;
+
+  /* this is here on the off chance that we really want some data */
+  u_long data_area[512];
+  struct strbuf data_message;
+
+  int error;
+
+  data_message.maxlen = 2048;
+  data_message.len = 0;
+  data_message.buf = (char *)data_area;
+
+  connection_req->dl_primitive = DL_CONNECT_REQ;
+  connection_req->dl_dest_addr_length = remote_addr_len;
+  connection_req->dl_dest_addr_offset = sizeof(dl_connect_req_t);
+  connection_req->dl_qos_length = 0;
+  connection_req->dl_qos_offset = 0;
+  bcopy (remote_addr, 
+         (unsigned char *)control_data + sizeof(dl_connect_req_t),
+         remote_addr_len);
+
+  /* well, I would call the put_control routine here, but the sequence */
+  /* of connection stuff with DLPI is a bit screwey with all this */
+  /* message passing - Toto, I don't think were in Berkeley anymore. */
+
+  control_message.len = sizeof(dl_connect_req_t) + remote_addr_len;
+  if ((error = putmsg(fd,&control_message,0,0)) !=0) {
+    fprintf(where,"dl_connect: putmsg failure, errno = %d, error 0x%x \n",
+            errno,error);
+    fflush(where);
+    return(-1);
+  };
+
+  pinfo.fd = fd;
+  pinfo.events = POLLIN | POLLPRI;
+  pinfo.revents = 0;
+
+  if ((error = getmsg(fd,&control_message,&data_message,&flags)) != 0) {
+    fprintf(where,"dl_connect: getmsg failure, errno = %d, error 0x%x \n",
+            errno,error);
+    fflush(where);
+    return(-1);
+  }
+  while (control_data[0] == DL_TEST_CON) {
+    /* i suppose we spin until we get an error, or a connection */
+    /* indication */
+    if((error = getmsg(fd,&control_message,&data_message,&flags)) !=0) {
+       fprintf(where,"dl_connect: getmsg failure, errno = %d, error = 0x%x\n",
+               errno,error);
+       fflush(where);
+       return(-1);
+    }
+  }
+
+  /* we are out - it either worked or it didn't - which was it? */
+  if (control_data[0] == DL_CONNECT_CON) {
+    return(0);
+  }
+  else {
+    return(-1);
+  }
+}
+
+int
+dl_accept(fd, remote_addr, remote_addr_len)
+     int fd;
+     unsigned char *remote_addr;
+     int remote_addr_len;
+{
+  dl_connect_ind_t *connect_ind = (dl_connect_ind_t *)control_data;
+  dl_connect_res_t *connect_res = (dl_connect_res_t *)control_data;
+  int tmp_cor;
+  int flags = 0;
+
+  /* hang around and wait for a connection request */
+  getmsg(fd,&control_message,0,&flags);
+  while (control_data[0] != DL_CONNECT_IND) {
+    getmsg(fd,&control_message,0,&flags);
+  }
+
+  /* now respond to the request. at some point, we may want to be sure */
+  /* that the connection came from the correct station address, but */
+  /* will assume that we do not have to worry about it just now. */
+
+  tmp_cor = connect_ind->dl_correlation;
+
+  connect_res->dl_primitive = DL_CONNECT_RES;
+  connect_res->dl_correlation = tmp_cor;
+  connect_res->dl_resp_token = 0;
+  connect_res->dl_qos_length = 0;
+  connect_res->dl_qos_offset = 0;
+  connect_res->dl_growth = 0;
+
+  return(put_control(fd, sizeof(dl_connect_res_t), 0, DL_OK_ACK));
+
+}
+
+int
+dl_set_window(fd, window)
+     int fd, window;
+{
+  return(0);
+}
+
+void
+dl_stats(fd)
+     int fd;
+{
+}
+
+int
+dl_send_disc(fd)
+     int fd;
+{
+}
+
+int
+dl_recv_disc(fd)
+     int fd;
+{
+}
+#endif /* WANT_DLPI*/
+
+ /* these routines for confidence intervals are courtesy of IBM. They */
+ /* have been modified slightly for more general usage beyond TCP/UDP */
+ /* tests. raj 11/94 I would suspect that this code carries an IBM */
+ /* copyright that is much the same as that for the original HP */
+ /* netperf code */
+int     confidence_iterations; /* for iterations */
+
+double  
+  result_confid=-10.0,
+  loc_cpu_confid=-10.0,
+  rem_cpu_confid=-10.0,
+
+  measured_sum_result=0.0, 
+  measured_square_sum_result=0.0,
+  measured_mean_result=0.0, 
+  measured_var_result=0.0, 
+
+  measured_sum_local_cpu=0.0,
+  measured_square_sum_local_cpu=0.0,
+  measured_mean_local_cpu=0.0,
+  measured_var_local_cpu=0.0, 
+
+  measured_sum_remote_cpu=0.0,
+  measured_square_sum_remote_cpu=0.0,
+  measured_mean_remote_cpu=0.0,
+  measured_var_remote_cpu=0.0, 
+  
+  measured_sum_local_service_demand=0.0,
+  measured_square_sum_local_service_demand=0.0,
+  measured_mean_local_service_demand=0.0,
+  measured_var_local_service_demand=0.0,
+
+  measured_sum_remote_service_demand=0.0,
+  measured_square_sum_remote_service_demand=0.0,
+  measured_mean_remote_service_demand=0.0,
+  measured_var_remote_service_demand=0.0,
+
+  measured_sum_local_time=0.0,
+  measured_square_sum_local_time=0.0,
+  measured_mean_local_time=0.0,
+  measured_var_local_time=0.0,
+
+  measured_mean_remote_time=0.0, 
+  
+  measured_fails,
+  measured_local_results,
+  confidence=-10.0;
+/*  interval=0.1; */
+
+/************************************************************************/
+/*                                                                      */
+/*      Constants for Confidence Intervals                              */
+/*                                                                      */
+/************************************************************************/
+void 
+init_stat()
+{
+        measured_sum_result=0.0;
+        measured_square_sum_result=0.0;
+        measured_mean_result=0.0;
+        measured_var_result=0.0;
+
+        measured_sum_local_cpu=0.0;
+        measured_square_sum_local_cpu=0.0;
+        measured_mean_local_cpu=0.0;
+        measured_var_local_cpu=0.0;
+
+        measured_sum_remote_cpu=0.0;
+        measured_square_sum_remote_cpu=0.0;
+        measured_mean_remote_cpu=0.0;
+        measured_var_remote_cpu=0.0;
+
+        measured_sum_local_service_demand=0.0;
+        measured_square_sum_local_service_demand=0.0;
+        measured_mean_local_service_demand=0.0;
+        measured_var_local_service_demand=0.0;
+
+        measured_sum_remote_service_demand=0.0;
+        measured_square_sum_remote_service_demand=0.0;
+        measured_mean_remote_service_demand=0.0;
+        measured_var_remote_service_demand=0.0;
+
+        measured_sum_local_time=0.0;
+        measured_square_sum_local_time=0.0;
+        measured_mean_local_time=0.0;
+        measured_var_local_time=0.0;
+
+        measured_mean_remote_time=0.0;
+
+        measured_fails = 0.0;
+        measured_local_results=0.0,
+        confidence=-10.0;
+}
+
+ /* this routine does a simple table lookup for some statistical */
+ /* function that I would remember if I stayed awake in my probstats */
+ /* class... raj 11/94 */
+double 
+confid(int level, int freedom)
+{
+double  t99[35],t95[35];
+
+   t95[1]=12.706;
+   t95[2]= 4.303;
+   t95[3]= 3.182;
+   t95[4]= 2.776;
+   t95[5]= 2.571;
+   t95[6]= 2.447;
+   t95[7]= 2.365;
+   t95[8]= 2.306;
+   t95[9]= 2.262;
+   t95[10]= 2.228;
+   t95[11]= 2.201;
+   t95[12]= 2.179;
+   t95[13]= 2.160;
+   t95[14]= 2.145;
+   t95[15]= 2.131;
+   t95[16]= 2.120;
+   t95[17]= 2.110;
+   t95[18]= 2.101;
+   t95[19]= 2.093;
+   t95[20]= 2.086;
+   t95[21]= 2.080;
+   t95[22]= 2.074;
+   t95[23]= 2.069;
+   t95[24]= 2.064;
+   t95[25]= 2.060;
+   t95[26]= 2.056;
+   t95[27]= 2.052;
+   t95[28]= 2.048;
+   t95[29]= 2.045;
+   t95[30]= 2.042;
+   
+   t99[1]=63.657;
+   t99[2]= 9.925;
+   t99[3]= 5.841;
+   t99[4]= 4.604;
+   t99[5]= 4.032;
+   t99[6]= 3.707;
+   t99[7]= 3.499;
+   t99[8]= 3.355;
+   t99[9]= 3.250;
+   t99[10]= 3.169;
+   t99[11]= 3.106;
+   t99[12]= 3.055;
+   t99[13]= 3.012;
+   t99[14]= 2.977;
+   t99[15]= 2.947;
+   t99[16]= 2.921;
+   t99[17]= 2.898;
+   t99[18]= 2.878;
+   t99[19]= 2.861;
+   t99[20]= 2.845;
+   t99[21]= 2.831;
+   t99[22]= 2.819;
+   t99[23]= 2.807;
+   t99[24]= 2.797;
+   t99[25]= 2.787;
+   t99[26]= 2.779;
+   t99[27]= 2.771;
+   t99[28]= 2.763;
+   t99[29]= 2.756;
+   t99[30]= 2.750;
+   
+   if(level==95){
+        return(t95[freedom]);
+   } else if(level==99){
+        return(t99[freedom]);
+   } else{
+        return(0);
+   }
+}
+
+void
+calculate_confidence(int confidence_iterations,
+                     float time,
+                     double result,
+                     float loc_cpu,
+                     float rem_cpu,
+                     float loc_sd,
+                     float rem_sd)
+{
+
+  if (debug) {
+    fprintf(where,
+            "calculate_confidence: itr  %d; time %f; res  %f\n",
+            confidence_iterations,
+            time,
+            result);
+    fprintf(where,
+            "                               lcpu %f; rcpu %f\n",
+            loc_cpu,
+            rem_cpu);
+    fprintf(where,
+            "                               lsdm %f; rsdm %f\n",
+            loc_sd,
+            rem_sd);
+    fflush(where);
+  }
+
+  /* the test time */
+  measured_sum_local_time               += 
+    (double) time;
+  measured_square_sum_local_time        += 
+    (double) time*time;
+  measured_mean_local_time              =  
+    (double) measured_sum_local_time/confidence_iterations;
+  measured_var_local_time               =  
+    (double) measured_square_sum_local_time/confidence_iterations
+      -measured_mean_local_time*measured_mean_local_time;
+  
+  /* the test result */
+  measured_sum_result           += 
+    (double) result;
+  measured_square_sum_result    += 
+    (double) result*result;
+  measured_mean_result          =  
+    (double) measured_sum_result/confidence_iterations;
+  measured_var_result           =  
+    (double) measured_square_sum_result/confidence_iterations
+      -measured_mean_result*measured_mean_result;
+
+  /* local cpu utilization */
+  measured_sum_local_cpu        += 
+    (double) loc_cpu;
+  measured_square_sum_local_cpu += 
+    (double) loc_cpu*loc_cpu;
+  measured_mean_local_cpu       = 
+    (double) measured_sum_local_cpu/confidence_iterations;
+  measured_var_local_cpu        = 
+    (double) measured_square_sum_local_cpu/confidence_iterations
+      -measured_mean_local_cpu*measured_mean_local_cpu;
+
+  /* remote cpu util */
+  measured_sum_remote_cpu       +=
+    (double) rem_cpu;
+  measured_square_sum_remote_cpu+=
+    (double) rem_cpu*rem_cpu;
+  measured_mean_remote_cpu      = 
+    (double) measured_sum_remote_cpu/confidence_iterations;
+  measured_var_remote_cpu       = 
+    (double) measured_square_sum_remote_cpu/confidence_iterations
+      -measured_mean_remote_cpu*measured_mean_remote_cpu;
+
+  /* local service demand */
+  measured_sum_local_service_demand     +=
+    (double) loc_sd;
+  measured_square_sum_local_service_demand+=
+    (double) loc_sd*loc_sd;
+  measured_mean_local_service_demand    = 
+    (double) measured_sum_local_service_demand/confidence_iterations;
+  measured_var_local_service_demand     = 
+    (double) measured_square_sum_local_service_demand/confidence_iterations
+      -measured_mean_local_service_demand*measured_mean_local_service_demand;
+
+  /* remote service demand */
+  measured_sum_remote_service_demand    +=
+    (double) rem_sd;
+  measured_square_sum_remote_service_demand+=
+    (double) rem_sd*rem_sd;
+  measured_mean_remote_service_demand   = 
+    (double) measured_sum_remote_service_demand/confidence_iterations;
+  measured_var_remote_service_demand    = 
+    (double) measured_square_sum_remote_service_demand/confidence_iterations
+      -measured_mean_remote_service_demand*measured_mean_remote_service_demand;
+
+  if(confidence_iterations>1){ 
+     result_confid= (double) interval - 
+       2.0 * confid(confidence_level,confidence_iterations-1)* 
+         sqrt(measured_var_result/(confidence_iterations-1.0)) / 
+           measured_mean_result;
+
+     loc_cpu_confid= (double) interval - 
+       2.0 * confid(confidence_level,confidence_iterations-1)* 
+         sqrt(measured_var_local_cpu/(confidence_iterations-1.0)) / 
+           measured_mean_local_cpu;
+
+     rem_cpu_confid= (double) interval - 
+       2.0 * confid(confidence_level,confidence_iterations-1)*
+         sqrt(measured_var_remote_cpu/(confidence_iterations-1.0)) / 
+           measured_mean_remote_cpu;
+
+     if(debug){
+       printf("Conf_itvl %2d: results:%4.1f%% loc_cpu:%4.1f%% rem_cpu:%4.1f%%\n",
+              confidence_iterations,
+              (interval-result_confid)*100.0,
+              (interval-loc_cpu_confid)*100.0,
+              (interval-rem_cpu_confid)*100.0);
+     }
+
+     /* if the user has requested that we only wait for the result to
+	be confident rather than the result and CPU util(s) then do
+	so. raj 2007-08-08 */
+     if (!result_confidence_only) {
+       confidence = min(min(result_confid,loc_cpu_confid),rem_cpu_confid);
+     }
+     else {
+       confidence = result_confid;
+     }
+  }
+}
+
+ /* here ends the IBM code */
+
+void
+retrieve_confident_values(float *elapsed_time,
+                          double *thruput,
+                          float *local_cpu_utilization,
+                          float *remote_cpu_utilization,
+                          float *local_service_demand,
+                          float *remote_service_demand)
+
+{
+  *elapsed_time            = (float)measured_mean_local_time;
+  *thruput                 = measured_mean_result;
+  *local_cpu_utilization   = (float)measured_mean_local_cpu;
+  *remote_cpu_utilization  = (float)measured_mean_remote_cpu;
+  *local_service_demand    = (float)measured_mean_local_service_demand;
+  *remote_service_demand   = (float)measured_mean_remote_service_demand;
+}
+
+ /* display_confidence() is called when we could not achieve the */
+ /* desirec confidence in the results. it will print the achieved */
+ /* confidence to "where" raj 11/94 */
+void
+display_confidence()
+
+{
+  fprintf(where,
+          "!!! WARNING\n");
+  fprintf(where,
+          "!!! Desired confidence was not achieved within ");
+  fprintf(where,
+          "the specified iterations.\n");
+  fprintf(where,
+          "!!! This implies that there was variability in ");
+  fprintf(where,
+          "the test environment that\n");
+  fprintf(where,
+          "!!! must be investigated before going further.\n");
+  fprintf(where,
+          "!!! Confidence intervals: Throughput      : %4.1f%%\n",
+          100.0 * (interval - result_confid));
+  fprintf(where,
+          "!!!                       Local CPU util  : %4.1f%%\n",
+          100.0 * (interval - loc_cpu_confid));
+  fprintf(where,
+          "!!!                       Remote CPU util : %4.1f%%\n\n",
+          100.0 * (interval - rem_cpu_confid));
+}
+
diff --git a/netlib.h b/netlib.h
new file mode 100644
index 0000000..5b6900e
--- /dev/null
+++ b/netlib.h
@@ -0,0 +1,621 @@
+/*
+        Copyright (C) 1993-2005 Hewlett-Packard Company
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_SYS_SOCKET_H)
+# include <sys/socket.h>
+#endif
+#if defined(HAVE_NETDB_H)
+# include <netdb.h>
+#endif
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
+# include "missing/getaddrinfo.h"
+#endif
+
+#define PAD_TIME 4
+/* library routine specifc defines                                      */
+#define         MAXSPECDATA     62      /* how many ints worth of data  */
+                                        /* can tests send...            */
+#define         MAXTIMES        4       /* how many times may we loop   */
+                                        /* to calibrate                 */
+#define         MAXCPUS         256     /* how many CPU's can we track */
+#define         MAXMESSAGESIZE  65536
+#define         MAXALIGNMENT    16384
+#define         MAXOFFSET        4096
+#define         DATABUFFERLEN   MAXMESSAGESIZE+MAXALIGNMENT+MAXOFFSET
+
+#define         DEBUG_ON                1
+#define         DEBUG_OFF               2
+#define         DEBUG_OK                3
+#define         NODE_IDENTIFY           4
+#define         CPU_CALIBRATE           5
+
+#define         DO_TCP_STREAM           10
+#define         TCP_STREAM_RESPONSE     11
+#define         TCP_STREAM_RESULTS      12
+
+#define         DO_TCP_RR               13
+#define         TCP_RR_RESPONSE         14
+#define         TCP_RR_RESULTS          15
+
+#define         DO_UDP_STREAM           16
+#define         UDP_STREAM_RESPONSE     17
+#define         UDP_STREAM_RESULTS      18
+
+#define         DO_UDP_RR               19
+#define         UDP_RR_RESPONSE         20
+#define         UDP_RR_RESULTS          21
+
+#define         DO_DLPI_CO_STREAM       22
+#define         DLPI_CO_STREAM_RESPONSE 23
+#define         DLPI_CO_STREAM_RESULTS  24
+
+#define         DO_DLPI_CO_RR           25
+#define         DLPI_CO_RR_RESPONSE     26
+#define         DLPI_CO_RR_RESULTS      27
+
+#define         DO_DLPI_CL_STREAM       28
+#define         DLPI_CL_STREAM_RESPONSE 29
+#define         DLPI_CL_STREAM_RESULTS  30
+
+#define         DO_DLPI_CL_RR           31
+#define         DLPI_CL_RR_RESPONSE     32
+#define         DLPI_CL_RR_RESULTS      33
+
+#define         DO_TCP_CRR              34
+#define         TCP_CRR_RESPONSE        35
+#define         TCP_CRR_RESULTS         36
+
+#define         DO_STREAM_STREAM        37
+#define         STREAM_STREAM_RESPONSE  38
+#define         STREAM_STREAM_RESULTS   39
+
+#define         DO_STREAM_RR            40
+#define         STREAM_RR_RESPONSE      41
+#define         STREAM_RR_RESULTS       42
+
+#define         DO_DG_STREAM            43
+#define         DG_STREAM_RESPONSE      44
+#define         DG_STREAM_RESULTS       45
+
+#define         DO_DG_RR                46
+#define         DG_RR_RESPONSE          47
+#define         DG_RR_RESULTS           48
+
+#define         DO_FORE_STREAM          49
+#define         FORE_STREAM_RESPONSE    50
+#define         FORE_STREAM_RESULTS     51
+
+#define         DO_FORE_RR              52
+#define         FORE_RR_RESPONSE        53
+#define         FORE_RR_RESULTS         54
+
+#define         DO_HIPPI_STREAM         55
+#define         HIPPI_STREAM_RESPONSE   56
+#define         HIPPI_STREAM_RESULTS    57
+
+#define         DO_HIPPI_RR             52
+#define         HIPPI_RR_RESPONSE       53
+#define         HIPPI_RR_RESULTS        54
+
+#define         DO_XTI_TCP_STREAM       55
+#define         XTI_TCP_STREAM_RESPONSE 56
+#define         XTI_TCP_STREAM_RESULTS  57
+
+#define         DO_XTI_TCP_RR           58
+#define         XTI_TCP_RR_RESPONSE     59
+#define         XTI_TCP_RR_RESULTS      60
+
+#define         DO_XTI_UDP_STREAM       61
+#define         XTI_UDP_STREAM_RESPONSE 62
+#define         XTI_UDP_STREAM_RESULTS  63
+
+#define         DO_XTI_UDP_RR           64
+#define         XTI_UDP_RR_RESPONSE     65
+#define         XTI_UDP_RR_RESULTS      66
+
+#define         DO_XTI_TCP_CRR          67
+#define         XTI_TCP_CRR_RESPONSE    68
+#define         XTI_TCP_CRR_RESULTS     69
+
+#define         DO_TCP_TRR              70
+#define         TCP_TRR_RESPONSE        71
+#define         TCP_TRR_RESULTS         72
+
+#define         DO_TCP_NBRR             73
+#define         TCP_NBRR_RESPONSE       74
+#define         TCP_NBRR_RESULTS        75
+
+#define         DO_TCPIPV6_STREAM           76
+#define         TCPIPV6_STREAM_RESPONSE     77
+#define         TCPIPV6_STREAM_RESULTS      78
+
+#define         DO_TCPIPV6_RR               79
+#define         TCPIPV6_RR_RESPONSE         80
+#define         TCPIPV6_RR_RESULTS          81
+
+#define         DO_UDPIPV6_STREAM           82
+#define         UDPIPV6_STREAM_RESPONSE     83
+#define         UDPIPV6_STREAM_RESULTS      84
+
+#define         DO_UDPIPV6_RR               85
+#define         UDPIPV6_RR_RESPONSE         86
+#define         UDPIPV6_RR_RESULTS          87
+
+#define         DO_TCPIPV6_CRR              88
+#define         TCPIPV6_CRR_RESPONSE        89
+#define         TCPIPV6_CRR_RESULTS         90
+
+#define         DO_TCPIPV6_TRR              91
+#define         TCPIPV6_TRR_RESPONSE        92
+#define         TCPIPV6_TRR_RESULTS         93
+
+#define         DO_TCP_MAERTS               94
+#define         TCP_MAERTS_RESPONSE         95
+#define         TCP_MAERTS_RESULTS          96
+
+#define         DO_LWPSTR_STREAM           100
+#define         LWPSTR_STREAM_RESPONSE     110
+#define         LWPSTR_STREAM_RESULTS      120
+
+#define         DO_LWPSTR_RR               130
+#define         LWPSTR_RR_RESPONSE         140
+#define         LWPSTR_RR_RESULTS          150
+
+#define         DO_LWPDG_STREAM            160
+#define         LWPDG_STREAM_RESPONSE      170
+#define         LWPDG_STREAM_RESULTS       180
+
+#define         DO_LWPDG_RR                190
+#define         LWPDG_RR_RESPONSE          200
+#define         LWPDG_RR_RESULTS           210
+
+#define         DO_TCP_CC                  300
+#define         TCP_CC_RESPONSE            301
+#define         TCP_CC_RESULTS             302
+
+/* The DNS_RR test has been removed from netperf but we leave these
+   here for historical purposes.  Those wanting to do DNS_RR tests
+   should use netperf4 instead. */
+#define         DO_DNS_RR                  400
+#define         DNS_RR_RESPONSE            401
+#define         DNS_RR_RESULTS             402
+
+#define         DO_SCTP_STREAM             500
+#define         SCTP_STREAM_RESPONSE       501
+#define         SCTP_STREAM_RESULT         502
+
+#define         DO_SCTP_STREAM_MANY        510
+#define         SCTP_STREAM_MANY_RESPONSE  511
+#define         SCTP_STREAM_MANY_RESULT    512
+
+#define         DO_SCTP_RR                 520
+#define         SCTP_RR_RESPONSE           521
+#define         SCTP_RR_RESULT             502
+
+#define         DO_SCTP_RR_MANY            530
+#define         SCTP_RR_MANY_RESPONSE      531
+#define         SCTP_RR_MANY_RESULT        532
+
+#define         DO_SDP_STREAM              540
+#define         SDP_STREAM_RESPONSE        541
+#define         SDP_STREAM_RESULTS         542
+
+#define         DO_SDP_RR                  543
+#define         SDP_RR_RESPONSE            544
+#define         SDP_RR_RESULTS             545
+
+#define         DO_SDP_MAERTS              546
+#define         SDP_MAERTS_RESPONSE        547
+#define         SDP_MAERTS_RESULTS         548
+
+#define         DO_SDP_CRR                 549
+#define         SDP_CRR_RESPONSE           550
+#define         SDP_CRR_RESULTS            551
+
+#define         DO_SDP_CC                  552
+#define         SDP_CC_RESPONSE            553
+#define         SDP_CC_RESULTS             554
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+enum sock_buffer{
+  SEND_BUFFER,
+  RECV_BUFFER
+};
+
+ /* some of the fields in these structures are going to be doubles and */
+ /* such. so, we probably want to ensure that they will start on */
+ /* "double" boundaries. this will break compatability to pre-2.1 */
+ /* releases, but then, backwards compatability has never been a */
+ /* stated goal of netperf. raj 11/95 */
+
+union netperf_request_struct {
+  struct {
+    int     request_type;
+    int     dummy;
+    int     test_specific_data[MAXSPECDATA];
+  } content;
+  double dummy;
+};
+
+union netperf_response_struct {
+  struct {
+    int response_type;
+    int serv_errno;
+    int test_specific_data[MAXSPECDATA];
+  } content;
+  double dummy;
+};
+
+struct ring_elt {
+  struct ring_elt *next;  /* next element in the ring */
+  char *buffer_base;      /* in case we have to free it at somepoint */
+  char *buffer_ptr;       /* the aligned and offset pointer */
+};
+
+/* +*+ SAF  Sorry about the hacks with errno; NT made me do it :(
+
+ WinNT does define an errno.
+ It is mostly a legacy from the XENIX days.
+
+ Depending upon the version of the C run time that is linked in, it is
+ either a simple variable (like UNIX code expects), but more likely it
+ is the address of a procedure to return the error number.  So any
+ code that sets errno is likely to be overwriting the address of this
+ procedure.  Worse, only a tiny fraction of NT's errors get set
+ through errno.
+
+ So I have changed the netperf code to use a define Set_errno when
+ that is it's intent.  On non-windows platforms this is just an
+ assignment to errno.  But on NT this calls SetLastError.
+
+ I also define errno (now only used on right side of assignments)
+ on NT to be GetLastError.
+
+ Similarly, perror is defined on NT, but it only accesses the same
+ XENIX errors that errno covers.  So on NT this is redefined to be
+ Perror and it expands all GetLastError texts. */
+
+
+#ifdef WIN32
+/* INVALID_SOCKET == INVALID_HANDLE_VALUE == (unsigned int)(~0) */
+/* SOCKET_ERROR == -1 */
+#define ENOTSOCK WSAENOTSOCK
+#define EINTR    WSAEINTR
+#define ENOBUFS  WSAENOBUFS
+#define EWOULDBLOCK    WSAEWOULDBLOCK
+#define EAFNOSUPPORT  WSAEAFNOSUPPORT
+/* I don't use a C++ style of comment because it upsets some C
+   compilers, possibly even when it is inside an ifdef WIN32... */
+/* from public\sdk\inc\crt\errno.h */
+#define ENOSPC          28
+
+#ifdef errno
+/* delete the one from stdlib.h  */
+/*#define errno       (*_errno()) */
+#undef errno
+#endif
+#define errno GetLastError()
+#define Set_errno(num) SetLastError((num))
+
+#define perror(text) PrintWin32Error(stderr, (text))
+#define Print_errno(stream, text) PrintWin32Error((stream), (text))
+
+extern void PrintWin32Error(FILE *stream, LPSTR text);
+
+#if !defined(NT_PERF) && !defined(USE_LOOPER)
+#define NT_PERF
+#endif
+#else
+/* Really shouldn't use manifest constants! */
+/*+*+SAF There are other examples of "== -1" and "<0" that probably */
+/*+*+SAF should be cleaned up as well. */
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+
+#define SOCKET int
+#define Set_errno(num) errno = (num)
+
+#define Print_errno(stream, text) fprintf((stream), "%s  errno %d\n", (text), errno)
+#endif
+
+/* Robin & Rick's kludge to try to have a timer signal EINTR by closing  */
+/* the socket from another thread can also return several other errors. */
+/* Let's define a macro to hide all of this. */
+
+#ifndef WIN32
+#define SOCKET_EINTR(return_value) (errno == EINTR)
+#define SOCKET_EADDRINUSE(return_value) (errno == EADDRINUSE)
+#define SOCKET_EADDRNOTAVAIL(return_value) (errno == EADDRNOTAVAIL)
+
+#else
+
+/* not quite sure I like the extra cases for WIN32 but that is what my
+   WIN32 expert sugested.  I'm not sure what WSA's to put for
+   EADDRINUSE */
+
+#define SOCKET_EINTR(return_value) \
+		(((return_value) == SOCKET_ERROR) && \
+	     ((errno == EINTR) || \
+	      (errno == WSAECONNABORTED) || \
+	      (errno == WSAECONNRESET) ))
+#define SOCKET_EADDRINUSE(return_value) \
+		(((return_value) == SOCKET_ERROR) && \
+	     ((errno == WSAEADDRINUSE) ))
+#define SOCKET_EADDRNOTAVAIL(return_value) \
+		(((return_value) == SOCKET_ERROR) && \
+	     ((errno == WSAEADDRNOTAVAIL) ))
+#endif
+
+#ifdef HAVE_SENDFILE
+
+struct sendfile_ring_elt {
+  struct sendfile_ring_elt *next; /* next element in the ring */
+  int fildes;                     /* the file descriptor of the source
+				     file */ 
+  off_t offset;                   /* the offset from the beginning of
+				     the file for this send */
+  size_t length;                  /* the number of bytes to send -
+				     this is redundant with the
+				     send_size variable but I decided
+				     to include it anyway */
+  struct iovec *hdtrl;            /* a pointer to a header/trailer
+				     that we do not initially use and
+				     so should be set to NULL when the 
+				     ring is setup. */
+  int flags;                      /* the flags to pass to sendfile() - 
+				     presently unused and should be
+				     set to zero when the ring is
+				     setup. */
+};
+
+#endif /* HAVE_SENDFILE */
+
+ /* the diferent codes to denote the type of CPU utilization */
+ /* methods used */
+#define CPU_UNKNOWN     0
+#define HP_IDLE_COUNTER 1
+#define PSTAT           2
+#define TIMES           3
+#define LOOPER          4
+#define GETRUSAGE       5
+#define NT_METHOD       6
+#define KSTAT           7
+#define PROC_STAT       8
+#define SYSCTL          9
+#define PERFSTAT       10
+#define KSTAT_10       11
+#define OSX            12
+
+#define BADCH ('?')
+
+#ifndef NETLIB
+#ifdef WIN32
+#ifndef _GETOPT_
+#define _GETOPT_
+
+int getopt(int argc, char **argv, char *optstring);
+
+extern char *optarg;		/* returned arg to go with this option */
+extern int optind;		/* index to next argv element to process */
+extern int opterr;		/* should error messages be printed? */
+extern int optopt;		/* */
+
+#endif /* _GETOPT_ */
+
+extern  SOCKET     win_kludge_socket, win_kludge_socket2;
+#endif /* WIN32 */
+
+extern  int   local_proc_affinity, remote_proc_affinity;
+
+/* these are to allow netperf to be run easily through those evil,
+   end-to-end breaking things known as firewalls */
+extern char local_data_port[10];
+extern char remote_data_port[10];
+
+extern char *local_data_address;
+extern char *remote_data_address;
+
+extern int local_data_family;
+extern int remote_data_family;
+
+extern  union netperf_request_struct netperf_request;
+extern  union netperf_response_struct netperf_response;
+
+extern  float    lib_local_cpu_util;
+extern  float    lib_elapsed;
+extern  float    lib_local_maxrate;
+
+extern  char    libfmt;
+
+extern  int     cpu_method;
+extern  int     lib_num_loc_cpus;
+extern  int     lib_num_rem_cpus;
+extern  SOCKET  server_sock;
+extern  int     times_up;
+extern  FILE    *where;
+extern  int     loops_per_msec;
+extern  float   lib_local_per_cpu_util[];
+  
+extern  void    netlib_init();
+extern  int     netlib_get_page_size();
+extern  void    install_signal_catchers();
+extern  void    establish_control(char hostname[], 
+				  char port[], 
+				  int af,
+				  char local_hostname[],
+				  char local_port[],
+				  int local_af);
+extern  void    shutdown_control();
+extern  void    init_stat();
+extern  void    send_request();
+extern  void    recv_response();
+extern  void    send_response();
+extern  void    recv_request();
+extern  void    dump_request();
+extern  void    dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+			      char *host, char *port, int family);
+extern  void    start_timer(int time);
+extern  void    stop_timer();
+extern  void    cpu_start(int measure_cpu);
+extern  void    cpu_stop(int measure_cpu, float *elapsed);
+extern  void	calculate_confidence(int confidence_iterations,
+		     float time,
+		     double result,
+		     float loc_cpu,
+		     float rem_cpu,
+		     float loc_sd,
+		     float rem_sd);
+extern  void	retrieve_confident_values(float *elapsed_time,
+			  double *thruput,
+			  float *local_cpu_utilization,
+			  float *remote_cpu_utilization,
+			  float *local_service_demand,
+			  float *remote_service_demand);
+extern  void    display_confidence();
+extern  void    set_sock_buffer(SOCKET sd,
+				enum sock_buffer which,
+				int requested_size,
+				int *effective_sizep);
+extern  char   *format_units();
+
+extern  char    *inet_ftos(int family);
+extern  char    *inet_ttos(int type);
+extern  char    *inet_ptos(int protocol);
+extern  double  ntohd(double net_double);
+extern  double  htond(double host_double);
+extern  int     inet_nton(int af, const void *src, char *dst, int cnt);
+extern  void    libmain();
+extern  double  calc_thruput(double units_received);
+extern  double  calc_thruput_interval(double units_received,double elapsed);
+extern  double  calc_thruput_omni(double units_received);
+extern  double  calc_thruput_interval_omni(double units_received,double elapsed);
+extern  float   calibrate_local_cpu(float local_cpu_rate);
+extern  float   calibrate_remote_cpu();
+extern  void    bind_to_specific_processor(int processor_affinity,int use_cpu_map);
+extern int      set_nonblock (SOCKET sock);
+
+#ifndef WIN32
+
+/* WIN32 requires that at least one of the file sets to select be
+ non-null.  Since msec_sleep routine is only called by nettest_dlpi &
+ nettest_unix, let's duck this issue. */
+
+extern int msec_sleep( int msecs );
+#endif  /* WIN32 */
+extern  float   calc_cpu_util(float elapsed_time);
+extern  float	calc_service_demand(double units_sent,
+				    float elapsed_time,
+				    float cpu_utilization,
+				    int num_cpus);
+extern  float	calc_service_demand_trans(double units_sent,
+					  float elapsed_time,
+					  float cpu_utilization,
+					  int num_cpus);
+#if defined(__hpux)
+extern  void    catcher(int, siginfo_t *,void *);
+#else
+extern  void    catcher(int);
+#endif /* __hpux */
+extern  struct ring_elt *allocate_buffer_ring();
+extern void access_buffer(char *buffer_ptr,
+			  int length,
+			  int dirty_count,
+			  int clean_count);
+
+#ifdef HAVE_ICSC_EXS
+extern  struct ring_elt *allocate_exs_buffer_ring();
+#endif /* HAVE_ICSC_EXS */
+#ifdef HAVE_SENDFILE
+extern  struct sendfile_ring_elt *alloc_sendfile_buf_ring();
+#endif /* HAVE_SENDFILE */
+#ifdef WANT_DLPI
+/* it seems that AIX in its finite wisdom has some bogus define in an
+   include file which defines "rem_addr" which then screws-up this extern
+   unless we change the names to protect the guilty. reported by Eric
+   Jones */
+extern int dl_connect(int fd, unsigned char *remote_addr, int remote_addr_len);
+extern int dl_bind(int fd, int sap, int mode, char *dlsap_ptr, int *dlsap_len);
+extern  int     dl_open(char devfile[], int ppa);
+#endif /* WANT_DLPI */
+extern  char    format_cpu_method(int method);
+extern unsigned int convert(char *string);
+extern unsigned int convert_timespec(char *string);
+
+#ifdef WANT_INTERVALS
+extern void start_itimer(unsigned int interval_len_msec);
+#endif
+ /* these are all for the confidence interval stuff */
+extern double confidence;
+
+#endif
+
+#ifdef WIN32
+#define close(x)	closesocket(x)
+#define strcasecmp(a,b) _stricmp(a,b)
+#define getpid() ((int)GetCurrentProcessId())
+#endif
+
+#ifdef WIN32
+#if 0
+/* Should really use safe string functions; but not for now... */
+#include <strsafe.h>
+/* Microsoft has deprecated _snprintf; it isn't guarenteed to null terminate the result buffer. */
+/* They want us to call StringCbPrintf instead; it always null terminates the string. */
+#endif
+
+#define snprintf _snprintf
+#endif
+
+/* Define a macro to align a buffer with an offset from a power of 2
+   boundary. */
+
+#ifndef WIN32
+#define ULONG_PTR unsigned long
+#endif
+
+#define ALIGN_BUFFER(BufPtr, Align, Offset) \
+  (char *)(( (ULONG_PTR)(BufPtr) + \
+			(ULONG_PTR) (Align) -1) & \
+			~((ULONG_PTR) (Align) - 1)) + (ULONG_PTR)(Offset)
+
+ /* if your system has bcopy and bzero, include it here, otherwise, we */
+ /* will try to use memcpy aand memset. fix from Bruce Barnett @ GE. */
+#if defined(hpux) || defined (__VMS)
+#define HAVE_BCOPY
+#define HAVE_BZERO
+#endif
+
+#ifdef WIN32
+#define HAVE_MIN
+#else
+#define _stdcall
+#define _cdecl
+#endif
+
+#ifndef HAVE_BCOPY
+#define bcopy(s,d,h) memcpy((d),(s),(h))
+#endif /* HAVE_BCOPY */
+
+#ifndef HAVE_BZERO
+#define bzero(p,h) memset((p),0,(h))
+#endif /* HAVE_BZERO */
+
+#ifndef HAVE_MIN
+#define min(a,b) ((a < b) ? a : b)
+#endif /* HAVE_MIN */
+
+#ifdef USE_PERFSTAT
+# include <libperfstat.h>
+#endif
diff --git a/netperf.c b/netperf.c
new file mode 100644
index 0000000..84717ac
--- /dev/null
+++ b/netperf.c
@@ -0,0 +1,284 @@
+/*
+ 
+	   Copyright (C) 1993-2007 Hewlett-Packard Company
+                         ALL RIGHTS RESERVED.
+ 
+  The enclosed software and documentation includes copyrighted works
+  of Hewlett-Packard Co. For as long as you comply with the following
+  limitations, you are hereby authorized to (i) use, reproduce, and
+  modify the software and documentation, and to (ii) distribute the
+  software and documentation, including modifications, for
+  non-commercial purposes only.
+      
+  1.  The enclosed software and documentation is made available at no
+      charge in order to advance the general development of
+      high-performance networking products.
+ 
+  2.  You may not delete any copyright notices contained in the
+      software or documentation. All hard copies, and copies in
+      source code or object code form, of the software or
+      documentation (including modifications) must contain at least
+      one of the copyright notices.
+ 
+  3.  The enclosed software and documentation has not been subjected
+      to testing and quality control and is not a Hewlett-Packard Co.
+      product. At a future time, Hewlett-Packard Co. may or may not
+      offer a version of the software and documentation as a product.
+  
+  4.  THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS".
+      HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE,
+      REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
+      DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL
+      PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR
+      DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES,
+      EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE
+      DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF
+      MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  
+  5.  HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY
+      DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+      (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION,
+      MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION.
+ 
+*/
+char	netperf_id[]="\
+@(#)netperf.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3";
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+/* FreeBSD doesn't like socket.h before types are set. */
+#if __FreeBSD__
+# include <sys/types.h>
+#endif
+
+#ifndef WIN32
+/* this should only be temporary */
+#include <sys/socket.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif /* WIN32 */
+
+#include "netsh.h"
+#include "netlib.h"
+#include "nettest_bsd.h"
+
+#ifdef WANT_UNIX
+#include "nettest_unix.h"
+#endif /* WANT_UNIX */
+
+#ifdef WANT_XTI
+#include "nettest_xti.h"
+#endif /* WANT_XTI */
+
+#ifdef WANT_DLPI
+#include "nettest_dlpi.h"
+#endif /* WANT_DLPI */
+
+#ifdef WANT_SDP
+#include "nettest_sdp.h"
+#endif
+
+/* The DNS tests have been removed from netperf2. Those wanting to do
+   DNS_RR tests should use netperf4 instead. */
+
+#ifdef DO_DNS
+#error DNS tests have been removed from netperf. Use netperf4 instead
+#endif /* DO_DNS */
+
+#ifdef WANT_SCTP
+#include "nettest_sctp.h"
+#endif
+
+ /* this file contains the main for the netperf program. all the other */
+ /* routines can be found in the file netsh.c */
+
+
+int _cdecl
+main(int argc, char *argv[])
+{
+
+#ifdef WIN32
+  WSADATA	wsa_data ;
+  
+  /* Initialize the winsock lib ( version 2.2 ) */
+  if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){
+    printf("WSAStartup() failed : %d\n", GetLastError()) ;
+    return 1 ;
+  }
+#endif /* WIN32 */
+  
+  netlib_init();
+  set_defaults();
+  scan_cmd_line(argc,argv);
+  
+  if (debug) {
+    dump_globals();
+    install_signal_catchers();
+  }
+  
+  if (debug) {
+    printf("remotehost is %s and port %s\n",host_name,test_port);
+    fflush(stdout);
+  }
+  
+  
+  if (!no_control) {
+    establish_control(host_name,test_port,address_family,
+		      local_host_name,local_test_port,local_address_family);
+  }
+  
+  if (strcasecmp(test_name,"TCP_STREAM") == 0) {
+    send_tcp_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"TCP_MAERTS") == 0) {
+    send_tcp_maerts(host_name);
+  }
+#ifdef HAVE_ICSC_EXS
+  else if (strcasecmp(test_name,"EXS_TCP_STREAM") == 0) {
+    send_exs_tcp_stream(host_name);
+  }
+#endif /* HAVE_ICSC_EXS */
+#ifdef HAVE_SENDFILE
+  else if (strcasecmp(test_name,"TCP_SENDFILE") == 0) {
+    sendfile_tcp_stream(host_name);
+  }
+#endif /* HAVE_SENDFILE */
+  else if (strcasecmp(test_name,"TCP_RR") == 0) {
+    send_tcp_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"TCP_CRR") == 0) {
+    send_tcp_conn_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"TCP_CC") == 0) {
+    send_tcp_cc(host_name);
+  }
+#ifdef DO_1644
+  else if (strcasecmp(test_name,"TCP_TRR") == 0) {
+    send_tcp_tran_rr(host_name);
+  }
+#endif /* DO_1644 */
+#ifdef DO_NBRR
+  else if (strcasecmp(test_name,"TCP_NBRR") == 0) {
+    send_tcp_nbrr(host_name);
+  }
+#endif /* DO_NBRR */
+  else if (strcasecmp(test_name,"UDP_STREAM") == 0) {
+    send_udp_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"UDP_RR") == 0) {
+    send_udp_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"LOC_CPU") == 0) {
+    loc_cpu_rate();
+  }
+  else if (strcasecmp(test_name,"REM_CPU") == 0) {
+    rem_cpu_rate();
+  }
+#ifdef WANT_DLPI
+  else if (strcasecmp(test_name,"DLCO_RR") == 0) {
+    send_dlpi_co_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"DLCL_RR") == 0) {
+    send_dlpi_cl_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"DLCO_STREAM") == 0) {
+    send_dlpi_co_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"DLCL_STREAM") == 0) {
+    send_dlpi_cl_stream(host_name);
+  }
+#endif /* WANT_DLPI */
+#ifdef WANT_UNIX
+  else if (strcasecmp(test_name,"STREAM_RR") == 0) {
+    send_stream_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"DG_RR") == 0) {
+    send_dg_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"STREAM_STREAM") == 0) {
+    send_stream_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"DG_STREAM") == 0) {
+    send_dg_stream(host_name);
+  }
+#endif /* WANT_UNIX */
+#ifdef WANT_XTI
+  else if (strcasecmp(test_name,"XTI_TCP_STREAM") == 0) {
+    send_xti_tcp_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"XTI_TCP_RR") == 0) {
+    send_xti_tcp_rr(host_name);
+  }
+  else if (strcasecmp(test_name,"XTI_UDP_STREAM") == 0) {
+    send_xti_udp_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"XTI_UDP_RR") == 0) {
+    send_xti_udp_rr(host_name);
+  }
+#endif /* WANT_XTI */
+  
+#ifdef WANT_SCTP
+  else if (strcasecmp(test_name, "SCTP_STREAM") == 0) {
+    send_sctp_stream(host_name);
+  }       
+  else if (strcasecmp(test_name, "SCTP_RR") == 0) {
+    send_sctp_rr(host_name);
+  }
+  else if (strcasecmp(test_name, "SCTP_STREAM_MANY") == 0) {
+    send_sctp_stream_1toMany(host_name);
+  }
+  else if (strcasecmp(test_name, "SCTP_RR_MANY") == 0) {
+    send_sctp_stream_1toMany(host_name);
+  }
+#endif
+  
+#ifdef DO_DNS
+  else if (strcasecmp(test_name,"DNS_RR") == 0) {
+    fprintf(stderr,
+	  "DNS tests can now be found in netperf4.\n");
+    fflush(stderr);
+    exit(-1);
+  }
+#endif /* DO_DNS */
+#ifdef WANT_SDP
+  else if (strcasecmp(test_name,"SDP_STREAM") == 0) {
+    send_sdp_stream(host_name);
+  }
+  else if (strcasecmp(test_name,"SDP_MAERTS") == 0) {
+    send_sdp_maerts(host_name);
+  }
+  else if (strcasecmp(test_name,"SDP_RR") == 0) {
+    send_sdp_rr(host_name);
+  }
+#endif /* WANT_SDP */
+  else {
+    printf("The test you requested is unknown to this netperf.\n");
+    printf("Please verify that you have the correct test name, \n");
+    printf("and that test family has been compiled into this netperf.\n");
+    exit(1);
+  }
+  
+  if (!no_control) {
+    shutdown_control();
+  }
+  
+#ifdef WIN32
+  /* Cleanup the winsock lib */
+  WSACleanup();
+#endif
+  
+  return(0);
+}
+
+
diff --git a/netperf_version.h b/netperf_version.h
new file mode 100644
index 0000000..b2b9fdc
--- /dev/null
+++ b/netperf_version.h
@@ -0,0 +1 @@
+#define NETPERF_VERSION "2.4.4"
diff --git a/netserver.c b/netserver.c
new file mode 100644
index 0000000..02be3ce
--- /dev/null
+++ b/netserver.c
@@ -0,0 +1,1022 @@
+/*
+ 
+	   Copyright (C) 1993-2007 Hewlett-Packard Company
+                         ALL RIGHTS RESERVED.
+ 
+  The enclosed software and documentation includes copyrighted works
+  of Hewlett-Packard Co. For as long as you comply with the following
+  limitations, you are hereby authorized to (i) use, reproduce, and
+  modify the software and documentation, and to (ii) distribute the
+  software and documentation, including modifications, for
+  non-commercial purposes only.
+      
+  1.  The enclosed software and documentation is made available at no
+      charge in order to advance the general development of
+      high-performance networking products.
+ 
+  2.  You may not delete any copyright notices contained in the
+      software or documentation. All hard copies, and copies in
+      source code or object code form, of the software or
+      documentation (including modifications) must contain at least
+      one of the copyright notices.
+ 
+  3.  The enclosed software and documentation has not been subjected
+      to testing and quality control and is not a Hewlett-Packard Co.
+      product. At a future time, Hewlett-Packard Co. may or may not
+      offer a version of the software and documentation as a product.
+  
+  4.  THE SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS".
+      HEWLETT-PACKARD COMPANY DOES NOT WARRANT THAT THE USE,
+      REPRODUCTION, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
+      DOCUMENTATION WILL NOT INFRINGE A THIRD PARTY'S INTELLECTUAL
+      PROPERTY RIGHTS. HP DOES NOT WARRANT THAT THE SOFTWARE OR
+      DOCUMENTATION IS ERROR FREE. HP DISCLAIMS ALL WARRANTIES,
+      EXPRESS AND IMPLIED, WITH REGARD TO THE SOFTWARE AND THE
+      DOCUMENTATION. HP SPECIFICALLY DISCLAIMS ALL WARRANTIES OF
+      MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  
+  5.  HEWLETT-PACKARD COMPANY WILL NOT IN ANY EVENT BE LIABLE FOR ANY
+      DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+      (INCLUDING LOST PROFITS) RELATED TO ANY USE, REPRODUCTION,
+      MODIFICATION, OR DISTRIBUTION OF THE SOFTWARE OR DOCUMENTATION.
+ 
+*/
+
+#include "netperf_version.h"
+
+char	netserver_id[]="\
+@(#)netserver.c (c) Copyright 1993-2007 Hewlett-Packard Co. Version 2.4.3";
+
+ /***********************************************************************/
+ /*									*/
+ /*	netserver.c							*/
+ /*									*/
+ /*	This is the server side code for the netperf test package. It	*/
+ /* will operate either stand-alone, or as a child of inetd. In this	*/
+ /* way, we insure that it can be installed on systems with or without	*/
+ /* root permissions (editing inetd.conf). Essentially, this code is	*/
+ /* the analog to the netsh.c code.					*/
+ /*									*/
+ /***********************************************************************/
+
+
+/************************************************************************/
+/*									*/
+/*	Global include files						*/
+/*									*/
+/************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#include <sys/types.h>
+#include <stdio.h>
+#ifndef WIN32
+#include <errno.h>
+#include <signal.h>
+#endif
+#if !defined(WIN32) && !defined(__VMS)
+#include <sys/ipc.h>
+#endif /* !defined(WIN32) && !defined(__VMS) */
+#include <fcntl.h>
+#ifdef WIN32
+#include <time.h>
+#include <winsock2.h>
+#define netperf_socklen_t socklen_t
+/* we need to find some other way to decide to include ws2 */
+/* if you are trying to compile on Windows 2000 or NT 4 you will */
+/* probably have to define DONT_IPV6 */
+#ifndef DONT_IPV6
+#include <ws2tcpip.h>
+#endif  /* DONT_IPV6 */
+#include <windows.h>
+#define sleep(x) Sleep((x)*1000)
+#else
+#ifndef MPE
+#include <sys/time.h>
+#endif /* MPE */
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#ifndef DONT_WAIT
+#include <sys/wait.h>
+#endif /* DONT_WAIT */
+#endif /* WIN32 */
+#include <stdlib.h>
+#ifdef __VMS
+#include <tcpip$inetdef.h> 
+#include <unixio.h> 
+#endif /* __VMS */
+#include "netlib.h"
+#include "nettest_bsd.h"
+
+#ifdef WANT_UNIX
+#include "nettest_unix.h"
+#endif /* WANT_UNIX */
+
+#ifdef WANT_DLPI
+#include "nettest_dlpi.h"
+#endif /* WANT_DLPI */
+
+#ifdef WANT_SCTP
+#include "nettest_sctp.h"
+#endif
+
+#include "netsh.h"
+
+#ifndef DEBUG_LOG_FILE
+#ifndef WIN32
+#define DEBUG_LOG_FILE "/tmp/netperf.debug"
+#else
+#define DEBUG_LOG_FILE "c:\\temp\\netperf.debug"
+#endif  /* WIN32 */
+#endif /* DEBUG_LOG_FILE */
+
+ /* some global variables */
+
+FILE	*afp;
+char    listen_port[10];
+extern	char	*optarg;
+extern	int	optind, opterr;
+
+#ifndef WIN32
+#define SERVER_ARGS "dL:n:p:v:V46"
+#else
+#define SERVER_ARGS "dL:n:p:v:V46I:i:"
+#endif
+
+/* perhaps one day we will use this as part of only opening a debug
+   log file if debug is set, of course we have to be wary of the base
+   use of "where" and so probably always need "where" pointing
+   "somewhere" or other. */
+void
+open_debug_file() 
+{
+#ifndef WIN32
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+  char FileName[PATH_MAX];   /* for opening the debug log file */
+  strcpy(FileName, DEBUG_LOG_FILE);
+
+  if (where != NULL) fflush(where);
+
+  snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid());
+  if ((where = fopen(FileName, "w")) == NULL) {
+    perror("netserver: debug file");
+    exit(1);
+  }
+
+  chmod(FileName,0644);
+#endif
+
+}
+ /* This routine implements the "main event loop" of the netperf	*/
+ /* server code. Code above it will have set-up the control connection	*/
+ /* so it can just merrily go about its business, which is to		*/
+ /* "schedule" performance tests on the server.				*/
+
+void 
+process_requests()
+{
+  
+  float	temp_rate;
+  
+  if (debug)    open_debug_file();
+
+
+  while (1) {
+    recv_request();
+
+    switch (netperf_request.content.request_type) {
+      
+    case DEBUG_ON:
+      netperf_response.content.response_type = DEBUG_OK;
+      /*  dump_request already present in recv_request; redundant? */
+      if (!debug) {
+	debug++;
+	open_debug_file();
+	dump_request();
+      }
+      send_response();
+      break;
+      
+    case DEBUG_OFF:
+      if (debug)
+	debug--;
+      netperf_response.content.response_type = DEBUG_OK;
+      send_response();
+      /* +SAF why??? */
+      if (!debug) 
+      {
+	fclose(where);
+#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
+	/* For Unix: reopen the debug write file descriptor to "/dev/null" */
+	/* and redirect stdout to it.					   */
+	fflush (stdout);
+	where = fopen ("/dev/null", "w");
+	if (where == NULL)
+	{
+	  perror ("netserver: reopening debug fp for writing: /dev/null");
+	  exit   (1);
+	}
+	if (close (STDOUT_FILENO) == -1)
+	{
+	  perror ("netserver: closing stdout file descriptor");
+	  exit   (1);
+	}
+	if (dup (fileno (where))  == -1)
+	{
+	  perror ("netserver: duplicate /dev/null write file descr. to stdout");
+	  exit   (1);
+	}
+#endif /* !WIN32 !MPE !__VMS */
+      }
+      break;
+      
+    case CPU_CALIBRATE:
+      netperf_response.content.response_type = CPU_CALIBRATE;
+      temp_rate = calibrate_local_cpu(0.0);
+      bcopy((char *)&temp_rate,
+	    (char *)netperf_response.content.test_specific_data,
+	    sizeof(temp_rate));
+      bcopy((char *)&lib_num_loc_cpus,
+	    (char *)netperf_response.content.test_specific_data + sizeof(temp_rate),
+	    sizeof(lib_num_loc_cpus));
+      if (debug) {
+	fprintf(where,"netserver: sending CPU information:");
+	fprintf(where,"rate is %g num cpu %d\n",temp_rate,lib_num_loc_cpus);
+	fflush(where);
+      }
+      
+      /* we need the cpu_start, cpu_stop in the looper case to kill the */
+      /* child proceses raj 7/95 */
+      
+#ifdef USE_LOOPER
+      cpu_start(1);
+      cpu_stop(1,&temp_rate);
+#endif /* USE_LOOPER */
+      
+      send_response();
+      break;
+      
+    case DO_TCP_STREAM:
+      recv_tcp_stream();
+      break;
+      
+    case DO_TCP_MAERTS:
+      recv_tcp_maerts();
+      break;
+      
+    case DO_TCP_RR:
+      recv_tcp_rr();
+      break;
+      
+    case DO_TCP_CRR:
+      recv_tcp_conn_rr();
+      break;
+      
+    case DO_TCP_CC:
+      recv_tcp_cc();
+      break;
+      
+#ifdef DO_1644
+    case DO_TCP_TRR:
+      recv_tcp_tran_rr();
+      break;
+#endif /* DO_1644 */
+      
+#ifdef DO_NBRR
+    case DO_TCP_NBRR:
+      recv_tcp_nbrr();
+      break;
+#endif /* DO_NBRR */
+      
+    case DO_UDP_STREAM:
+      recv_udp_stream();
+      break;
+      
+    case DO_UDP_RR:
+      recv_udp_rr();
+      break;
+      
+#ifdef WANT_DLPI
+
+    case DO_DLPI_CO_RR:
+      recv_dlpi_co_rr();
+      break;
+      
+    case DO_DLPI_CL_RR:
+      recv_dlpi_cl_rr();
+      break;
+
+    case DO_DLPI_CO_STREAM:
+      recv_dlpi_co_stream();
+      break;
+
+    case DO_DLPI_CL_STREAM:
+      recv_dlpi_cl_stream();
+      break;
+
+#endif /* WANT_DLPI */
+
+#ifdef WANT_UNIX
+
+    case DO_STREAM_STREAM:
+      recv_stream_stream();
+      break;
+      
+    case DO_STREAM_RR:
+      recv_stream_rr();
+      break;
+      
+    case DO_DG_STREAM:
+      recv_dg_stream();
+      break;
+      
+    case DO_DG_RR:
+      recv_dg_rr();
+      break;
+      
+#endif /* WANT_UNIX */
+
+#ifdef WANT_XTI
+    case DO_XTI_TCP_STREAM:
+      recv_xti_tcp_stream();
+      break;
+      
+    case DO_XTI_TCP_RR:
+      recv_xti_tcp_rr();
+      break;
+      
+    case DO_XTI_UDP_STREAM:
+      recv_xti_udp_stream();
+      break;
+      
+    case DO_XTI_UDP_RR:
+      recv_xti_udp_rr();
+      break;
+
+#endif /* WANT_XTI */
+
+#ifdef WANT_SCTP
+    case DO_SCTP_STREAM:
+      recv_sctp_stream();
+      break;
+      
+    case DO_SCTP_STREAM_MANY:
+      recv_sctp_stream_1toMany();
+      break;
+
+    case DO_SCTP_RR:
+      recv_sctp_rr();
+      break;
+
+    case DO_SCTP_RR_MANY:
+      recv_sctp_rr_1toMany();
+      break;
+#endif
+
+#ifdef WANT_SDP
+    case DO_SDP_STREAM:
+      recv_sdp_stream();
+      break;
+
+    case DO_SDP_MAERTS:
+      recv_sdp_maerts();
+      break;
+
+    case DO_SDP_RR:
+      recv_sdp_rr();
+      break;
+#endif 
+
+    default:
+      fprintf(where,"unknown test number %d\n",
+	      netperf_request.content.request_type);
+      fflush(where);
+      netperf_response.content.serv_errno=998;
+      send_response();
+      break;
+      
+    }
+  }
+}
+
+/*	
+ set_up_server()
+
+ set-up the server listen socket. we only call this routine if the 
+ user has specified a port number on the command line or we believe we
+ are not a child of inetd or its platform-specific equivalent */
+
+/*KC*/
+
+void 
+set_up_server(char hostname[], char port[], int af)
+{ 
+
+  struct addrinfo     hints;
+  struct addrinfo     *local_res;
+  struct addrinfo     *local_res_temp;
+
+  struct sockaddr_storage     peeraddr;
+  netperf_socklen_t                 peeraddr_len = sizeof(peeraddr);
+  
+  SOCKET server_control;
+  int on=1;
+  int count;
+  int error;
+  int not_listening;
+
+#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
+  FILE *rd_null_fp;    /* Used to redirect from "/dev/null". */
+  FILE *wr_null_fp;    /* Used to redirect to   "/dev/null". */
+#endif /* !WIN32 !MPE !__VMS */
+
+  if (debug) {
+    fprintf(stderr,
+            "set_up_server called with host '%s' port '%s' remfam %d\n",
+            hostname,
+	    port,
+            af);
+    fflush(stderr);
+  }
+
+  memset(&hints,0,sizeof(hints));
+  hints.ai_family = af;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = IPPROTO_TCP;
+  hints.ai_flags = AI_PASSIVE;
+
+  count = 0;
+  do {
+    error = getaddrinfo((char *)hostname,
+                        (char *)port,
+                        &hints,
+                        &local_res);
+    count += 1;
+    if (error == EAI_AGAIN) {
+      if (debug) {
+        fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n");
+        fflush(stderr);
+      }
+      sleep(1);
+    }
+  } while ((error == EAI_AGAIN) && (count <= 5));
+
+  if (error) {
+    fprintf(stderr,
+	    "set_up_server: could not resolve remote '%s' port '%s' af %d",
+	    hostname,
+	    port,
+	    af);
+    fprintf(stderr,"\n\tgetaddrinfo returned %d %s\n",
+	    error,
+	    gai_strerror(error));
+    exit(-1);
+  }
+
+  if (debug) {
+    dump_addrinfo(stderr, local_res, hostname, port, af);
+  }
+
+  not_listening = 1;
+  local_res_temp = local_res;
+
+  while((local_res_temp != NULL) && (not_listening)) {
+
+    fprintf(stderr,
+	    "Starting netserver at port %s\n",
+	    port);
+
+    server_control = socket(local_res_temp->ai_family,SOCK_STREAM,0);
+
+    if (server_control == INVALID_SOCKET) {
+      perror("set_up_server could not allocate a socket");
+      exit(-1);
+    }
+
+    /* happiness and joy, keep going */
+    if (setsockopt(server_control, 
+		   SOL_SOCKET, 
+		   SO_REUSEADDR, 
+		   (char *)&on , 
+		   sizeof(on)) == SOCKET_ERROR) {
+      if (debug) {
+	perror("warning: set_up_server could not set SO_REUSEADDR");
+      }
+    }
+    /* still happy and joyful */
+
+    if ((bind (server_control, 
+	       local_res_temp->ai_addr, 
+	       local_res_temp->ai_addrlen) != SOCKET_ERROR) &&
+	(listen (server_control,5) != SOCKET_ERROR))  {
+      not_listening = 0;
+      break;
+    }
+    else {
+      /* we consider a bind() or listen() failure a transient and try
+	 the next address */
+      if (debug) {
+	perror("warning: set_up_server failed a bind or listen call\n");
+      }
+      local_res_temp = local_res_temp->ai_next;
+      continue;
+    }
+  }
+
+  if (not_listening) {
+    fprintf(stderr,
+	    "set_up_server could not establish a listen endpoint for %s port %s with family %s\n",
+	    host_name,
+	    port,
+	    inet_ftos(af));
+    fflush(stderr);
+    exit(-1);
+  }
+  else {
+    printf("Starting netserver at hostname %s port %s and family %s\n",
+	   hostname,
+	   port,
+	   inet_ftos(af));
+  }
+
+  /*
+    setpgrp();
+    */
+
+#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
+  /* Flush the standard I/O file descriptors before forking. */
+  fflush (stdin);
+  fflush (stdout);
+  fflush (stderr);
+  switch (fork())
+    {
+    case -1:  	
+      perror("netperf server error");
+      exit(1);
+      
+    case 0:	
+      /* Redirect stdin from "/dev/null". */
+      rd_null_fp = fopen ("/dev/null", "r");
+      if (rd_null_fp == NULL)
+      {
+	perror ("netserver: opening for reading: /dev/null");
+	exit   (1);
+      }
+      if (close (STDIN_FILENO) == -1)
+      {
+	perror ("netserver: closing stdin file descriptor");
+	exit   (1);
+      }
+      if (dup (fileno (rd_null_fp)) == -1)
+      {
+	perror ("netserver: duplicate /dev/null read file descr. to stdin");
+	exit   (1);
+      }
+
+      /* Redirect stdout to the debug write file descriptor. */
+      if (close (STDOUT_FILENO) == -1)
+      {
+	perror ("netserver: closing stdout file descriptor");
+	exit   (1);
+      }
+      if (dup (fileno (where))  == -1)
+      {
+	perror ("netserver: duplicate the debug write file descr. to stdout");
+	exit   (1);
+      }
+
+      /* Redirect stderr to "/dev/null". */
+      wr_null_fp = fopen ("/dev/null", "w");
+      if (wr_null_fp == NULL)
+      {
+	perror ("netserver: opening for writing: /dev/null");
+	exit   (1);
+      }
+      if (close (STDERR_FILENO) == -1)
+      {
+	perror ("netserver: closing stderr file descriptor");
+	exit   (1);
+      }
+      if (dup (fileno (wr_null_fp))  == -1)
+      {
+	perror ("netserver: dupicate /dev/null write file descr. to stderr");
+	exit   (1);
+      }
+ 
+#ifndef NO_SETSID
+      setsid();
+#else
+      setpgrp();
+#endif /* NO_SETSID */
+
+ /* some OS's have SIGCLD defined as SIGCHLD */
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif /* SIGCLD */
+
+      signal(SIGCLD, SIG_IGN);
+      
+#endif /* !WIN32 !MPE !__VMS */
+
+      for (;;)
+	{
+	  if ((server_sock=accept(server_control,
+				  (struct sockaddr *)&peeraddr,
+				  &peeraddr_len)) == INVALID_SOCKET)
+	    {
+	      printf("server_control: accept failed errno %d\n",errno);
+	      exit(1);
+	    }
+#if defined(MPE) || defined(__VMS)
+	  /*
+	   * Since we cannot fork this process , we cant fire any threads
+	   * as they all share the same global data . So we better allow
+	   * one request at at time 
+	   */
+	  process_requests() ;
+#elif WIN32
+		{
+			BOOL b;
+			char cmdline[80];
+			PROCESS_INFORMATION pi;
+			STARTUPINFO si;
+			int i;
+
+			memset(&si, 0 , sizeof(STARTUPINFO));
+			si.cb = sizeof(STARTUPINFO);
+
+			/* Pass the server_sock as stdin for the new process. */
+			/* Hopefully this will continue to be created with the OBJ_INHERIT attribute. */
+			si.hStdInput = (HANDLE)server_sock;
+			si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+			si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+			si.dwFlags = STARTF_USESTDHANDLES;
+
+			/* Build cmdline for child process */
+			strcpy(cmdline, program);
+			if (verbosity > 1) {
+				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -v %d", verbosity);
+			}
+			for (i=0; i < debug; i++) {
+				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -d");
+			}
+			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -I %x", (int)(UINT_PTR)server_sock);
+			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)server_control);
+			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)where);
+
+			b = CreateProcess(NULL,	 /* Application Name */
+					cmdline,
+					NULL,    /* Process security attributes */
+					NULL,    /* Thread security attributes */
+					TRUE,    /* Inherit handles */
+					0,	   /* Creation flags  PROCESS_QUERY_INFORMATION,  */
+					NULL,    /* Enviornment */
+					NULL,    /* Current directory */
+					&si,	   /* StartupInfo */
+					&pi);
+			if (!b)
+			{
+				perror("CreateProcessfailure: ");
+				exit(1);
+			}
+
+			/* We don't need the thread or process handles any more; let them */
+			/* go away on their own timeframe. */
+
+			CloseHandle(pi.hThread);
+			CloseHandle(pi.hProcess);
+
+			/* And close the server_sock since the child will own it. */
+
+			close(server_sock);
+		}
+#else
+      signal(SIGCLD, SIG_IGN);
+	  
+	  switch (fork())
+	    {
+	    case -1:
+	      /* something went wrong */
+	      exit(1);
+	    case 0:
+	      /* we are the child process */
+	      close(server_control);
+	      process_requests();
+	      exit(0);
+	      break;
+	    default:
+	      /* we are the parent process */
+	      close(server_sock);
+	      /* we should try to "reap" some of our children. on some */
+	      /* systems they are being left as defunct processes. we */
+	      /* will call waitpid, looking for any child process, */
+	      /* with the WNOHANG feature. when waitpid return a zero, */
+	      /* we have reaped all the children there are to reap at */
+	      /* the moment, so it is time to move on. raj 12/94 */
+#ifndef DONT_WAIT
+#ifdef NO_SETSID
+	      /* Only call "waitpid()" if "setsid()" is not used. */
+	      while(waitpid(-1, NULL, WNOHANG) > 0) { }
+#endif /* NO_SETSID */
+#endif /* DONT_WAIT */
+	      break;
+	    }
+#endif /* !WIN32 !MPE !__VMS */  
+	} /*for*/
+#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
+      break; /*case 0*/
+      
+    default: 
+      exit (0);
+      
+    }
+#endif /* !WIN32 !MPE !__VMS */  
+}
+
+#ifdef WIN32
+
+  /* With Win2003, WinNT's POSIX subsystem is gone and hence so is */
+  /* fork. */
+
+  /* But hopefully the kernel support will continue to exist for some */
+  /* time. */
+
+  /* We are not counting on the child address space copy_on_write */
+  /* support, since it isn't exposed except through the NT native APIs */
+  /* (which is not public). */
+
+  /* We will try to use the InheritHandles flag in CreateProcess.  It */
+  /* is in the public API, though it is documented as "must be FALSE". */
+
+  /* So where we would have forked, we will now create a new process. */
+  /* I have added a set of command line switches to specify a list of */
+  /* handles that the child should close since they shouldn't have */
+  /* been inherited ("-i#"), and a single switch to specify the handle */
+  /* for the server_sock ("I#"). */
+
+  /* A better alternative would be to re-write NetPerf to be */
+  /* multi-threaded; i.e., move all of the various NetPerf global */
+  /* variables in to thread specific structures.  But this is a bigger */
+  /* effort than I want to tackle at this time.  (And I doubt that the */
+  /* HP-UX author sees value in this effort). */
+
+#endif
+
+int _cdecl
+main(int argc, char *argv[])
+{
+
+  int	c;
+  int   not_inetd = 0;
+#ifdef WIN32
+  BOOL  child = FALSE;
+#endif
+  char arg1[BUFSIZ], arg2[BUFSIZ];
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+  char FileName[PATH_MAX];   /* for opening the debug log file */
+
+  struct sockaddr name;
+  netperf_socklen_t namelen = sizeof(name);
+  
+
+#ifdef WIN32
+	WSADATA	wsa_data ;
+
+	/* Initialize the winsock lib ( version 2.2 ) */
+	if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){
+		printf("WSAStartup() failed : %d\n", GetLastError()) ;
+		return 1 ;
+	}
+#endif /* WIN32 */
+
+	/* Save away the program name */
+	program = (char *)malloc(strlen(argv[0]) + 1);
+	if (program == NULL) {
+		printf("malloc(%d) failed!\n", strlen(argv[0]) + 1);
+		return 1 ;
+	}
+	strcpy(program, argv[0]);
+
+  netlib_init();
+  
+  /* Scan the command line to see if we are supposed to set-up our own */
+  /* listen socket instead of relying on inetd. */
+
+  /* first set a copy of initial values */
+  strncpy(local_host_name,"0.0.0.0",sizeof(local_host_name));
+  local_address_family = AF_UNSPEC;
+  strncpy(listen_port,TEST_PORT,sizeof(listen_port));
+
+  while ((c = getopt(argc, argv, SERVER_ARGS)) != EOF) {
+    switch (c) {
+    case '?':
+    case 'h':
+      print_netserver_usage();
+      exit(1);
+    case 'd':
+      /* we want to set the debug file name sometime */
+      debug++;
+      break;
+    case 'L':
+      not_inetd = 1;
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	strncpy(local_host_name,arg1,sizeof(local_host_name));
+      }
+      if (arg2[0]) {
+	local_address_family = parse_address_family(arg2);
+	/* if only the address family was set, we may need to set the
+	   local_host_name accordingly. since our defaults are IPv4
+	   this should only be necessary if we have IPv6 support raj
+	   2005-02-07 */  
+#if defined (AF_INET6)
+	if (!arg1[0]) {
+	  strncpy(local_host_name,"::0",sizeof(local_host_name));
+	}
+#endif
+      }
+      break;
+    case 'n':
+      shell_num_cpus = atoi(optarg);
+      if (shell_num_cpus > MAXCPUS) {
+	fprintf(stderr,
+		"netserver: This version can only support %d CPUs. Please",
+		MAXCPUS);
+	fprintf(stderr,
+		"           increase MAXCPUS in netlib.h and recompile.\n");
+	fflush(stderr);
+	exit(1);
+      }
+      break;
+    case 'p':
+      /* we want to open a listen socket at a */
+      /* specified port number */
+      strncpy(listen_port,optarg,sizeof(listen_port));
+      not_inetd = 1;
+      break;
+    case '4':
+      local_address_family = AF_INET;
+      break;
+    case '6':
+#if defined(AF_INET6)
+      local_address_family = AF_INET6;
+      strncpy(local_host_name,"::0",sizeof(local_host_name));
+#else
+      local_address_family = AF_UNSPEC;
+#endif
+      break;
+    case 'v':
+      /* say how much to say */
+      verbosity = atoi(optarg);
+      break;
+    case 'V':
+      printf("Netperf version %s\n",NETPERF_VERSION);
+      exit(0);
+      break;
+#ifdef WIN32
+/*+*+SAF */
+	case 'I':
+		child = TRUE;
+		/* This is the handle we expect to inherit. */
+		/*+*+SAF server_sock = (HANDLE)atoi(optarg); */
+		break;
+	case 'i':
+		/* This is a handle we should NOT inherit. */
+		/*+*+SAF CloseHandle((HANDLE)atoi(optarg)); */
+		break;
+#endif
+
+    }
+  }
+
+  /* +*+SAF I need a better way to find inherited handles I should close! */
+  /* +*+SAF Use DuplicateHandle to force inheritable attribute (or reset it)? */
+
+/*  unlink(DEBUG_LOG_FILE); */
+
+  strcpy(FileName, DEBUG_LOG_FILE);
+    
+#ifndef WIN32
+  snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%d", getpid());
+  if ((where = fopen(FileName, "w")) == NULL) {
+    perror("netserver: debug file");
+    exit(1);
+  }
+#else
+  {
+    
+    if (child) {
+      snprintf(&FileName[strlen(FileName)], sizeof(FileName) - strlen(FileName), "_%x", getpid());
+    }
+    
+    /* Hopefully, by closing stdout & stderr, the subsequent
+       fopen calls will get mapped to the correct std handles. */
+    fclose(stdout);
+    
+    if ((where = fopen(FileName, "w")) == NULL) {
+      perror("netserver: fopen of debug file as new stdout failed!");
+      exit(1);
+    }
+    
+    fclose(stderr);
+    
+    if ((where = fopen(FileName, "w")) == NULL) {
+      fprintf(stdout, "fopen of debug file as new stderr failed!\n");
+      exit(1);
+    }
+  }
+#endif
+ 
+#ifndef WIN32 
+  chmod(DEBUG_LOG_FILE,0644);
+#endif
+  
+#if WIN32
+  if (child) {
+	  server_sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE);
+  }
+#endif
+
+  /* if we are not a child of an inetd or the like, then we should
+   open a socket and hang listens off of it. otherwise, we should go
+   straight into processing requests. the do_listen() routine will sit
+   in an infinite loop accepting connections and forking child
+   processes. the child processes will call process_requests */
+  
+  /* If fd 0 is not a socket then assume we're not being called */
+  /* from inetd and start server socket on the default port. */
+  /* this enhancement comes from vwelch@ncsa.uiuc.edu (Von Welch) */
+  if (not_inetd) {
+    /* the user specified a port number on the command line */
+    set_up_server(local_host_name,listen_port,local_address_family);
+  }
+#ifdef WIN32
+  /* OK, with Win2003 WinNT's POSIX subsystem is gone, and hence so is */
+  /* fork.  But hopefully the kernel support will continue to exist */
+  /* for some time.  We are not counting on the address space */
+  /* copy_on_write support, since it isn't exposed except through the */
+  /* NT native APIs (which are not public).  We will try to use the */
+  /* InheritHandles flag in CreateProcess though since this is public */
+  /* and is used for more than just POSIX so hopefully it won't go */
+  /* away. */
+  else if (TRUE) {
+    if (child) {
+      process_requests();
+    } else {
+      strncpy(listen_port,TEST_PORT,sizeof(listen_port));
+      set_up_server(local_host_name,listen_port,local_address_family);
+    }
+  }
+#endif
+#if !defined(__VMS)
+  else if (getsockname(0, &name, &namelen) == SOCKET_ERROR) {
+    /* we may not be a child of inetd */
+    if (errno == ENOTSOCK) {
+      strncpy(listen_port,TEST_PORT,sizeof(listen_port));
+      set_up_server(local_host_name,listen_port,local_address_family);
+    }
+  }
+#endif /* !defined(__VMS) */
+  else {
+    /* we are probably a child of inetd, or are being invoked via the
+       VMS auxilliarly server mechanism */
+#if !defined(__VMS)
+    server_sock = 0;
+#else
+    if ( (server_sock = socket(TCPIP$C_AUXS, SOCK_STREAM, 0)) == INVALID_SOCKET ) 
+    { 
+      perror("Failed to grab aux server socket" ); 
+      exit(1); 
+    } 
+  
+#endif /* !defined(__VMS) */
+    process_requests();
+  }
+#ifdef WIN32
+	/* Cleanup the winsock lib */
+	WSACleanup();
+#endif
+
+  return(0);
+}
diff --git a/netsh.c b/netsh.c
new file mode 100644
index 0000000..7659679
--- /dev/null
+++ b/netsh.c
@@ -0,0 +1,1002 @@
+#include "netperf_version.h"
+
+char	netsh_id[]="\
+@(#)netsh.c (c) Copyright 1993-2007 Hewlett-Packard Company. Version 2.4.3pre";
+
+
+/****************************************************************/
+/*								*/
+/*	Global include files					*/
+/*								*/
+/****************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifndef WIN32
+#include <unistd.h>
+#ifndef __VMS
+#include <sys/ipc.h>
+#endif /* __VMS */
+#endif /* WIN32 */
+#include <fcntl.h>
+#ifndef WIN32
+#include <errno.h>
+#include <signal.h>
+#endif  /* !WIN32 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+ /* the following four includes should not be needed ?*/
+#ifndef WIN32
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#else
+#include <time.h>
+#include <winsock2.h>
+#define netperf_socklen_t socklen_t
+#endif
+
+#ifndef STRINGS
+#include <string.h>
+#else /* STRINGS */
+#include <strings.h>
+#endif /* STRINGS */
+
+#ifdef WIN32
+extern	int	getopt(int , char **, char *) ;
+#else
+double atof(const char *);
+#endif /* WIN32 */
+
+/**********************************************************************/
+/*                                                                    */
+/*          Local Include Files                                       */
+/*                                                                    */
+/**********************************************************************/
+
+#define  NETSH
+#include "netsh.h"
+#include "netlib.h"
+#include "nettest_bsd.h"
+
+#ifdef WANT_UNIX
+#include "nettest_unix.h"
+#ifndef WIN32
+#include "sys/socket.h"
+#endif  /* !WIN32 */
+#endif /* WANT_UNIX */
+
+#ifdef WANT_XTI
+#include "nettest_xti.h"
+#endif /* WANT_XTI */
+
+#ifdef WANT_DLPI
+#include "nettest_dlpi.h"
+#endif /* WANT_DLPI */
+
+#ifdef WANT_SCTP
+#include "nettest_sctp.h"
+#endif
+
+
+/************************************************************************/
+/*									*/
+/*	Global constants  and macros					*/
+/*									*/
+/************************************************************************/
+
+ /* Some of the args take optional parameters. Since we are using */
+ /* getopt to parse the command line, we will tell getopt that they do */
+ /* not take parms, and then look for them ourselves */
+#define GLOBAL_CMD_LINE_ARGS "A:a:b:B:CcdDf:F:H:hi:I:k:K:l:L:n:NO:o:P:p:rt:T:v:VW:w:46"
+
+/************************************************************************/
+/*									*/
+/*	Extern variables 						*/
+/*									*/
+/************************************************************************/
+
+/*
+extern int errno;
+extern char *sys_errlist[ ];
+extern int sys_nerr;
+*/
+
+/************************************************************************/
+/*									*/
+/*	Global variables 						*/
+/*									*/
+/************************************************************************/
+
+/* some names and such                                                  */
+char	*program;		/* program invocation name		*/
+char	username[BUFSIZ];	/* login name of user			*/
+char	cmd_file[BUFSIZ];	/* name of the commands file		*/
+
+/* stuff to say where this test is going                                */
+char	host_name[HOSTNAMESIZE];	/* remote host name or ip addr  */
+char    local_host_name[HOSTNAMESIZE];  /* local hostname or ip */
+char    test_name[BUFSIZ];		/* which test to run 		*/
+char	test_port[PORTBUFSIZE];		/* where is the test waiting    */
+char    local_test_port[PORTBUFSIZE];   /* from whence we should start */
+int     address_family;                 /* which address family remote */
+int     local_address_family;           /* which address family local */
+
+/* the source of data for filling the buffers */
+char    fill_file[BUFSIZ];
+
+/* output controlling variables                                         */
+int
+  debug,			/* debugging level */
+  print_headers,		/* do/don't display headers */
+  verbosity;		/* verbosity level */
+
+/* When specified with -B, this will be displayed at the end of the line
+   for output that does not include the test header.  mostly this is
+   to help identify a specific netperf result when concurrent netperfs
+   are run. raj 2006-02-01 */
+char *result_brand = NULL;
+
+/* cpu variables */
+int
+  local_cpu_usage,	/* you guessed it			*/
+  remote_cpu_usage;	/* still right !			*/
+
+float			       
+  local_cpu_rate,
+  remote_cpu_rate;
+
+int
+  shell_num_cpus=1;
+
+/* the end-test conditions for the tests - either transactions, bytes,  */
+/* or time. different vars used for clarity - space is cheap ;-)        */
+int	
+  test_time,		/* test ends by time			*/
+  test_len_ticks,       /* how many times will the timer go off before */
+			/* the test is over? */
+  test_bytes,		/* test ends on byte count		*/
+  test_trans;		/* test ends on tran count		*/
+
+/* the alignment conditions for the tests				*/
+int
+  local_recv_align,	/* alignment for local receives		*/
+  local_send_align,	/* alignment for local sends		*/
+  local_send_offset = 0,
+  local_recv_offset = 0,
+  remote_recv_align,	/* alignment for remote receives	*/
+  remote_send_align,	/* alignment for remote sends		*/
+  remote_send_offset = 0,
+  remote_recv_offset = 0;
+
+#if defined(WANT_INTERVALS) || defined(WANT_DEMO)
+int
+  interval_usecs,
+  interval_wate,
+  interval_burst;
+
+int demo_mode;                    /* are we actually in demo mode? */
+double demo_interval = 1000000.0; /* what is the desired interval to
+				     display interval results. default
+				     is one second in units of
+				     microseconds */
+double demo_units = 0.0;          /* what is our current best guess as
+				     to how many work units must be
+				     done to be near the desired
+				     reporting interval? */ 
+
+double units_this_tick;
+#endif
+
+#ifdef DIRTY
+int	loc_dirty_count;
+int	loc_clean_count;
+int	rem_dirty_count;
+int	rem_clean_count;
+#endif /* DIRTY */
+
+ /* some of the vairables for confidence intervals... */
+
+int  confidence_level;
+int  iteration_min;
+int  iteration_max;
+int  result_confidence_only = 0;
+
+double interval;
+
+ /* stuff to control the "width" of the buffer rings for sending and */
+ /* receiving data */
+int	send_width;
+int     recv_width;
+
+/* address family */
+int	af = AF_INET;
+
+/* did someone request processor affinity? */
+int cpu_binding_requested = 0;
+
+/* are we not establishing a control connection? */
+int no_control = 0;
+
+char netserver_usage[] = "\n\
+Usage: netserver [options] \n\
+\n\
+Options:\n\
+    -h                Display this text\n\
+    -d                Increase debugging output\n\
+    -L name,family    Use name to pick listen address and family for family\n\
+    -p portnum        Listen for connect requests on portnum.\n\
+    -4                Do IPv4\n\
+    -6                Do IPv6\n\
+    -v verbosity      Specify the verbosity level\n\
+    -V                Display version information and exit\n\
+\n";
+
+/* netperf_usage done as two concatenated strings to make the MS
+   compiler happy when compiling for x86_32.  fix from Spencer
+   Frink.  */
+
+char netperf_usage1[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+Global options:\n\
+    -a send,recv      Set the local send,recv buffer alignment\n\
+    -A send,recv      Set the remote send,recv buffer alignment\n\
+    -B brandstr       Specify a string to be emitted with brief output\n\
+    -c [cpu_rate]     Report local CPU usage\n\
+    -C [cpu_rate]     Report remote CPU usage\n\
+    -d                Increase debugging output\n\
+    -D [secs,units] * Display interim results at least every secs seconds\n\
+                      using units as the initial guess for units per second\n\
+    -f G|M|K|g|m|k    Set the output units\n\
+    -F fill_file      Pre-fill buffers with data from fill_file\n\
+    -h                Display this text\n\
+    -H name|ip,fam *  Specify the target machine and/or local ip and family\n\
+    -i max,min        Specify the max and min number of iterations (15,1)\n\
+    -I lvl[,intvl]    Specify confidence level (95 or 99) (99) \n\
+                      and confidence interval in percentage (10)\n\
+    -l testlen        Specify test duration (>0 secs) (<0 bytes|trans)\n\
+    -L name|ip,fam *  Specify the local ip|name and address family\n\
+    -o send,recv      Set the local send,recv buffer offsets\n\
+    -O send,recv      Set the remote send,recv buffer offset\n\
+    -n numcpu         Set the number of processors for CPU util\n\
+    -N                Establish no control connection, do 'send' side only\n\
+    -p port,lport*    Specify netserver port number and/or local port\n\
+    -P 0|1            Don't/Do display test headers\n\
+    -r                Allow confidence to be hit on result only\n\
+    -t testname       Specify test to perform\n\
+    -T lcpu,rcpu      Request netperf/netserver be bound to local/remote cpu\n\
+    -v verbosity      Specify the verbosity level\n\
+    -W send,recv      Set the number of send,recv buffers\n\
+    -v level          Set the verbosity level (default 1, min 0)\n\
+    -V                Display the netperf version and exit\n";
+
+char netperf_usage2[] = "\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\
+\n"
+"* For these options taking two parms, specifying one value with no comma\n\
+will only set the first parms and will leave the second at the default\n\
+value. To set the second value it must be preceded with a comma or be a\n\
+comma-separated pair. This is to retain previous netperf behaviour.\n"; 
+
+
+/* This routine will return the two arguments to the calling routine. */
+/* If the second argument is not specified, and there is no comma, */
+/* then the value of the second argument will be the same as the */
+/* value of the first. If there is a comma, then the value of the */
+/* second argument will be the value of the second argument ;-) */
+void
+break_args(char *s, char *arg1, char *arg2)
+
+{
+  char *ns;
+  ns = strchr(s,',');
+  if (ns) {
+    /* there was a comma arg2 should be the second arg*/
+    *ns++ = '\0';
+    while ((*arg2++ = *ns++) != '\0');
+  }
+  else {
+    /* there was not a comma, we can use ns as a temp s */
+    /* and arg2 should be the same value as arg1 */
+    ns = s;
+    while ((*arg2++ = *ns++) != '\0');
+  };
+  while ((*arg1++ = *s++) != '\0');
+}
+
+/* break_args_explicit
+
+   this routine is somewhat like break_args in that it will separate a
+   pair of comma-separated values.  however, if there is no comma,
+   this version will not ass-u-me that arg2 should be the same as
+   arg1. raj 2005-02-04 */
+void
+break_args_explicit(char *s, char *arg1, char *arg2)
+
+{
+  char *ns;
+  ns = strchr(s,',');
+  if (ns) {
+    /* there was a comma arg2 should be the second arg*/
+    *ns++ = '\0';
+    while ((*arg2++ = *ns++) != '\0');
+  }
+  else {
+    /* there was not a comma, so we should make sure that arg2 is \0
+       lest something become confused. raj 2005-02-04 */
+    *arg2 = '\0';
+  };
+  while ((*arg1++ = *s++) != '\0');
+
+}
+
+/* given a string with possible values for setting an address family,
+   convert that into one of the AF_mumble values - AF_INET, AF_INET6,
+   AF_UNSPEC as apropriate. the family_string is compared in a
+   case-insensitive manner */
+
+int
+parse_address_family(char family_string[])
+{
+
+  char temp[10];  /* gotta love magic constants :) */
+
+  strncpy(temp,family_string,10);
+
+  if (debug) {
+    fprintf(where,
+	    "Attempting to parse address family from %s derived from %s\n",
+	    temp,
+	    family_string);
+  }
+#if defined(AF_INET6)
+  if (strstr(temp,"6")) {
+    return(AF_INET6);
+  }
+#endif
+  if (strstr(temp,"inet") ||
+      strstr(temp,"4")) {
+    return(AF_INET);
+  }
+  if (strstr(temp,"unspec") ||
+      strstr(temp,"0")) {
+    return(AF_UNSPEC);
+  }
+  fprintf(where,
+	  "WARNING! %s not recognized as an address family, using AF_UNPSEC\n",
+	  family_string);
+  fprintf(where,
+	  "Are you sure netperf was configured for that address family?\n");
+  fflush(where);
+  return(AF_UNSPEC);
+}
+
+
+void
+set_defaults()
+{
+  
+  /* stuff to say where this test is going                              */
+  strcpy(host_name,"");	      /* remote host name or ip addr  */
+  strcpy(local_host_name,""); /* we want it to be INADDR_ANY */
+  strcpy(test_name,"TCP_STREAM");	/* which test to run 		*/
+  strncpy(test_port,"12865",PORTBUFSIZE); /* where is the test waiting    */
+  strncpy(local_test_port,"0",PORTBUFSIZE);/* INPORT_ANY as it were */
+  address_family = AF_UNSPEC;
+  local_address_family = AF_UNSPEC;
+
+  /* output controlling variables                               */
+  debug			= 0;/* debugging level			*/
+  print_headers		= 1;/* do print test headers		*/
+  verbosity		= 1;/* verbosity level			*/
+  /* cpu variables */
+  local_cpu_usage	= 0;/* measure local cpu		*/
+  remote_cpu_usage	= 0;/* what do you think ;-)		*/
+  
+  local_cpu_rate	= (float)0.0;
+  remote_cpu_rate	= (float)0.0;
+  
+  /* the end-test conditions for the tests - either transactions, bytes,  */
+  /* or time. different vars used for clarity - space is cheap ;-)        */
+  test_time	= 10;	/* test ends by time			*/
+  test_bytes	= 0;	/* test ends on byte count		*/
+  test_trans	= 0;	/* test ends on tran count		*/
+  
+  /* the alignment conditions for the tests				*/
+  local_recv_align	= 8;	/* alignment for local receives	*/
+  local_send_align	= 8;	/* alignment for local sends	*/
+  remote_recv_align	= 8;	/* alignment for remote receives*/
+  remote_send_align	= 8;	/* alignment for remote sends	*/
+  
+#ifdef WANT_INTERVALS
+  /* rate controlling stuff */
+  interval_usecs  = 0;
+  interval_wate   = 1;
+  interval_burst  = 0;
+#endif /* WANT_INTERVALS */
+  
+#ifdef DIRTY
+  /* dirty and clean cache stuff */
+  loc_dirty_count = 0;
+  loc_clean_count = 0;
+  rem_dirty_count = 0;
+  rem_clean_count = 0;
+#endif /* DIRTY */
+
+ /* some of the vairables for confidence intervals... */
+
+  confidence_level = 99;
+  iteration_min = 1;
+  iteration_max = 1;
+  interval = 0.05; /* five percent? */
+
+  no_control = 0;
+  strcpy(fill_file,"");
+}
+     
+
+void
+print_netserver_usage()
+{
+  fwrite(netserver_usage, sizeof(char), strlen(netserver_usage), stderr);
+}
+
+
+void
+print_netperf_usage()
+{
+  fwrite(netperf_usage1, sizeof(char), strlen(netperf_usage1),  stderr);
+  fwrite(netperf_usage2, sizeof(char), strlen(netperf_usage2),  stderr);
+}
+
+void
+scan_cmd_line(int argc, char *argv[])
+{
+  extern int	optind;           /* index of first unused arg 	*/
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+  
+  program = (char *)malloc(strlen(argv[0]) + 1);
+  if (program == NULL) {
+    printf("malloc(%d) failed!\n", strlen(argv[0]) + 1);
+    exit(1);
+  }
+  strcpy(program, argv[0]);
+  
+  /* 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, GLOBAL_CMD_LINE_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case 'h':
+      print_netperf_usage();
+      exit(1);
+    case 'a':
+      /* set local alignments */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	local_send_align = convert(arg1);
+      }
+      if (arg2[0])
+	local_recv_align = convert(arg2);
+      break;
+    case 'A':
+      /* set remote alignments */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	remote_send_align = convert(arg1);
+      }
+      if (arg2[0])
+	remote_recv_align = convert(arg2);
+      break;
+    case 'c':
+      /* measure local cpu usage please. the user */
+      /* may have specified the cpu rate as an */
+      /* optional parm */
+      if (argv[optind] && isdigit((unsigned char)argv[optind][0])){
+	/* there was an optional parm */
+	local_cpu_rate = (float)atof(argv[optind]);
+	optind++;
+      }
+      local_cpu_usage++;
+      break;
+    case 'C':
+      /* measure remote cpu usage please */
+      if (argv[optind] && isdigit((unsigned char)argv[optind][0])){
+	/* there was an optional parm */
+	remote_cpu_rate = (float)atof(argv[optind]);
+	optind++;
+      }
+      remote_cpu_usage++;
+      break;
+    case 'd':
+      debug++;
+      break;
+    case 'D':
+#if (defined WANT_DEMO)
+      demo_mode++;
+      if (argv[optind] && isdigit((unsigned char)argv[optind][0])){
+	/* there was an optional parm */
+	break_args_explicit(argv[optind],arg1,arg2);
+	optind++;
+	if (arg1[0]) {
+	  demo_interval = atof(arg1) * 1000000.0;
+	}
+	if (arg2[0]) {
+	  demo_units = convert(arg2);
+	}
+      }
+#else 
+      printf("Sorry, Demo Mode not configured into this netperf.\n");
+      printf("please consider reconfiguring netperf with\n");
+      printf("--enable-demo=yes and recompiling\n");
+#endif 
+      break;
+    case 'f':
+      /* set the thruput formatting */
+      libfmt = *optarg;
+      break;
+    case 'F':
+      /* set the fill_file variable for pre-filling buffers */
+      strcpy(fill_file,optarg);
+      break;
+    case 'i':
+      /* set the iterations min and max for confidence intervals */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	iteration_max = convert(arg1);
+      }
+      if (arg2[0] ) {
+	iteration_min = convert(arg2);
+      }
+      /* if the iteration_max is < iteration_min make iteration_max
+	 equal iteration_min */
+      if (iteration_max < iteration_min) iteration_max = iteration_min;
+      /* limit minimum to 3 iterations */
+      if (iteration_max < 3) iteration_max = 3;
+      if (iteration_min < 3) iteration_min = 3;
+      /* limit maximum to 30 iterations */
+      if (iteration_max > 30) iteration_max = 30;
+      if (iteration_min > 30) iteration_min = 30;
+      break;
+    case 'I':
+      /* set the confidence level (95 or 99) and width */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	confidence_level = convert(arg1);
+      }
+      if((confidence_level != 95) && (confidence_level != 99)){
+	printf("Only 95%% and 99%% confidence level is supported\n");
+	exit(1);
+      }
+      if (arg2[0] ) {
+	interval = (double) convert(arg2)/100;
+      }
+      /* make sure that iteration_min and iteration_max are at least
+	 at a reasonable default value.  if a -i option has previously
+	 been parsed, these will no longer be 1, so we can check
+	 against 1 */ 
+      if (iteration_min == 1) iteration_min = 3;
+      if (iteration_max == 1) iteration_max = 10;
+
+      break;
+    case 'k':
+      /* local dirty and clean counts */
+#ifdef DIRTY
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	loc_dirty_count = convert(arg1);
+      }
+      if (arg2[0] ) {
+	loc_clean_count = convert(arg2);
+      }
+#else
+      printf("I don't know how to get dirty.\n");
+#endif /* DIRTY */
+      break;
+    case 'K':
+      /* remote dirty and clean counts */
+#ifdef DIRTY
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	rem_dirty_count = convert(arg1);
+      }
+      if (arg2[0] ) {
+	rem_clean_count = convert(arg2);
+      }
+#else
+      printf("I don't know how to get dirty.\n");
+#endif /* DIRTY */
+      break;
+    case 'n':
+      shell_num_cpus = atoi(optarg);
+      break;
+    case 'N':
+      no_control = 1;
+      break;
+    case 'o':
+      /* set the local offsets */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	local_send_offset = convert(arg1);
+      if (arg2[0])
+	local_recv_offset = convert(arg2);
+      break;
+    case 'O':
+      /* set the remote offsets */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) 
+	remote_send_offset = convert(arg1);
+      if (arg2[0])
+	remote_recv_offset = convert(arg2);
+      break;
+    case 'P':
+      /* to print or not to print, that is */
+      /* the header question */
+      print_headers = convert(optarg);
+      break;
+    case 'r':
+      /* the user wishes that we declare confidence when hit on the
+	 result even if not yet reached on CPU utilization.  only
+	 meaningful if cpu util is enabled */
+      result_confidence_only = 1;
+      break;
+    case 't':
+      /* set the test name */
+      strcpy(test_name,optarg);
+      break;
+    case 'T':
+      /* We want to set the processor on which netserver or netperf */
+      /* will run */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) {
+	local_proc_affinity = convert(arg1);
+	bind_to_specific_processor(local_proc_affinity,0);
+      }
+      if (arg2[0]) {
+	remote_proc_affinity = convert(arg2);
+      }
+      cpu_binding_requested = 1;
+      break;
+    case 'W':
+      /* set the "width" of the user space data buffer ring. This will */
+      /* be the number of send_size buffers malloc'd in the tests */  
+      break_args(optarg,arg1,arg2);
+      if (arg1[0]) 
+	send_width = convert(arg1);
+      if (arg2[0])
+	recv_width = convert(arg2);
+      break;
+    case 'l':
+      /* determine test end conditions */
+      /* assume a timed test */
+      test_time = convert(optarg);
+      test_bytes = test_trans = 0;
+      if (test_time < 0) {
+	test_bytes = -1 * test_time;
+	test_trans = test_bytes;
+	test_time = 0;
+      }
+      break;
+    case 'v':
+      /* say how much to say */
+      verbosity = convert(optarg);
+      break;
+    case 'p':
+      /* specify an alternate port number we use break_args_explicit
+	 here to maintain backwards compatibility with previous
+	 generations of netperf where having a single value did not
+	 set both remote _and_ local port number. raj 2005-02-04 */
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(test_port,arg1,PORTBUFSIZE);
+      if (arg2[0])
+	strncpy(local_test_port,arg2,PORTBUFSIZE);
+      break;
+    case 'H':
+      /* save-off the host identifying information, use
+	 break_args_explicit since passing just one value should not
+	 set both */ 
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(host_name,arg1,sizeof(host_name));
+      if (arg2[0])
+	address_family = parse_address_family(arg2);
+      break;
+    case 'L':
+      /* save-off the local control socket addressing information. use
+	 break_args_explicit since passing just one value should not
+	 set both */
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(local_host_name,arg1,sizeof(local_host_name));
+      if (arg2[0])
+	local_address_family = parse_address_family(arg2);
+      break;
+    case 'w':
+      /* We want to send requests at a certain wate. */
+      /* Remember that there are 1000000 usecs in a */
+      /* second, and that the packet rate is */
+      /* expressed in packets per millisecond. */
+#ifdef WANT_INTERVALS
+      interval_usecs = convert_timespec(optarg);
+      interval_wate  = interval_usecs / 1000;
+#else
+      fprintf(where,
+	      "Packet rate control is not compiled in.\n");
+#endif
+      break;
+    case 'b':
+      /* we want to have a burst so many packets per */
+      /* interval. */
+#ifdef WANT_INTERVALS
+      interval_burst = convert(optarg);
+#else
+      fprintf(where,
+	      "Packet burst size is not compiled in. \n");
+#endif /* WANT_INTERVALS */
+      break;
+    case 'B':
+      result_brand = malloc(strlen(optarg)+1);
+      if (NULL != result_brand) {
+	strcpy(result_brand,optarg);
+      }
+      else {
+	fprintf(where,
+		"Unable to malloc space for result brand\n");
+      }
+      break;
+    case '4':
+      address_family = AF_INET;
+      local_address_family = AF_INET;
+      break;
+    case '6':
+#if defined(AF_INET6)
+      address_family = AF_INET6;
+      local_address_family = AF_INET6;
+#else
+      printf("This netperf was not compiled on an IPv6 capable system!\n");
+      exit(-1);
+#endif
+      break;
+    case 'V':
+      printf("Netperf version %s\n",NETPERF_VERSION);
+      exit(0);
+      break;
+    };
+  }
+  /* ok, what should our default hostname and local binding info be?
+   */
+  if ('\0' == host_name[0]) {
+    /* host_name was not set */
+    switch (address_family) {
+    case AF_INET:
+      strcpy(host_name,"localhost");
+      break;
+    case AF_UNSPEC:
+      /* what to do here? case it off the local_address_family I
+	 suppose */
+      switch (local_address_family) {
+      case AF_INET:
+      case AF_UNSPEC:
+	strcpy(host_name,"localhost");
+	break;
+#if defined(AF_INET6)
+      case AF_INET6:
+	strcpy(host_name,"::1");
+	break;
+#endif
+      default:
+	printf("Netperf does not understand %d as an address family\n",
+	       address_family);
+	exit(-1);
+      }
+      break; 
+#if defined(AF_INET6)
+    case AF_INET6:
+      strcpy(host_name,"::1");
+      break;
+#endif
+    default:
+      printf("Netperf does not understand %d as an address family\n",
+	     address_family);
+      exit(-1);
+    }
+  }
+  
+  /* now, having established the name to which the control will
+     connect, from what should it come? */
+  if ('\0' == local_host_name[0]) {
+    switch (local_address_family) {
+    case AF_INET:
+      strcpy(local_host_name,"0.0.0.0");
+      break;
+    case AF_UNSPEC:
+      switch (address_family) {
+      case AF_INET:
+      case AF_UNSPEC:
+	strcpy(local_host_name,"0.0.0.0");
+	break;
+#if defined(AF_INET6)
+      case AF_INET6:
+	strcpy(local_host_name,"::0");
+	break;
+#endif
+      default:
+	printf("Netperf does not understand %d as an address family\n",
+	       address_family);
+	exit(-1);
+      }
+      break;
+#if defined(AF_INET6)
+    case AF_INET6:
+      strcpy(local_host_name,"::0");
+      break;
+#endif
+    default:
+      printf("Netperf does not understand %d as an address family\n",
+	     address_family);
+      exit(-1);
+    }
+  }
+
+  /* so, if we aren't even going to establish a control connection we
+     should set certain "remote" settings to reflect this, regardless
+     of what else may have been set on the command line */
+  if (no_control) {
+    remote_recv_align = -1;
+    remote_send_align = -1;
+    remote_send_offset = -1;
+    remote_recv_offset = -1;
+    remote_cpu_rate = (float)-1.0;
+    remote_cpu_usage = 0;
+  }
+
+  /* parsing test-specific options used to be conditional on there
+    being a "--" in the option stream.  however, some of the tests
+    have other initialization happening in their "scan" routines so we
+    want to call them regardless. raj 2005-02-08 */
+    if ((strcasecmp(test_name,"TCP_STREAM") == 0) ||
+#ifdef HAVE_ICSC_EXS
+    (strcasecmp(test_name,"EXS_TCP_STREAM") == 0) ||
+#endif /* HAVE_ICSC_EXS */ 
+#ifdef HAVE_SENDFILE
+	(strcasecmp(test_name,"TCP_SENDFILE") == 0) ||
+#endif /* HAVE_SENDFILE */
+	(strcasecmp(test_name,"TCP_MAERTS") == 0) ||
+	(strcasecmp(test_name,"TCP_RR") == 0) ||
+	(strcasecmp(test_name,"TCP_CRR") == 0) ||
+	(strcasecmp(test_name,"TCP_CC") == 0) ||
+#ifdef DO_1644
+	(strcasecmp(test_name,"TCP_TRR") == 0) ||
+#endif /* DO_1644 */
+#ifdef DO_NBRR
+	(strcasecmp(test_name,"TCP_TRR") == 0) ||
+#endif /* DO_NBRR */
+	(strcasecmp(test_name,"UDP_STREAM") == 0) ||
+	(strcasecmp(test_name,"UDP_RR") == 0))
+      {
+	scan_sockets_args(argc, argv);
+      }
+
+#ifdef WANT_DLPI
+    else if ((strcasecmp(test_name,"DLCO_RR") == 0) ||
+	     (strcasecmp(test_name,"DLCL_RR") == 0) ||
+	     (strcasecmp(test_name,"DLCO_STREAM") == 0) ||
+	     (strcasecmp(test_name,"DLCL_STREAM") == 0))
+      {
+	scan_dlpi_args(argc, argv);
+      }
+#endif /* WANT_DLPI */
+
+#ifdef WANT_UNIX
+    else if ((strcasecmp(test_name,"STREAM_RR") == 0) ||
+	     (strcasecmp(test_name,"DG_RR") == 0) ||
+	     (strcasecmp(test_name,"STREAM_STREAM") == 0) ||
+	     (strcasecmp(test_name,"DG_STREAM") == 0))
+      {
+	scan_unix_args(argc, argv);
+      }
+#endif /* WANT_UNIX */
+
+#ifdef WANT_XTI
+    else if ((strcasecmp(test_name,"XTI_TCP_RR") == 0) ||
+	     (strcasecmp(test_name,"XTI_TCP_STREAM") == 0) ||
+	     (strcasecmp(test_name,"XTI_UDP_RR") == 0) ||
+	     (strcasecmp(test_name,"XTI_UDP_STREAM") == 0))
+      {
+	scan_xti_args(argc, argv);
+      }
+#endif /* WANT_XTI */
+
+#ifdef WANT_SCTP
+    else if ((strcasecmp(test_name,"SCTP_STREAM") == 0) ||
+	     (strcasecmp(test_name,"SCTP_RR") == 0) ||
+	     (strcasecmp(test_name,"SCTP_STREAM_MANY") == 0) ||
+	     (strcasecmp(test_name,"SCTP_RR_MANY") == 0))
+    {
+      scan_sctp_args(argc, argv);
+    }
+#endif
+
+#ifdef WANT_SDP
+    else if((strcasecmp(test_name,"SDP_STREAM") == 0) ||
+	    (strcasecmp(test_name,"SDP_MAERTS") == 0) ||
+	    (strcasecmp(test_name,"SDP_RR") == 0))
+      {
+	scan_sdp_args(argc, argv);
+      }
+#endif
+    
+    /* what is our default value for the output units?  if the test
+       name contains "RR" or "rr" or "Rr" or "rR" then the default is
+       'x' for transactions. otherwise it is 'm' for megabits
+       (10^6) */
+
+    if ('?' == libfmt) {
+      /* we use a series of strstr's here because not everyone has
+	 strcasestr and I don't feel like up or downshifting text */
+      if ((strstr(test_name,"RR")) ||
+	  (strstr(test_name,"rr")) ||
+	  (strstr(test_name,"Rr")) ||
+	  (strstr(test_name,"rR"))) {
+	libfmt = 'x';
+      }
+      else {
+	libfmt = 'm';
+      }
+    }
+    else if ('x' == libfmt) {
+      /* now, a format of 'x' makes no sense for anything other than
+	 an RR test. if someone has been silly enough to try to set
+	 that, we will reset it silently to default - namely 'm' */
+      if ((strstr(test_name,"RR") == NULL) &&
+	  (strstr(test_name,"rr") == NULL) &&
+	  (strstr(test_name,"Rr") == NULL) &&
+	  (strstr(test_name,"rR") == NULL)) {
+	libfmt = 'm';
+      }
+    }
+}
+
+
+void
+dump_globals()
+{
+  printf("Program name: %s\n", program);
+  printf("Local send alignment: %d\n",local_send_align);
+  printf("Local recv alignment: %d\n",local_recv_align);
+  printf("Remote send alignment: %d\n",remote_send_align);
+  printf("Remote recv alignment: %d\n",remote_recv_align);
+  printf("Report local CPU %d\n",local_cpu_usage);
+  printf("Report remote CPU %d\n",remote_cpu_usage);
+  printf("Verbosity: %d\n",verbosity);
+  printf("Debug: %d\n",debug);
+  printf("Port: %s\n",test_port);
+  printf("Test name: %s\n",test_name);
+  printf("Test bytes: %d Test time: %d Test trans: %d\n",
+	 test_bytes,
+	 test_time,
+	 test_trans);
+  printf("Host name: %s\n",host_name);
+  printf("\n");
+}
diff --git a/netsh.h b/netsh.h
new file mode 100644
index 0000000..e99883b
--- /dev/null
+++ b/netsh.h
@@ -0,0 +1,149 @@
+/*
+        Copyright (C) 1993,1995 Hewlett-Packard Company
+*/
+
+/* libraried performance include file 				*/
+/* the define NOPERFEXTERN tels us not to re-define all the 	*/
+
+/* defines and defaults */
+#define		HOSTNAMESIZE 	255
+#define         PORTBUFSIZE     10
+#define		DEFAULT_SIZE	32768
+#define		HOST_NAME	"127.0.0.1"
+#define		TEST_PORT	"12865"
+
+/* output controlling variables                                         */
+#define 	DEBUG 0		/* debugging level			*/
+#define 	VERBOSITY 0	/* verbosity level			*/
+
+/* the end-test conditions for the tests - either transactions, bytes,  */
+/* or time. different vars used for clarity - space is cheap ;-)        */
+#define 	TEST_TIME 10	/* test ends by time			*/
+#define 	TEST_BYTES 0	/* test ends on byte count		*/
+#define 	TEST_TRANS 0	/* test ends on tran count		*/
+
+/* the alignment conditions for the tests				*/
+#define 	LOC_RECV_ALIGN	4	/* alignment for local receives	*/
+#define 	LOC_SEND_ALIGN	4	/* alignment for local sends	*/
+#define 	REM_RECV_ALIGN	4	/* alignment for remote receive	*/
+#define 	REM_SEND_ALIGN	4	/* alignment for remote sends	*/
+
+/* misc defines for the hell of it					*/
+#ifndef MAXLONG
+#define 	MAXLONG  	4294967295UL
+#endif /* MAXLONG */
+
+#ifndef NETSH
+extern char		*program;		/* program invocation name		*/
+
+/* stuff to say where this test is going                                */
+extern char	host_name[HOSTNAMESIZE];/* remote host name or ip addr  */
+extern char     local_host_name[HOSTNAMESIZE];
+extern char	test_port[PORTBUFSIZE]; /* where is the test waiting    */
+extern char     local_test_port[PORTBUFSIZE];
+extern int      address_family;
+extern int      local_address_family;
+extern int      parse_address_family(char family_string[]);
+extern void     set_defaults();
+extern void     scan_cmd_line(int argc, char *argv[]);
+extern void     dump_globals();
+extern void     break_args(char *s, char *arg1, char *arg2);
+extern void     break_args_explicit(char *s, char *arg1, char *arg2);
+extern void     print_netserver_usage();
+
+/* output controlling variables                                         */
+extern int
+  debug,		/* debugging level			*/
+  print_headers,	/* do/don't print test headers		*/
+  verbosity;		/* verbosity level			*/
+
+/* the end-test conditions for the tests - either transactions, bytes,  */
+/* or time. different vars used for clarity - space is cheap ;-)        */
+extern int	
+  test_time,		/* test ends by time			*/
+  test_len_ticks,
+  test_bytes,		/* test ends on byte count		*/
+  test_trans;		/* test ends on tran count		*/
+
+/* the alignment conditions for the tests				*/
+extern int
+  local_recv_align,	/* alignment for local receives		*/
+  local_send_align,	/* alignment for local sends		*/
+  remote_recv_align,	/* alignment for remote receives	*/
+  remote_send_align,	/* alignment for remote sends		*/
+  local_send_offset,
+  local_recv_offset,
+  remote_send_offset,
+  remote_recv_offset;
+
+#if defined(WANT_INTERVALS) || defined(WANT_DEMO)
+extern	int          interval_usecs;
+extern  int          interval_wate;
+extern	int	     interval_burst;
+
+extern int    demo_mode;
+extern double demo_interval;
+extern double demo_units;
+extern double units_this_tick;
+#endif 
+
+#ifdef DIRTY
+extern int	rem_dirty_count;
+extern int	rem_clean_count;
+extern int	loc_dirty_count;
+extern int	loc_clean_count;
+#endif /* DIRTY */
+
+/* stuff for confidence intervals */
+
+extern int  confidence_level;
+extern int  iteration_min;
+extern int  iteration_max;
+extern int  result_confidence_only;
+extern double interval;
+
+extern int cpu_binding_requested;
+
+/* stuff to controll the bufferspace "width" */
+extern int	send_width;
+extern int      recv_width;
+
+/* address family */
+extern int	af;
+
+/* different options for other things					*/
+extern int
+  local_cpu_usage,
+  remote_cpu_usage;
+
+extern float
+  local_cpu_rate,
+  remote_cpu_rate;
+
+extern int
+  shell_num_cpus;
+
+extern	char	
+  test_name[BUFSIZ];
+
+extern char
+  fill_file[BUFSIZ];
+
+extern char *
+  result_brand;
+
+extern int
+  no_control;
+
+#ifdef WANT_DLPI
+
+extern int
+  loc_ppa,
+  rem_ppa;
+
+extern int
+  dlpi_sap;
+
+#endif /* WANT_DLPI */
+
+#endif
diff --git a/nettest_bsd.c b/nettest_bsd.c
new file mode 100644
index 0000000..27092f3
--- /dev/null
+++ b/nettest_bsd.c
@@ -0,0 +1,12333 @@
+#ifndef lint
+char	nettest_id[]="\
+@(#)nettest_bsd.c (c) Copyright 1993-2004 Hewlett-Packard Co. Version 2.4.3";
+#endif /* lint */
+
+
+/****************************************************************/
+/*								*/
+/*	nettest_bsd.c						*/
+/*								*/
+/*      the BSD sockets parsing routine...                      */
+/*       ...with the addition of Windows NT, this is now also   */
+/*          a Winsock test... sigh :)                           */
+/*                                                              */
+/*      scan_sockets_args()                                     */
+/*                                                              */
+/*	the actual test routines...				*/
+/*								*/
+/*	send_tcp_stream()	perform a tcp stream test	*/
+/*	recv_tcp_stream()					*/
+/*      send_tcp_maerts()       perform a tcp stream test       */
+/*      recv_tcp_maerts()       in the other direction          */
+/*	send_tcp_rr()		perform a tcp request/response	*/
+/*	recv_tcp_rr()						*/
+/*      send_tcp_conn_rr()      an RR test including connect    */
+/*      recv_tcp_conn_rr()                                      */
+/*      send_tcp_cc()           a connect/disconnect test with  */
+/*      recv_tcp_cc()           no RR                           */
+/*	send_udp_stream()	perform a udp stream test	*/
+/*	recv_udp_stream()					*/
+/*	send_udp_rr()		perform a udp request/response	*/
+/*	recv_udp_rr()						*/
+/*	loc_cpu_rate()		determine the local cpu maxrate */
+/*	rem_cpu_rate()		find the remote cpu maxrate	*/
+/*								*/
+/****************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#ifndef WIN32
+#include <errno.h>
+#include <signal.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#endif /* NOSTDLIBH */
+
+#ifndef WIN32
+#if !defined(__VMS)
+#include <sys/ipc.h>
+#endif /* !defined(__VMS) */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#else /* WIN32 */
+#include <process.h>
+#define netperf_socklen_t socklen_t
+#include <winsock2.h>
+
+/* while it is unlikely that anyone running Windows 2000 or NT 4 is
+   going to be trying to compile this, if they are they will want to
+   define DONT_IPV6 in the sources file */
+#ifndef DONT_IPV6
+#include <ws2tcpip.h>
+#endif
+#include <windows.h>
+
+#define sleep(x) Sleep((x)*1000)
+
+#define __func__ __FUNCTION__
+#endif /* WIN32 */
+
+/* We don't want to use bare constants in the shutdown() call.  In the
+   extremely unlikely event that SHUT_WR isn't defined, we will define
+   it to the value we used to be passing to shutdown() anyway.  raj
+   2007-02-08 */
+#if !defined(SHUT_WR)
+#define SHUT_WR 1
+#endif
+
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
+# include "missing/getaddrinfo.h"
+#endif
+
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_bsd.h"
+
+#if defined(WANT_HISTOGRAM) || defined(WANT_DEMO) 
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+
+/* make first_burst_size unconditional so we can use it easily enough
+   when calculating transaction latency for the TCP_RR test. raj
+   2007-06-08 */
+int first_burst_size=0;
+
+#if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun__))
+#include <sys/sendfile.h>
+#endif /* HAVE_SENDFILE && (__linux || __sun__) */
+
+
+
+/* these variables are specific to the BSD sockets tests, but can
+ * be used elsewhere if needed.  They are externed through nettest_bsd.h
+ */
+
+int	
+  rss_size_req = -1,	/* requested remote socket send buffer size */
+  rsr_size_req = -1,	/* requested remote socket recv buffer size */
+  rss_size,		/* remote socket send buffer size	*/
+  rsr_size,		/* remote socket recv buffer size	*/
+  lss_size_req = -1,	/* requested local socket send buffer size */
+  lsr_size_req = -1,	/* requested local 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;
+
+/* these will control the width of port numbers we try to use in the */
+/* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
+static int client_port_min = 5000;
+static int client_port_max = 65535;
+
+ /* different options for the sockets				*/
+
+int
+  loc_nodelay,		/* don't/do use NODELAY	locally		*/
+  rem_nodelay,		/* don't/do use NODELAY remotely	*/
+#ifdef TCP_CORK
+  loc_tcpcork=0,        /* don't/do use TCP_CORK locally        */
+  rem_tcpcork=0,        /* don't/do use TCP_CORK remotely       */
+#endif /* TCP_CORK */
+  loc_sndavoid,		/* avoid send copies locally		*/
+  loc_rcvavoid,		/* avoid recv copies locally		*/
+  rem_sndavoid,		/* avoid send copies remotely		*/
+  rem_rcvavoid, 	/* avoid recv_copies remotely		*/
+  local_connected = 0,  /* local socket type, connected/non-connected */
+  remote_connected = 0; /* remote socket type, connected/non-connected */
+
+#ifdef WANT_HISTOGRAM
+#ifdef HAVE_GETHRTIME
+static hrtime_t time_one;
+static hrtime_t time_two;
+#elif HAVE_GET_HRT
+#include "hrt.h"
+static hrt_t time_one;
+static hrt_t time_two;
+#elif defined(WIN32)
+static LARGE_INTEGER time_one;
+static LARGE_INTEGER time_two;
+#else
+static struct timeval time_one;
+static struct timeval time_two;
+#endif /* HAVE_GETHRTIME */
+static HIST time_hist;
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_INTERVALS
+int interval_count;
+#ifndef WANT_SPIN
+sigset_t signal_set;
+#define INTERVALS_INIT() \
+    if (interval_burst) { \
+      /* zero means that we never pause, so we never should need the \
+         interval timer. we used to use it for demo mode, but we deal \
+	 with that with a variant on watching the clock rather than \
+	 waiting for a timer. raj 2006-02-06 */ \
+      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, \
+	      "%s: unable to get sigmask errno %d\n", \
+	      __func__, \
+	      errno); \
+      fflush(where); \
+      exit(1); \
+    }
+
+#define INTERVALS_WAIT() \
+      /* 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 > 1) { \
+	  fprintf(where,"about to suspend\n"); \
+	  fflush(where); \
+	} \
+	if (sigsuspend(&signal_set) == EFAULT) { \
+	  fprintf(where, \
+		  "%s: fault with sigsuspend.\n", \
+                  __func__); \
+	  fflush(where); \
+	  exit(1); \
+	} \
+	interval_count = interval_burst; \
+      }
+#else
+/* first out timestamp */
+#ifdef HAVE_GETHRTIME
+static hrtime_t intvl_one;
+static hrtime_t intvl_two;
+static hrtime_t *intvl_one_ptr = &intvl_one;
+static hrtime_t *intvl_two_ptr = &intvl_two;
+static hrtime_t *temp_intvl_ptr = &intvl_one;
+#elif defined(WIN32)
+static LARGE_INTEGER intvl_one;
+static LARGE_INTEGER intvl_two;
+static LARGE_INTEGER *intvl_one_ptr = &intvl_one;
+static LARGE_INTEGER *intvl_two_ptr = &intvl_two;
+static LARGE_INTEGER *temp_intvl_ptr = &intvl_one;
+#else
+static struct timeval intvl_one;
+static struct timeval intvl_two;
+static struct timeval *intvl_one_ptr = &intvl_one;
+static struct timeval *intvl_two_ptr = &intvl_two;
+static struct timeval *temp_intvl_ptr = &intvl_one;
+#endif
+
+#define INTERVALS_INIT() \
+      if (interval_burst) { \
+	HIST_timestamp(intvl_one_ptr); \
+      } \
+      interval_count = interval_burst; \
+
+#define INTERVALS_WAIT() \
+      /* 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 > 1) { \
+	  fprintf(where,"about to spin suspend\n"); \
+	  fflush(where); \
+	} \
+        HIST_timestamp(intvl_two_ptr); \
+        while(delta_micro(intvl_one_ptr,intvl_two_ptr) < interval_usecs) { \
+	  HIST_timestamp(intvl_two_ptr); \
+	} \
+	temp_intvl_ptr = intvl_one_ptr; \
+	intvl_one_ptr = intvl_two_ptr; \
+	intvl_two_ptr = temp_intvl_ptr; \
+	interval_count = interval_burst; \
+      }
+#endif
+#endif
+
+#ifdef WANT_DEMO
+#ifdef HAVE_GETHRTIME
+static hrtime_t demo_one;
+static hrtime_t demo_two;
+static hrtime_t *demo_one_ptr = &demo_one;
+static hrtime_t *demo_two_ptr = &demo_two;
+static hrtime_t *temp_demo_ptr = &demo_one;
+#elif defined(WIN32)
+static LARGE_INTEGER demo_one;
+static LARGE_INTEGER demo_two;
+static LARGE_INTEGER *demo_one_ptr = &demo_one;
+static LARGE_INTEGER *demo_two_ptr = &demo_two;
+static LARGE_INTEGER *temp_demo_ptr = &demo_one;
+#else
+static struct timeval demo_one;
+static struct timeval demo_two;
+static struct timeval *demo_one_ptr = &demo_one;
+static struct timeval *demo_two_ptr = &demo_two;
+static struct timeval *temp_demo_ptr = &demo_one;
+#endif 
+
+/* for a _STREAM test, "a" should be lss_size and "b" should be
+   rsr_size. for a _MAERTS test, "a" should be lsr_size and "b" should
+   be rss_size. raj 2005-04-06 */
+#define DEMO_STREAM_SETUP(a,b) \
+    if ((demo_mode) && (demo_units == 0)) { \
+      /* take our default value of demo_units to be the larger of \
+	 twice the remote's SO_RCVBUF or twice our SO_SNDBUF */ \
+      if (a > b) { \
+	demo_units = 2*a; \
+      } \
+      else { \
+	demo_units = 2*b; \
+      } \
+    }
+
+#define DEMO_STREAM_INTERVAL(units) \
+      if (demo_mode) { \
+	double actual_interval; \
+	units_this_tick += units; \
+	if (units_this_tick >= demo_units) { \
+	  /* time to possibly update demo_units and maybe output an \
+	     interim result */ \
+	  HIST_timestamp(demo_two_ptr); \
+	  actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
+	  /* we always want to fine-tune demo_units here whether we \
+	     emit an interim result or not.  if we are short, this \
+	     will lengthen demo_units.  if we are long, this will \
+	     shorten it */ \
+	  demo_units = demo_units * (demo_interval / actual_interval); \
+	  if (actual_interval >= demo_interval) { \
+	    /* time to emit an interim result */ \
+	    fprintf(where, \
+		    "Interim result: %7.2f %s/s over %.2f seconds\n", \
+		    calc_thruput_interval(units_this_tick, \
+					  actual_interval/1000000.0), \
+		    format_units(), \
+		    actual_interval/1000000.0); \
+            fflush(where); \
+	    units_this_tick = 0.0; \
+	    /* now get a new starting timestamp.  we could be clever \
+	       and swap pointers - the math we do probably does not \
+	       take all that long, but for now this will suffice */ \
+	    temp_demo_ptr = demo_one_ptr; \
+	    demo_one_ptr = demo_two_ptr; \
+	    demo_two_ptr = temp_demo_ptr; \
+	  } \
+	} \
+      }
+
+#define DEMO_RR_SETUP(a) \
+    if ((demo_mode) && (demo_units == 0)) { \
+      /* take whatever we are given */ \
+	demo_units = a; \
+    }
+
+#define DEMO_RR_INTERVAL(units) \
+      if (demo_mode) { \
+	double actual_interval; \
+	units_this_tick += units; \
+	if (units_this_tick >= demo_units) { \
+	  /* time to possibly update demo_units and maybe output an \
+	     interim result */ \
+	  HIST_timestamp(demo_two_ptr); \
+	  actual_interval = delta_micro(demo_one_ptr,demo_two_ptr); \
+	  /* we always want to fine-tune demo_units here whether we \
+	     emit an interim result or not.  if we are short, this \
+	     will lengthen demo_units.  if we are long, this will \
+	     shorten it */ \
+	  demo_units = demo_units * (demo_interval / actual_interval); \
+	  if (actual_interval >= demo_interval) { \
+	    /* time to emit an interim result */ \
+	    fprintf(where, \
+		    "Interim result: %.2f %s/s over %.2f seconds\n", \
+                    units_this_tick / (actual_interval/1000000.0), \
+		    "Trans", \
+		    actual_interval/1000000.0); \
+	    units_this_tick = 0.0; \
+	    /* now get a new starting timestamp.  we could be clever \
+	       and swap pointers - the math we do probably does not \
+	       take all that long, but for now this will suffice */ \
+	    temp_demo_ptr = demo_one_ptr; \
+	    demo_one_ptr = demo_two_ptr; \
+	    demo_two_ptr = temp_demo_ptr; \
+	  } \
+	} \
+      }
+#endif 
+
+char sockets_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+TCP/UDP BSD Sockets Test Options:\n\
+    -b number         Send number requests at start of _RR tests\n\
+    -C                Set TCP_CORK when available\n\
+    -D [L][,R]        Set TCP_NODELAY locally and/or remotely (TCP_*)\n\
+    -h                Display this text\n\
+    -H name,fam       Use name (or IP) and family as target of data connection\n\
+    -L name,fam       Use name (or IP) and family as source of data connection\n\
+    -m bytes          Set the send size (TCP_STREAM, UDP_STREAM)\n\
+    -M bytes          Set the recv size (TCP_STREAM, UDP_STREAM)\n\
+    -n                Use the connected socket for UDP locally\n\
+    -N                Use the connected socket for UDP remotely\n\
+    -p min[,max]      Set the min/max port numbers for TCP_CRR, TCP_TRR\n\
+    -P local[,remote] Set the local/remote port for the data socket\n\
+    -r req,[rsp]      Set request/response sizes (TCP_RR, 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\
+    -4                Use AF_INET (eg IPv4) on both ends of the data conn\n\
+    -6                Use AF_INET6 (eg IPv6) on both ends of the data conn\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"; 
+
+
+
+/* these routines convert between the AF address space and the NF
+   address space since the numeric values of AF_mumble are not the
+   same across the platforms. raj 2005-02-08 */
+
+int
+nf_to_af(int nf) {
+  switch(nf) {
+  case NF_INET:
+    return AF_INET;
+    break;
+  case NF_UNSPEC:
+    return AF_UNSPEC;
+    break;
+  case NF_INET6:
+#if defined(AF_INET6)
+    return AF_INET6;
+#else
+    return AF_UNSPEC;
+#endif
+    break;
+  default:
+    return AF_UNSPEC;
+    break;
+  }
+}
+
+int
+af_to_nf(int af) {
+
+  switch(af) {
+  case AF_INET:
+    return NF_INET;
+    break;
+  case AF_UNSPEC:
+    return NF_UNSPEC;
+    break;
+#if defined(AF_INET6)
+  case AF_INET6:
+    return NF_INET6;
+    break;
+#endif
+  default:
+    return NF_UNSPEC;
+    break;
+  }
+}     
+
+
+ /* 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 */
+static
+void
+get_tcp_info(SOCKET socket, int *mss)
+{
+
+#ifdef TCP_MAXSEG
+  netperf_socklen_t sock_opt_len;
+
+  sock_opt_len = sizeof(netperf_socklen_t);
+  if (getsockopt(socket,
+		 getprotobyname("tcp")->p_proto,	
+		 TCP_MAXSEG,
+		 (char *)mss,
+		 &sock_opt_len) == SOCKET_ERROR) {
+    fprintf(where,
+	    "netperf: get_tcp_info: getsockopt TCP_MAXSEG: errno %d\n",
+	    errno);
+    fflush(where);
+    *mss = -1;
+  }
+#else
+  *mss = -1;
+#endif /* TCP_MAXSEG */
+}
+
+
+/* return a pointer to a completed addrinfo chain - prefer
+   data_address to controlhost and utilize the specified address
+   family */
+
+struct addrinfo *
+complete_addrinfo(char *controlhost, char *data_address, char *port, int family, int type, int protocol, int flags) 
+{
+  struct addrinfo hints;
+  struct addrinfo *res;
+  struct addrinfo *temp_res;
+
+#define CHANGED_SOCK_TYPE  0x1
+#define CHANGED_PROTOCOL   0x2
+#define CHANGED_SCTP       0x4
+  int    change_info = 0;
+  static int change_warning_displayed = 0;
+
+  int count = 0;
+  int error = 0;
+
+  char *hostname;
+
+  /* take data-address over controlhost */
+  if (data_address)
+    hostname = data_address;
+  else
+    hostname = controlhost;
+
+  if (debug) {
+    fprintf(where,
+	    "complete_addrinfo using hostname %s port %s family %s type %s prot %s flags 0x%x\n",
+	    hostname,
+	    port,
+	    inet_ftos(family),
+	    inet_ttos(type),
+	    inet_ptos(protocol),
+	    flags);
+    fflush(where);
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = family;
+  hints.ai_socktype = type;
+  hints.ai_protocol = protocol;
+  hints.ai_flags = flags|AI_CANONNAME;
+
+  count = 0;
+  do {
+    error = getaddrinfo((char *)hostname,
+                        (char *)port,
+                        &hints,
+                        &res);
+    count += 1;
+    if (error == EAI_AGAIN) {
+      if (debug) {
+        fprintf(where,"Sleeping on getaddrinfo EAI_AGAIN\n");
+        fflush(where);
+      }
+      sleep(1);
+    }
+    /* while you see this kludge first, it is actually the second, the
+       first being the one for Solaris below. The need for this kludge
+       came after implementing the Solaris broken getaddrinfo kludge -
+       now we see a kludge in Linux getaddrinfo where if it is given
+       SOCK_STREAM and IPPROTO_SCTP it barfs with a -7
+       EAI_SOCKTYPE. so, we check if the error was EAI_SOCKTYPE and if
+       we were asking for IPPROTO_SCTP and if so, kludge, again... raj
+       2008-10-13 */
+#ifdef WANT_SCTP
+    if (EAI_SOCKTYPE == error
+#ifdef EAI_BADHINTS
+        || EAI_BADHINTS == error
+#endif
+        ) {
+      /* we ass-u-me this is the Linux getaddrinfo bug, clear the
+	 hints.ai_protocol field, and set some state "remembering"
+	 that we did this so the code for the Solaris kludge can do
+	 the fix-up for us.  also flip error over to EAI_AGAIN and
+	 make sure we don't "count" this time around the loop. */
+      hints.ai_protocol = 0;
+      error = EAI_AGAIN;
+      count -= 1;
+      change_info |= CHANGED_SCTP;
+    }
+#endif
+  } while ((error == EAI_AGAIN) && (count <= 5));
+
+  if (error) {
+    fprintf(where,
+	    "complete_addrinfo: could not resolve '%s' port '%s' af %d",
+	    hostname,
+	    port,
+	    family);
+    fprintf(where,
+	    "\n\tgetaddrinfo returned %d %s\n",
+	    error,
+	    gai_strerror(error));
+    fflush(where);
+    exit(-1);
+  }
+
+  /* there exists at least one platform - Solaris 10 - that does not
+     seem to completely honor the ai_protocol and/or ai_socktype one
+     sets in the hints parm to the getaddrinfo call.  so, we need to
+     walk the list of entries returned and if either of those do not
+     match what we asked for, we need to go ahead and set them
+     "correctly" this is based in part on some earlier SCTP-only code
+     from previous revisions.  raj 2006-10-09 */
+
+  temp_res = res;
+
+  while (temp_res) {
+
+    if ((type)  &&
+	(temp_res->ai_socktype != type)) {
+      change_info |= CHANGED_SOCK_TYPE;
+      if (debug) {
+	fprintf(where,
+		"WARNING! Changed bogus getaddrinfo socket type %d to %d\n",
+		temp_res->ai_socktype,
+		type);
+	fflush(where);
+      }
+      temp_res->ai_socktype = type;
+    }
+
+    if ((protocol) &&
+	(temp_res->ai_protocol != protocol)) {
+      change_info |= CHANGED_PROTOCOL;
+      if (debug) {
+	fprintf(where,
+		"WARNING! Changed bogus getaddrinfo protocol %d to %d\n",
+		temp_res->ai_protocol,
+		protocol);
+	fflush(where);
+      }
+      temp_res->ai_protocol = protocol;
+    }
+    temp_res = temp_res->ai_next;
+  }
+	
+  if ((change_info & CHANGED_SOCK_TYPE) &&
+      !(change_warning_displayed & CHANGED_SOCK_TYPE)) {
+    change_warning_displayed |= CHANGED_SOCK_TYPE;
+    fprintf(where,
+	    "WARNING! getaddrinfo returned a socket type which did not\n");
+    fprintf(where,
+	    "match the requested type.  Please contact your vendor for\n");
+    fprintf(where,
+	    "a fix to this bug in getaddrinfo()\n");
+    fflush(where);
+  }
+
+  /* if we dropped the protocol hint, it would be for a protocol that
+     getaddrinfo() wasn't supporting yet, not for the bug that it took
+     our hint and still returned zero. raj 2006-10-16 */
+  if ((change_info & CHANGED_PROTOCOL) &&
+      !(change_warning_displayed & CHANGED_PROTOCOL) &&
+      (hints.ai_protocol != 0)) {
+    change_warning_displayed |= CHANGED_PROTOCOL;
+    fprintf(where,
+	    "WARNING! getaddrinfo returned a protocol other than the\n");
+    fprintf(where,
+	    "requested protocol.  Please contact your vendor for\n");
+    fprintf(where,
+	    "a fix to this bug in getaddrinfo()\n");
+    fflush(where);
+  }
+
+  if ((change_info & CHANGED_SCTP) &&
+      !(change_warning_displayed & CHANGED_SCTP)) {
+    change_warning_displayed |= CHANGED_SCTP;
+    fprintf(where,
+	    "WARNING! getaddrinfo on this platform does not accept IPPROTO_SCTP!\n");
+    fprintf(where,
+	    "Please contact your vendor for a fix to this bug in getaddrinfo().\n");
+    fflush(where);
+  }
+
+
+  if (debug) {
+    dump_addrinfo(where, res, hostname, port, family);
+  }
+
+  return(res);
+}
+
+void
+complete_addrinfos(struct addrinfo **remote,struct addrinfo **local, char remote_host[], int type, int protocol, int flags) {
+
+  *remote = complete_addrinfo(remote_host,
+			      remote_data_address,
+			      remote_data_port,
+			      remote_data_family,
+			      type,
+			      protocol,
+			      flags);
+
+  /* OK, if the user has not specified a local data endpoint address
+     (test-specific -L), pick the local data endpoint address based on
+     the remote data family info (test-specific -H or -4 or -6
+     option).  if the user has not specified remote data addressing
+     info (test-specific -H, -4 -6) pick something based on the local
+     control connection address (ie the global -L option). */
+
+  if (NULL == local_data_address) {
+    local_data_address = malloc(HOSTNAMESIZE);
+    if (NULL == remote_data_address) {
+      if (debug) {
+	fprintf(where,
+		"local_data_address not set, using local_host_name of '%s'\n",
+		local_host_name);
+	fflush(where);
+      }
+      strcpy(local_data_address,local_host_name);
+    }
+    else {
+      if (debug) {
+	fprintf(where,
+		"local_data_address not set, using address family info\n");
+	fflush(where);
+      }
+      /* by default, use 0.0.0.0 - assume IPv4 */
+      strcpy(local_data_address,"0.0.0.0");
+#if defined(AF_INET6)
+      if ((AF_INET6 == local_data_family) ||
+	  ((AF_UNSPEC == local_data_family) &&
+	   (AF_INET6 == remote_data_family)) ||
+	  ((AF_UNSPEC == local_data_family) && 
+	   (AF_INET6 == (*remote)->ai_family))) {
+	strcpy(local_data_address,"::0");
+      }
+#endif
+    }
+  }
+
+  *local = complete_addrinfo("what to put here?",
+			     local_data_address,
+			     local_data_port,
+			     local_data_family,
+			     type,
+			     protocol,
+			     flags|AI_PASSIVE);
+
+}
+
+void
+set_hostname_and_port(char *hostname, char *portstr, int family, int port)
+{
+  strcpy(hostname,"0.0.0.0");
+#if defined AF_INET6
+  if (AF_INET6 == family) {
+    strcpy(hostname,"::0");
+  }
+#endif
+    
+  sprintf(portstr, "%u", port);
+
+}
+
+static unsigned short
+get_port_number(struct addrinfo *res) 
+{
+ switch(res->ai_family) {
+  case AF_INET: {
+    struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
+    return(ntohs(foo->sin_port));
+    break;
+  }
+#if defined(AF_INET6)
+  case AF_INET6: {
+    struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
+    return(ntohs(foo->sin6_port));
+    break;
+  }
+#endif
+  default:
+    fprintf(where,
+	    "Unexpected Address Family of %u\n",res->ai_family);
+    fflush(where);
+    exit(-1);
+  }
+}
+
+/* this routine will set the port number of the sockaddr in the
+   addrinfo to the specified value, based on the address family */
+void
+set_port_number(struct addrinfo *res, unsigned short port)
+{
+  switch(res->ai_family) {
+  case AF_INET: {
+    struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
+    foo->sin_port = htons(port);
+    break;
+  }
+#if defined(AF_INET6)
+  case AF_INET6: {
+    struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
+    foo->sin6_port = htons(port);
+    break;
+  }
+#endif
+  default:
+    fprintf(where,
+	    "Unexpected Address Family of %u\n",res->ai_family);
+    fflush(where);
+    exit(-1);
+  }
+}
+
+
+
+ /* 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.  This routine will
+  also be used by the "SCTP" tests, hence the slightly strange-looking
+  SCTP stuff in the classic bsd sockets test file... vlad/raj
+  2005-03-15 */
+
+SOCKET
+create_data_socket(struct addrinfo *res)
+{
+
+  SOCKET temp_socket;
+  int one;
+  int    on  = 1;
+  
+
+  /*set up the data socket                        */
+  temp_socket = socket(res->ai_family,
+		       res->ai_socktype,
+		       res->ai_protocol);
+  
+  if (temp_socket == INVALID_SOCKET){
+    fprintf(where,
+	    "netperf: create_data_socket: socket: errno %d fam %s type %s prot %s errmsg %s\n",
+	    errno,
+	    inet_ftos(res->ai_family),
+	    inet_ttos(res->ai_socktype),
+	    inet_ptos(res->ai_protocol),
+	    strerror(errno));
+    fflush(where);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"create_data_socket: socket %d obtained...\n",temp_socket);
+    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 (well, should
+   never be) 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.  */
+  
+  /* all the oogy nitty gritty stuff moved from here into the routine
+     being called below, per patches from davidm to workaround the bug
+     in Linux getsockopt().  raj 2004-06-15 */
+  set_sock_buffer (temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
+  set_sock_buffer (temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
+
+  /* now, we may wish to enable the copy avoidance features on the */
+  /* local system. of course, this may not be possible... */
+  
+#ifdef SO_RCV_COPYAVOID
+  if (loc_rcvavoid) {
+    if (setsockopt(temp_socket,
+		   SOL_SOCKET,
+		   SO_RCV_COPYAVOID,
+		   (const char *)&loc_rcvavoid,
+		   sizeof(int)) == SOCKET_ERROR) {
+      fprintf(where,
+	      "netperf: create_data_socket: Could not enable receive copy avoidance");
+      fflush(where);
+      loc_rcvavoid = 0;
+    }
+  }
+#else
+  /* it wasn't compiled in... */
+  loc_rcvavoid = 0;
+#endif /* SO_RCV_COPYAVOID */
+
+#ifdef SO_SND_COPYAVOID
+  if (loc_sndavoid) {
+    if (setsockopt(temp_socket,
+		   SOL_SOCKET,
+		   SO_SND_COPYAVOID,
+		   (const char *)&loc_sndavoid,
+		   sizeof(int)) == SOCKET_ERROR) {
+      fprintf(where,
+	      "netperf: create_data_socket: Could not enable send copy avoidance");
+      fflush(where);
+      loc_sndavoid = 0;
+    }
+  }
+#else
+  /* it was not compiled in... */
+  loc_sndavoid = 0;
+#endif
+  
+  /* 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 */
+
+  /* well..... long ago and far away that would have happened, in
+     particular because we would always use IPPROTO_TCP here.
+     however, now we are using res->ai_protocol, which will be
+     IPPROT_UDP, and while HP-UX, and I suspect no-one else on the
+     planet has a UDP_mumble option that overlaps with TCP_NODELAY,
+     sure as knuth made little green programs, linux has a UDP_CORK
+     option that is defined as a value of 1, which is the same a
+     TCP_NODELAY under Linux.  So, when asking for -D and
+     "TCP_NODELAY" under Linux, we are actually setting UDP_CORK
+     instead of getting an error like every other OS on the
+     planet. joy and rupture. this stops a UDP_RR test cold sooo we
+     have to make sure that res->ai_protocol actually makes sense for
+     a _NODELAY setsockopt() or a UDP_RR test on Linux where someone
+     mistakenly sets -D will hang.  raj 2005-04-21 */
+  
+#if defined(TCP_NODELAY) || defined(SCTP_NODELAY)
+  if ((loc_nodelay) && (res->ai_protocol != IPPROTO_UDP)) {
+
+    /* strictly speaking, since the if defined above is an OR, we
+       should probably check against TCP_NODELAY being defined here.
+       however, the likelihood of SCTP_NODELAY being defined and
+       TCP_NODELAY _NOT_ being defined is, probably :), epsilon.  raj
+       2005-03-15 */
+
+    int option = TCP_NODELAY;
+
+    /* I suspect that WANT_SCTP would suffice here since that is the
+       only time we would have called getaddrinfo with a hints asking
+       for SCTP, but just in case there is an SCTP implementation out
+       there _without_ SCTP_NODELAY... raj 2005-03-15 */ 
+
+#if defined(WANT_SCTP) && defined(SCTP_NODELAY)
+    if (IPPROTO_SCTP == res->ai_protocol) {
+      option = SCTP_NODELAY;
+    }
+#endif
+
+    one = 1;
+    if(setsockopt(temp_socket,
+		  res->ai_protocol,
+		  option,
+		  (char *)&one,
+		  sizeof(one)) == SOCKET_ERROR) {
+      fprintf(where,
+	      "netperf: create_data_socket: nodelay: errno %d\n",
+	      errno);
+      fflush(where);
+    }
+    
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: create_data_socket: [TCP|SCTP]_NODELAY requested...\n");
+      fflush(where);
+    }
+  }
+#else /* TCP_NODELAY */
+  
+  loc_nodelay = 0;
+  
+#endif /* TCP_NODELAY */
+
+#if defined(TCP_CORK)
+    
+    if (loc_tcpcork != 0) {
+      /* the user wishes for us to set TCP_CORK on the socket */
+      int one = 1;
+      if (setsockopt(temp_socket,
+		     getprotobyname("tcp")->p_proto,
+		     TCP_CORK,
+		     (char *)&one,
+		     sizeof(one)) == SOCKET_ERROR) {
+	perror("netperf: sendfile_tcp_stream: tcp_cork");
+	exit(1);
+      }
+      if (debug) {
+	fprintf(where,"sendfile_tcp_stream: tcp_cork...\n");
+      }
+    }
+    
+#endif /* TCP_CORK */    
+
+  /* since some of the UDP tests do not do anything to cause an
+     implicit bind() call, we need to be rather explicit about our
+     bind() call here. even if the address and/or the port are zero
+     (INADDR_ANY etc). raj 2004-07-20 */
+
+  if (setsockopt(temp_socket,
+		 SOL_SOCKET,
+		 SO_REUSEADDR,
+		 (const char *)&on,
+		 sizeof(on)) < 0) {
+    fprintf(where,
+	    "netperf: create_data_socket: SO_REUSEADDR failed %d\n",
+	    errno);
+    fflush(where);
+  }
+  
+  if (bind(temp_socket,
+	   res->ai_addr,
+	   res->ai_addrlen) < 0) {
+    if (debug) {
+      fprintf(where,
+	      "netperf: create_data_socket: data socket bind failed errno %d\n",
+	      errno);
+      fprintf(where," port: %d\n",get_port_number(res));
+      fflush(where);
+    }
+  }
+  
+
+  return(temp_socket);
+
+}
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+
+
+ /* This routine is for those BROKEN systems which do not correctly */
+ /* pass socket attributes through calls such as accept(). It should */
+ /* only be called for those broken systems. I *really* don't want to */
+ /* have this, but even broken systems must be measured. raj 11/95 */
+void
+kludge_socket_options(int temp_socket)
+{
+
+  set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
+  set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
+
+  /* now, we may wish to enable the copy avoidance features on the */
+  /* local system. of course, this may not be possible... */
+  /* those calls were only valid for HP-UX, and I know that HP-UX is */
+  /* written correctly, and so we do not need to include those calls */
+  /* in this kludgy routine. raj 11/95 */
+
+  
+  /* 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 (loc_nodelay) {
+    one = 1;
+    if(setsockopt(temp_socket,
+		  getprotobyname("tcp")->p_proto,
+		  TCP_NODELAY,
+		  (char *)&one,
+		  sizeof(one)) == SOCKET_ERROR) {
+      fprintf(where,"netperf: kludge_socket_options: nodelay: errno %d\n",
+	      errno);
+      fflush(where);
+    }
+    
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: kludge_socket_options: TCP_NODELAY requested...\n");
+      fflush(where);
+    }
+  }
+#else /* TCP_NODELAY */
+  
+  loc_nodelay = 0;
+  
+#endif /* TCP_NODELAY */
+
+  }
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+
+static void *
+get_address_address(struct addrinfo *info) 
+{
+  struct sockaddr_in *sin;
+#if defined(AF_INET6)
+  struct sockaddr_in6 *sin6;
+#endif
+
+  switch(info->ai_family) {
+  case AF_INET:
+    sin = (struct sockaddr_in *)info->ai_addr;
+    return(&(sin->sin_addr));
+    break;
+#if defined(AF_INET6)
+  case AF_INET6:
+    sin6 = (struct sockaddr_in6 *)info->ai_addr;
+    return(&(sin6->sin6_addr));
+    break;
+#endif
+  default:
+    fprintf(stderr,"we never expected to get here in get_address_address\n");
+    fflush(stderr);
+    exit(-1);
+  }
+}
+
+#if defined(WIN32) 
+/* +*+ Why isn't this in the winsock headers yet? */
+const char *
+inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
+/* This routine is a generic test header printer for the topmost header */
+void
+print_top_test_header(char test_name[], struct addrinfo *source, struct addrinfo *destination)
+{
+
+#if defined(AF_INET6)
+  char address_buf[INET6_ADDRSTRLEN];
+#else
+  char address_buf[16]; /* magic constant */
+#endif
+
+  /* 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,test_name);
+  address_buf[0] = '\0';
+  inet_ntop(source->ai_family,get_address_address(source),address_buf,sizeof(address_buf));
+  fprintf(where,
+	  " from %s (%s) port %u %s",
+	  source->ai_canonname,
+	  address_buf,
+	  get_port_number(source),
+	  inet_ftos(source->ai_family));
+  address_buf[0] = '\0';
+  inet_ntop(destination->ai_family,get_address_address(destination),address_buf,sizeof(address_buf));
+  fprintf(where,
+	  " to %s (%s) port %u %s",
+	  destination->ai_canonname,
+	  address_buf,
+	  get_port_number(destination),
+	  inet_ftos(destination->ai_family));
+
+  if (iteration_max > 1) {
+    fprintf(where,
+	    " : +/-%3.1f%% @ %2d%% conf. %s",
+	    interval/0.02,
+	    confidence_level,
+	    result_confidence_only ? " on result only" : "");
+  }
+  if ((loc_nodelay > 0) || (rem_nodelay > 0)) {
+    fprintf(where," : nodelay");
+  }
+  if ((loc_sndavoid > 0) || 
+      (loc_rcvavoid > 0) ||
+      (rem_sndavoid > 0) ||
+      (rem_rcvavoid > 0)) {
+    fprintf(where," : copy avoidance");
+  }
+
+  if (no_control) {
+    fprintf(where," : no control");
+  }
+
+#ifdef WANT_HISTOGRAM
+  fprintf(where," : histogram");
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_INTERVALS
+#ifndef WANT_SPIN
+  fprintf(where," : interval");
+#else
+  fprintf(where," : spin interval");
+#endif
+#endif /* WANT_INTERVALS */
+
+#ifdef DIRTY 
+  fprintf(where," : dirty data");
+#endif /* DIRTY */
+#ifdef WANT_DEMO
+  fprintf(where," : demo");
+#endif
+#ifdef WANT_FIRST_BURST
+  /* a little hokey perhaps, but we really only want this to be
+     emitted for tests where it actually is used, which means a
+     "REQUEST/RESPONSE" test. raj 2005-11-10 */
+  if (strstr(test_name,"REQUEST/RESPONSE")) {
+    fprintf(where," : first burst %d",first_burst_size);
+  }
+#endif
+  if (cpu_binding_requested) {
+    fprintf(where," : cpu bind");
+  }
+  fprintf(where,"\n");
+  
+}
+
+
+/* This routine implements the TCP unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_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 %s\n";
+  
+  char *tput_fmt_1 =
+    "%6d %6d %6d    %-6.2f   %7.2f   %s\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 %s\n";
+
+  char *cpu_fmt_1 =
+    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f %s\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;
+  
+  /* 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. */
+  
+  struct ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  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 */
+
+  unsigned long long local_bytes_sent = 0;
+  double	bytes_sent = 0.0;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+  
+  struct	tcp_stream_request_struct	*tcp_stream_request;
+  struct	tcp_stream_response_struct	*tcp_stream_response;
+  struct	tcp_stream_results_struct	*tcp_stream_result;
+  
+  tcp_stream_request  = 
+    (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+  tcp_stream_response =
+    (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+  tcp_stream_result   = 
+    (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  /* complete_addrinfos will either succede or exit the process */
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+  
+  if ( print_headers ) {
+    print_top_test_header("TCP STREAM TEST",local_res,remote_res);
+  }
+
+  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_data_socket(local_res);
+    
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_tcp_stream: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_tcp_stream: send_socket obtained...\n");
+    }
+    
+    /* 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);
+    }
+    
+    if (!no_control) {
+      /* 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_TCP_STREAM;
+      tcp_stream_request->send_buf_size	=	rss_size_req;
+      tcp_stream_request->recv_buf_size	=	rsr_size_req;
+      tcp_stream_request->receive_size	=	recv_size;
+      tcp_stream_request->no_delay	=	rem_nodelay;
+      tcp_stream_request->recv_alignment	=	remote_recv_align;
+      tcp_stream_request->recv_offset	=	remote_recv_offset;
+      tcp_stream_request->measure_cpu	=	remote_cpu_usage;
+      tcp_stream_request->cpu_rate	=	remote_cpu_rate;
+      if (test_time) {
+	tcp_stream_request->test_length	=	test_time;
+      }
+      else {
+	tcp_stream_request->test_length	=	test_bytes;
+      }
+      tcp_stream_request->so_rcvavoid	=	rem_rcvavoid;
+      tcp_stream_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+      tcp_stream_request->dirty_count     =       rem_dirty_count;
+      tcp_stream_request->clean_count     =       rem_clean_count;
+#endif /* DIRTY */
+      tcp_stream_request->port            =    atoi(remote_data_port);
+      tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
+      if (debug > 1) {
+	fprintf(where,
+		"netperf: send_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	      =	tcp_stream_response->recv_buf_size;
+	rss_size	      =	tcp_stream_response->send_buf_size;
+	rem_nodelay     =	tcp_stream_response->no_delay;
+	remote_cpu_usage=	tcp_stream_response->measure_cpu;
+	remote_cpu_rate = tcp_stream_response->cpu_rate;
+	
+	/* we have to make sure that the server port number is in
+	   network order */
+	set_port_number(remote_res,
+			(short)tcp_stream_response->data_port_number);
+	
+	rem_rcvavoid	= tcp_stream_response->so_rcvavoid;
+	rem_sndavoid	= tcp_stream_response->so_sndavoid;
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lss_size,rsr_size)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: send_tcp_stream: data socket connect failed");
+      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);
+
+    /* we only start the interval timer if we are using the
+       timer-timed intervals rather than the sit and spin ones. raj
+       2006-02-06 */    
+#if defined(WANT_INTERVALS)
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+    /* before we start, initialize a few variables */
+
+#ifdef WANT_DEMO
+      if (demo_mode) {
+	HIST_timestamp(demo_one_ptr);
+      }
+#endif
+      
+
+    /* 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
+      access_buffer(send_ring->buffer_ptr,
+		    send_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+#endif /* DIRTY */
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp just before we go into send and then again just
+	 after we come out raj 8/94 */
+	/* but lets only do this if there is going to be a histogram
+	   displayed */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+
+      if((len=send(send_socket,
+		   send_ring->buffer_ptr,
+		   send_size,
+		   0)) != send_size) {
+      if ((len >=0) || SOCKET_EINTR(len)) {
+	    /* the test was interrupted, must be the end of test */
+	    break;
+	  }
+	perror("netperf: data send error");
+	printf("len was %d\n",len);
+	exit(1);
+      }
+
+      local_bytes_sent += send_size;
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* 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_DEMO
+      DEMO_STREAM_INTERVAL(send_size)
+#endif 
+
+#if defined(WANT_INTERVALS)
+      INTERVALS_WAIT();
+#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_tcp_info(send_socket,&tcp_mss);
+    }
+    
+    if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
+      perror("netperf: cannot shutdown tcp stream socket");
+      exit(1);
+    }
+    
+    /* hang a recv() off the socket to block until the remote has */
+    /* brought all the data up into the application. it will do a */
+    /* shutdown to cause a FIN to be sent our way. We will assume that */
+    /* any exit from the recv() call is good... raj 4/93 */
+    
+    recv(send_socket, send_ring->buffer_ptr, send_size, 0);
+    
+    /* 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+
+    close(send_socket);
+
+    if (!no_control) {
+      /* 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);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	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	= ntohd(tcp_stream_result->bytes_received);
+    }
+    else {
+      bytes_sent = (double)local_bytes_sent;
+    }
+
+    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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= tcp_stream_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      tcp_stream_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(tcp_stream_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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)tcp_stream_result->recv_calls,
+	    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 routine implements the netperf-side TCP unidirectional data
+   transfer test (a.k.a. stream) for the sockets interface where the
+   data flow is from the netserver to the netperf.  It receives its
+   parameters via global variables from the shell and writes its
+   output to the standard output. */
+
+
+void 
+send_tcp_maerts(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 %s\n";
+  
+  char *tput_fmt_1 =
+    "%6d %6d %6d    %-6.2f   %7.2f    %s \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 %s\n";
+
+  char *cpu_fmt_1 =
+    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f %s\n";
+  
+  char *ksink_fmt = "\n\
+Alignment      Offset         %-8.8s %-8.8s    Recvs   %-8.8s Sends\n\
+Local  Remote  Local  Remote  Xfered   Per                 Per\n\
+Recv   Send    Recv   Send             Recv (avg)          Send (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;
+  
+  /* what we want is to have a buffer space that is at least one */
+  /* recv-size greater than our recv 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. */
+  
+  struct ring_elt *recv_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  SOCKET recv_socket;
+  int bytes_remaining;
+  int tcp_mss = -1;  /* possibly uninitialized on printf far below */
+
+  /* with links like fddi, one can recv > 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 = 0.0;
+  unsigned long long local_bytes_recvd = 0;
+
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+  
+  struct	tcp_maerts_request_struct	*tcp_maerts_request;
+  struct	tcp_maerts_response_struct	*tcp_maerts_response;
+  struct	tcp_maerts_results_struct	*tcp_maerts_result;
+  
+  tcp_maerts_request  = 
+    (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data;
+  tcp_maerts_response =
+    (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data;
+  tcp_maerts_result   = 
+    (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+  
+  if ( print_headers ) {
+    print_top_test_header("TCP MAERTS TEST",local_res,remote_res);
+  }
+
+  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_sent     =	0.0;
+    times_up       = 	0;
+    
+    /*set up the data socket                        */
+    recv_socket = create_data_socket(local_res);
+    
+    if (recv_socket == INVALID_SOCKET){
+      perror("netperf: send_tcp_maerts: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_tcp_maerts: recv_socket obtained...\n");
+    }
+
+    /* 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 recv */
+    /* 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 recv size to 4KB - no */
+    /* particular reason, just arbitrary... */
+    if (recv_size == 0) {
+      if (lsr_size > 0) {
+	recv_size = lsr_size;
+      }
+      else {
+	recv_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 recv-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 */
+    /* recv_size is bigger than the socket size, so we must check... the */
+    /* user may have wanted to explicitly set the "width" of our recv */
+    /* buffers, we should respect that wish... */
+    if (recv_width == 0) {
+      recv_width = (lsr_size/recv_size) + 1;
+      if (recv_width == 1) recv_width++;
+    }
+    
+    if (recv_ring == NULL) {
+      /* only allocate the recv 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 */
+      recv_ring = allocate_buffer_ring(recv_width,
+				       recv_size,
+				       local_recv_align,
+				       local_recv_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);
+    }
+    
+    if (!no_control) {
+      /* 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_TCP_MAERTS;
+      tcp_maerts_request->send_buf_size	=	rss_size_req;
+      tcp_maerts_request->recv_buf_size	=	rsr_size_req;
+      tcp_maerts_request->send_size	=	send_size;
+      tcp_maerts_request->no_delay	=	rem_nodelay;
+      tcp_maerts_request->send_alignment	=	remote_send_align;
+      tcp_maerts_request->send_offset	=	remote_send_offset;
+      tcp_maerts_request->measure_cpu	=	remote_cpu_usage;
+      tcp_maerts_request->cpu_rate	=	remote_cpu_rate;
+      if (test_time) {
+	tcp_maerts_request->test_length	=	test_time;
+      }
+      else {
+	tcp_maerts_request->test_length	=	test_bytes;
+      }
+      tcp_maerts_request->so_rcvavoid	=	rem_rcvavoid;
+      tcp_maerts_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+      tcp_maerts_request->dirty_count       =       rem_dirty_count;
+      tcp_maerts_request->clean_count       =       rem_clean_count;
+#endif /* DIRTY */
+      tcp_maerts_request->port            = atoi(remote_data_port);
+      tcp_maerts_request->ipfamily        = af_to_nf(remote_res->ai_family);
+      if (debug > 1) {
+	fprintf(where,
+		"netperf: send_tcp_maerts: requesting TCP maerts 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	=	tcp_maerts_response->recv_buf_size;
+	rss_size	=	tcp_maerts_response->send_buf_size;
+	rem_nodelay     =	tcp_maerts_response->no_delay;
+	remote_cpu_usage=	tcp_maerts_response->measure_cpu;
+	remote_cpu_rate = tcp_maerts_response->cpu_rate;
+	send_size       = tcp_maerts_response->send_size;
+	
+	/* we have to make sure that the server port number is in
+	 network order */
+      set_port_number(remote_res,
+		      (short)tcp_maerts_response->data_port_number);
+      rem_rcvavoid	= tcp_maerts_response->so_rcvavoid;
+      rem_sndavoid	= tcp_maerts_response->so_sndavoid;
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lsr_size,rss_size)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(recv_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: send_tcp_maerts: data socket connect failed");
+      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 maerts 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 */
+      if (!no_control) {
+	/* this is a netperf to netserver test, netserver will close
+	   to tell us the test is over, so use PAD_TIME to avoid
+	   causing the netserver fits. */
+	start_timer(test_time + PAD_TIME);
+      }
+      else {
+	/* this is a netperf to data source test, no PAD_TIME */
+	start_timer(test_time);
+      }
+    }
+    else {
+      /* The tester wanted to recv a number of bytes. we don't do that 
+	 in a TCP_MAERTS test. sorry. raj 2002-06-21 */
+      printf("netperf: send_tcp_maerts: test must be timed\n");
+      exit(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
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+    /* before we start, initialize a few variables */
+
+#ifdef WANT_DEMO
+    if (demo_mode) {
+      HIST_timestamp(demo_one_ptr);
+    }
+#endif
+
+    /* the test will continue until we either get a zero-byte recv()
+       on the socket or our failsafe timer expires. most of the time
+       we trust that we get a zero-byte recieve from the socket. raj
+       2002-06-21 */
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      /* timestamp just before we go into recv and then again just
+	 after we come out raj 8/94 */
+      /* but only if we are actually going to display a histogram. raj
+	 2006-02-07 */
+      HIST_timestamp(&time_one);
+    }
+#endif /* WANT_HISTOGRAM */
+    
+    while ((!times_up) && (len=recv(recv_socket,
+				    recv_ring->buffer_ptr,
+				    recv_size,
+				    0)) > 0 ) {
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp the exit from the recv call and update the histogram */
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */      
+
+#ifdef DIRTY
+      access_buffer(recv_ring->buffer_ptr,
+		    recv_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+#endif /* DIRTY */
+
+#ifdef WANT_DEMO
+      DEMO_STREAM_INTERVAL(len);
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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 recv width, and use that to calculate the offset to add */
+      /* to the base pointer. */
+      nummessages++;          
+      recv_ring = recv_ring->next;
+      if (bytes_remaining) {
+	bytes_remaining -= len;
+      }
+
+      local_bytes_recvd += len;
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* make sure we timestamp just before we go into recv  */
+	/* raj 2004-06-15 */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+    
+    }
+
+    /* an EINTR is to be expected when this is a no_control test */
+    if (((len < 0) || SOCKET_EINTR(len)) && (!no_control)) {
+      perror("send_tcp_maerts: data recv error");
+      printf("len was %d\n",len);
+      exit(1);
+    }
+    
+    /* if we get here, it must mean we had a recv return of 0 before
+       the watchdog timer expired, or the watchdog timer expired and
+       this was a no_control test */
+
+    /* The test is over. Flush the buffers to the remote end. We do a
+       graceful release to tell the  remote we have all the data. */  
+
+    /* 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_tcp_info(recv_socket,&tcp_mss);
+    }
+    
+    if (shutdown(recv_socket,SHUT_WR) == SOCKET_ERROR) {
+      perror("netperf: cannot shutdown tcp maerts socket");
+      exit(1);
+    }
+
+    stop_timer();
+    
+    /* this call will always give us the local 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+
+    close(recv_socket);
+
+    if (!no_control) {
+      /* 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);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	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 maerts 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 recv_size, so we
+	 really didn't recv what he asked for ;-) */
+    
+      bytes_sent	= ntohd(tcp_maerts_result->bytes_sent);
+    }
+    else {
+      bytes_sent = (double)local_bytes_recvd;
+    }
+
+
+    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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= tcp_maerts_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      tcp_maerts_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(tcp_maerts_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      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 recvs */
+	      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      lsr_size, 		/* local recvbuf size */
+	      rss_size, 		/* remot sendbuf size */
+	      send_size,		/* how large were the recvs */
+	      elapsed_time, 		/* how long did it take */
+	      thruput,                  /* how fast did it go */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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_recv_align,
+	    remote_recv_align,
+	    local_recv_offset,
+	    remote_recv_offset,
+	    bytes_sent,
+	    bytes_sent / (double)nummessages,
+	    nummessages,
+	    bytes_sent / (double)tcp_maerts_result->send_calls,
+	    tcp_maerts_result->send_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    tcp_mss);
+    fflush(where);
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\n\nHistogram of time spent in recv() call.\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+  }
+  
+}
+
+
+
+#ifdef HAVE_ICSC_EXS
+
+#include <sys/exs.h>
+
+
+/* This routine implements the TCP unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+void
+send_exs_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;
+
+    /* 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. */
+
+    struct ring_elt *send_ring;
+
+    int len;
+    unsigned int nummessages = 0;
+    SOCKET send_socket;
+    int bytes_remaining;
+    int tcp_mss = -1;  /* possibly uninitialized on printf far below */
+
+    exs_mhandle_t exs_mhandle;
+    exs_qhandle_t exs_qhandle;
+#define NETPERF_EXS_PENDING  16
+    int exs_aio_pending;
+    int exs_aio_eagain;
+    int exs_aio_dequeued;
+    int exs_aio_dequeuecnt;
+    int exs_evtcnt;
+#define NETPERF_EXS_QSIZE    128
+    exs_event_t exs_evtvec[NETPERF_EXS_QSIZE];
+
+    /* 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 = 0.0;
+
+    float   local_cpu_utilization;
+    float   local_service_demand;
+    float   remote_cpu_utilization;
+    float   remote_service_demand;
+
+    double   thruput;
+
+    struct addrinfo *remote_res;
+    struct addrinfo *local_res;
+
+    struct   tcp_stream_request_struct   *tcp_stream_request;
+    struct   tcp_stream_response_struct   *tcp_stream_response;
+    struct   tcp_stream_results_struct   *tcp_stream_result;
+
+    tcp_stream_request  =
+        (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+    tcp_stream_response =
+        (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+    tcp_stream_result   =
+        (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+
+#if 0 /* def 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. */
+
+    /* complete_addrinfos will either succede or exit the process */
+    complete_addrinfos(&remote_res,
+                       &local_res,
+                       remote_host,
+                       SOCK_STREAM,
+                       IPPROTO_TCP,
+                       0);
+
+    if ( print_headers ) {
+        print_top_test_header("EXS TCP STREAM TEST",local_res,remote_res);
+    }
+
+    send_ring = NULL;
+    confidence_iteration = 1;
+    init_stat();
+
+    /* initialize EXS API and create event queue */
+    if (exs_init (EXS_VERSION) == -1) {
+        perror ("netperf: send_exs_tcp_stream: exs_init failed");
+        exit (1);
+    }
+
+    if ((exs_qhandle = exs_qcreate (NETPERF_EXS_QSIZE)) == EXS_QHANDLE_INVALID) {
+        perror ("netperf: send_exs_tcp_stream: exs_qcreate failed");
+        exit (1);
+    }
+    if (debug) {
+        fprintf (where, "send_exs_tcp_stream: qhandle=%d\n", exs_qhandle);
+    }
+
+    /* 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_data_socket(local_res);
+
+        if (send_socket == INVALID_SOCKET){
+            perror("netperf: send_tcp_stream: tcp stream data socket");
+            exit(1);
+        }
+
+        if (debug) {
+            fprintf(where,"send_tcp_stream: send_socket obtained...\n");
+        }
+
+        /* 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_exs_buffer_ring(send_width,
+                                                 send_size,
+                                                 local_send_align,
+                                                 local_send_offset,
+                                                 &exs_mhandle);
+        }
+
+        /* 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_TCP_STREAM;
+        tcp_stream_request->send_buf_size   =   rss_size_req;
+        tcp_stream_request->recv_buf_size   =   rsr_size_req;
+        tcp_stream_request->receive_size   =   recv_size;
+        tcp_stream_request->no_delay   =   rem_nodelay;
+        tcp_stream_request->recv_alignment   =   remote_recv_align;
+        tcp_stream_request->recv_offset   =   remote_recv_offset;
+        tcp_stream_request->measure_cpu   =   remote_cpu_usage;
+        tcp_stream_request->cpu_rate   =   remote_cpu_rate;
+        if (test_time) {
+            tcp_stream_request->test_length   =   test_time;
+        }
+        else {
+            tcp_stream_request->test_length   =   test_bytes;
+        }
+        tcp_stream_request->so_rcvavoid   =   rem_rcvavoid;
+        tcp_stream_request->so_sndavoid   =   rem_sndavoid;
+#ifdef DIRTY
+        tcp_stream_request->dirty_count     =       rem_dirty_count;
+        tcp_stream_request->clean_count     =       rem_clean_count;
+#endif /* DIRTY */
+        tcp_stream_request->port            =    atoi(remote_data_port);
+        tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
+        if (debug > 1) {
+            fprintf(where,
+                    "netperf: send_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         =   tcp_stream_response->recv_buf_size;
+            rss_size         =   tcp_stream_response->send_buf_size;
+            rem_nodelay     =   tcp_stream_response->no_delay;
+            remote_cpu_usage=   tcp_stream_response->measure_cpu;
+            remote_cpu_rate = tcp_stream_response->cpu_rate;
+
+            /* we have to make sure that the server port number is in */
+            /* network order */
+            set_port_number(remote_res,(short)tcp_stream_response->data_port_number);
+
+            rem_rcvavoid   = tcp_stream_response->so_rcvavoid;
+            rem_sndavoid   = tcp_stream_response->so_sndavoid;
+        }
+        else {
+            Set_errno(netperf_response.content.serv_errno);
+            fprintf(where,
+                    "netperf: remote error %d",
+                    netperf_response.content.serv_errno);
+            perror("");
+            fflush(where);
+
+            exit(1);
+        }
+
+#if 0 /* def WANT_DEMO */
+        DEMO_STREAM_SETUP(lss_size,rsr_size)
+#endif
+
+            /*Connect up to the remote port on the data socket  */
+            if (connect(send_socket,
+                        remote_res->ai_addr,
+                        remote_res->ai_addrlen) == INVALID_SOCKET){
+                perror("netperf: send_tcp_stream: data socket connect failed");
+                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);
+
+#if 0 /* def WANT_INTERVALS */
+	INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+        /* before we start, initialize a few variables */
+
+#if 0 /* def WANT_DEMO */
+        if (demo_mode) {
+            HIST_timestamp(demo_one_ptr);
+        }
+#endif
+
+
+        /* 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. */
+
+        exs_aio_pending = 0;
+        exs_aio_eagain = 0;
+        exs_aio_dequeuecnt = 0;
+
+        while ((!times_up) || (bytes_remaining > 0)) {
+
+#ifdef DIRTY
+	  access_buffer(send_ring->buffer_ptr,
+			send_size,
+			loc_dirty_count,
+			loc_clean_count);
+#endif /* DIRTY */
+
+#if 0 /* def 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 */
+
+
+            /* post up to NETPERF_EXS_PENDING I/Os  */
+            while ((exs_aio_pending < NETPERF_EXS_PENDING) &&
+                   (exs_send (send_socket, send_ring->buffer_ptr, send_size,
+                              0, exs_qhandle, (exs_ahandle_t)-1, exs_mhandle) == 0)) {
+                exs_aio_pending++;
+
+                /* 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;
+                }
+            }
+
+            /* check exs_send result */
+            if (exs_aio_pending < NETPERF_EXS_PENDING) {
+               /* standard flow control case */
+                if (errno == EAGAIN)
+                    exs_aio_eagain++;
+                /* case of times_up */
+                else if (errno == EINTR)
+                    break;
+                /* strange, let's stop */
+                else {
+                    perror ("netperf: exs_send error");
+                    exit (1);
+                }
+            }
+
+            /* dequeue events with "threshold" on 1/2 posted */
+            exs_aio_dequeued =
+                exs_qdequeue (exs_qhandle, exs_evtvec,
+                              -(exs_aio_pending>>1), NULL);
+            exs_aio_dequeuecnt++;
+
+            /* check exs_dequeue result */
+            if (exs_aio_dequeued < 0) {
+                /* case of times_up */
+                if (errno == EINTR)
+                    break;
+                /* strange, let's stop */
+                else {
+                    perror ("netperf: exs_send error");
+                    exit (1);
+                }
+            }
+            /* update number of pending I/Os */
+            else {
+                exs_aio_pending -= exs_aio_dequeued;
+            }
+
+
+#if 0 /* def 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 */
+
+#if 0 /* def WANT_DEMO */
+            DEMO_STREAM_INTERVAL(send_size);
+#endif
+
+#if 0 /* def WANT_INTERVALS */
+	    INTERVALS_WAIT();
+#endif /* WANT_INTERVALS */
+
+        }
+
+        /* Collect the last completion events */
+        exs_aio_dequeued =
+            exs_qdequeue (exs_qhandle, exs_evtvec, -exs_aio_pending, NULL);
+        exs_aio_dequeuecnt++;
+        /* check exs_dequeue result and update number of pending I/Os */
+        if (exs_aio_dequeued < 0) {
+            perror ("netperf: exs_send error");
+            exit (1);
+        }
+        exs_aio_pending -= exs_aio_dequeued;
+
+        /* Display some async I/O debug info */
+        if (debug) {
+            fprintf (where, "send_exs_tcp_stream: "
+                     "aio sent=%d eagain=%d dequeue=%d pending=%d\n",
+                     nummessages, exs_aio_eagain, exs_aio_dequeuecnt, exs_aio_pending);
+        }
+
+        /* 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_tcp_info(send_socket,&tcp_mss);
+        }
+
+        if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
+            perror("netperf: cannot shutdown tcp stream socket");
+            exit(1);
+        }
+
+        /* hang a recv() off the socket to block until the remote has */
+        /* brought all the data up into the application. it will do a */
+        /* shutdown to cause a FIN to be sent our way. We will assume that */
+        /* any exit from the recv() call is good... raj 4/93 */
+
+        recv(send_socket, send_ring->buffer_ptr, send_size, 0);
+
+        /* 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? */
+
+        /* we are finished with the socket, so close it to prevent hitting */
+        /* the limit on maximum open files. */
+
+        close(send_socket);
+
+        /* 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);
+            fprintf(where,
+                    "netperf: remote error %d",
+                    netperf_response.content.serv_errno);
+            perror("");
+            fflush(where);
+
+            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   = ntohd(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   = (float) -1.0;
+                local_service_demand   = (float) -1.0;
+            }
+
+            if (remote_cpu_usage) {
+
+                remote_cpu_utilization   = tcp_stream_result->cpu_util;
+                remote_service_demand   = calc_service_demand(bytes_sent,
+                                                              0.0,
+                                                              remote_cpu_utilization,
+                                                              tcp_stream_result->num_cpus);
+            }
+            else {
+                remote_cpu_utilization = (float) -1.0;
+                remote_service_demand  = (float) -1.0;
+            }
+        }
+        else {
+            /* we were not measuring cpu, for the confidence stuff, we */
+            /* should make it -1.0 */
+            local_cpu_utilization   = (float) -1.0;
+            local_service_demand   = (float) -1.0;
+            remote_cpu_utilization = (float) -1.0;
+            remote_service_demand  = (float) -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(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)tcp_stream_result->recv_calls,
+                tcp_stream_result->recv_calls);
+        fprintf(where,
+                ksink_fmt2,
+                tcp_mss);
+        fflush(where);
+#if 0 /* def WANT_HISTOGRAM */
+        fprintf(where,"\n\nHistogram of time spent in send() call.\n");
+        fflush(where);
+        HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+    }
+
+}
+
+#endif /* HAVE_ICSC_EXS */
+
+
+
+#if defined(HAVE_SENDFILE) 
+
+#if defined(QUICK_SENDPATH)
+
+/*
+ * a temporary stub for the sendpath() system call
+ * which is defined & implemented in the kernel
+ * but which has no libc stub.
+ */
+#include <sys/types.h>
+#include <sys/scall_define.h>
+#include <sys/uio.h>
+
+ssize_t
+sendpath(int s, char *path, off_t offset, size_t nbytes,
+	 const struct iovec *hdtrl, int flags)
+  {
+    return syscall(SYS_sendpath, s, path, offset, nbytes, hdtrl, flags);
+  }
+#endif /* QUICK_SENDPATH */
+
+/* This routine implements the TCP unidirectional data transfer test
+   (a.k.a. stream) for the sockets interface using the sendfile()
+   system call - TCP_SENDFILE.  It receives its  parameters via global
+   variables from the shell and writes its  output to the standard
+   output. Basically,  this is the same test as the send_tcp_stream()
+   logic and we even tell the remote to do a TCP_STREAM test since for 
+   all it knows, nothig is different. */
+
+void 
+sendfile_tcp_stream(remote_host)
+     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;
+  
+  /* 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. */
+  
+  struct sendfile_ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  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 = 0.0;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct  addrinfo *remote_res;
+  struct  addrinfo *local_res;
+  struct	sockaddr_in	server;
+
+#if defined(__linux) || defined(__sun__)
+  off_t     scratch_offset;   /* the linux sendfile() call will update
+				 the offset variable, which is
+				 something we do _not_ want to happen
+				 to the value in the send_ring! so, we
+				 have to use a scratch variable. */
+#endif /* __linux  || defined(__sun__) */
+#if defined (USE_OSX)
+   off_t    scratch_len;  /* Darwin 9.x need a value-result parameter  */
+#endif
+#if defined (__sun__)
+   size_t  scratch_len;	/* the sun sendfilev() needs a place to 
+			   tell us how many bytes were written,
+			   even though it also returns the value */
+   sendfilevec_t sv;
+#endif /* __sun__ */
+  
+  struct	tcp_stream_request_struct	*tcp_stream_request;
+  struct	tcp_stream_response_struct	*tcp_stream_response;
+  struct	tcp_stream_results_struct	*tcp_stream_result;
+
+  tcp_stream_request  = 
+    (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+  tcp_stream_response =
+    (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+  tcp_stream_result   = 
+    (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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));
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  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 */
+#ifdef QUICK_SENDPATH
+    print_top_test_header("TCP SENDPATH TEST",local_res,remote_res);
+#else
+    print_top_test_header("TCP SENDFILE TEST",local_res,remote_res);
+#endif /* QUICK_SENDPATH */
+  }
+  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_data_socket(local_res);
+
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: sendfile_tcp_stream: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"sendfile_tcp_stream: send_socket obtained...\n");
+    }
+    
+#if defined(TCP_CORK)
+    /* should this even be here?!? */
+    if (loc_tcpcork != 0) {
+      /* the user wishes for us to set TCP_CORK on the socket */
+      int one = 1;
+      if (setsockopt(send_socket,
+		     getprotobyname("tcp")->p_proto,
+		     TCP_CORK,
+		     (char *)&one,
+		     sizeof(one)) == SOCKET_ERROR) {
+	perror("netperf: sendfile_tcp_stream: tcp_cork");
+	exit(1);
+      }
+      if (debug) {
+	fprintf(where,"sendfile_tcp_stream: tcp_cork...\n");
+      }
+    }
+    
+#endif /* TCP_CORK */    
+
+    /* 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... */
+
+    /*check for file size/ min file size here?  create file here/ back out???*/
+    
+    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... */ 
+
+    /*sendring -> an offset index that will shift the starting point of the*/
+    /*section of the file sent throughout the file*/
+    
+    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 = alloc_sendfile_buf_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_TCP_STREAM;
+    tcp_stream_request->send_buf_size	=	rss_size_req;
+    tcp_stream_request->recv_buf_size	=	rsr_size_req;
+    tcp_stream_request->receive_size	=	recv_size;
+    tcp_stream_request->no_delay	=	rem_nodelay;
+    tcp_stream_request->recv_alignment	=	remote_recv_align;
+    tcp_stream_request->recv_offset	=	remote_recv_offset;
+    tcp_stream_request->measure_cpu	=	remote_cpu_usage;
+    tcp_stream_request->cpu_rate	=	remote_cpu_rate;
+
+    if (test_time) {
+      tcp_stream_request->test_length	=	test_time;
+    }
+    else {
+      tcp_stream_request->test_length	=	test_bytes;
+    }
+
+    tcp_stream_request->so_rcvavoid	=	rem_rcvavoid;
+    tcp_stream_request->so_sndavoid	=	rem_sndavoid;
+
+#ifdef DIRTY
+    tcp_stream_request->dirty_count       =       rem_dirty_count;
+    tcp_stream_request->clean_count       =       rem_clean_count;
+#endif /* DIRTY */
+    tcp_stream_request->port     = atoi(remote_data_port);
+    tcp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
+
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: send_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	      =	tcp_stream_response->recv_buf_size;
+      rss_size	      =	tcp_stream_response->send_buf_size;
+      rem_nodelay     =	tcp_stream_response->no_delay;
+      remote_cpu_usage=	tcp_stream_response->measure_cpu;
+      remote_cpu_rate = tcp_stream_response->cpu_rate;
+
+      /* we have to make sure that the server port number is in */
+      /* network order */
+      set_port_number(remote_res,(short)tcp_stream_response->data_port_number);
+      rem_rcvavoid	= tcp_stream_response->so_rcvavoid;
+      rem_sndavoid	= tcp_stream_response->so_sndavoid;
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      exit(1);
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lss_size,rsr_size)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: send_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
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+   
+    /* before we start, initialize a few variables */
+
+#ifdef WANT_DEMO
+    if (demo_mode) {
+      HIST_timestamp(demo_one_ptr);
+    }
+#endif
+
+    /* 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)) {
+      
+      /* the sendfile_tcp_stream test does not support making the buffers
+	 dirty. 08/2000 */
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp just before we go into sendfile() and then again
+         just after we come out raj 08/2000 */
+	/* but only if we are actually going to display a histogram */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+      
+      /* you can look at netlib.h for a description of the fields we
+	 are passing to sendfile(). 08/2000 */
+#ifdef QUICK_SENDPATH
+      if ((len=sendpath(send_socket, 
+			fill_file,
+			send_ring->offset,
+			send_ring->length,
+			send_ring->hdtrl,
+			send_ring->flags)) != send_size)
+#elif defined(__linux)
+	scratch_offset = send_ring->offset;
+      if ((len=sendfile(send_socket, 
+			send_ring->fildes, 
+			&scratch_offset,   /* modified after the call! */
+			send_ring->length)) != send_size)
+#elif defined (__sun__)
+      /* We must call with SFV_NOWAIT and a large file size (>= 16MB) to
+	 get zero-copy, as well as compiling with  -D_LARGEFILE_SOURCE
+	  -D_FILE_OFFSET_BITS=64 */
+      sv.sfv_fd = send_ring->fildes;
+      sv.sfv_flag = SFV_NOWAIT;
+      sv.sfv_off = send_ring->offset;
+      sv.sfv_len =  send_ring->length;
+      if ((len = sendfilev(send_socket, &sv, 1, &scratch_len)) != send_size)
+#elif defined(__FreeBSD__)
+	/* so close to HP-UX and yet so far away... :) */
+	if ((sendfile(send_ring->fildes, 
+		      send_socket, 
+		      send_ring->offset,
+		      send_ring->length,
+		      NULL,
+		      (off_t *)&len,
+		      send_ring->flags) != 0) ||
+	    (len != send_size))
+#elif defined(USE_OSX)
+    scratch_len = send_ring->length;
+    if ((sendfile(send_ring->fildes,
+              send_socket,
+              send_ring->offset,
+              (off_t *)&scratch_len,
+              NULL,
+              send_ring->flags) != 0) ||
+        (scratch_len != send_size))
+#else /* original sendile HP-UX */
+	  if ((len=sendfile(send_socket, 
+			    send_ring->fildes, 
+			    send_ring->offset,
+			    send_ring->length,
+			    send_ring->hdtrl,
+			    send_ring->flags)) != send_size)
+#endif /* QUICK_SENDPATH */
+	    {
+	      /* the test was interrupted, must be the end of test. the
+		 send_tcp_stream code has some WIN32 ifdefs that we do not
+		 need here. */
+	      if ((len >=0) || SOCKET_EINTR(len)) {
+		break;
+	      }
+	      perror("netperf: data send error: sendfile");
+	      fprintf(stderr,
+		      "len was %d send_size was %d\n",
+		      len,
+		      send_size);
+	      fflush(stderr);
+	      exit(1);
+	    }
+      
+      /*	offset += len;*/
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* 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_DEMO
+      DEMO_STREAM_INTERVAL(send_size);
+#endif 
+  
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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_tcp_info(send_socket,&tcp_mss);
+    }
+    
+    if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
+      perror("netperf: cannot shutdown tcp stream socket");
+      exit(1);
+    }
+    
+    /* hang a recv() off the socket to block until the remote has */
+    /* brought all the data up into the application. it will do a */
+    /* shutdown to cause a FIN to be sent our way. We will assume that */
+    /* any exit from the recv() call is good... raj 4/93 */
+
+    /* since we are using sendfile() instead of send, we have no
+       scratch buffer from the send_ring to use for the
+       receive. however, since we "know" that the recv should be
+       returning zero bytes (not that we are making the checks we
+       should) we can pass the address of the flags field. raj 08/2000 
+    */
+
+    recv(send_socket,
+	 &(send_ring->flags), 
+	 sizeof(send_ring->flags),
+	 0);
+    
+    /* 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+
+    close(send_socket);
+
+    /* 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);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      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	= ntohd(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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= tcp_stream_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      tcp_stream_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(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)tcp_stream_result->recv_calls,
+	    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 */
+  }
+}
+
+#endif /* HAVE_SENDFILE */
+
+/* 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_tcp_stream()
+{
+  
+  struct sockaddr_storage myaddr_in, peeraddr_in;
+  SOCKET s_listen,s_data;
+  netperf_socklen_t addrlen;
+  int	len;
+  unsigned int	receive_calls;
+  float	elapsed_time;
+  double   bytes_received;
+  
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+#ifdef DO_SELECT
+  fd_set readfds;
+  struct timeval timeout;
+#endif /* DO_SELECT */
+
+  struct	tcp_stream_request_struct	*tcp_stream_request;
+  struct	tcp_stream_response_struct	*tcp_stream_response;
+  struct	tcp_stream_results_struct	*tcp_stream_results;
+  
+#ifdef DO_SELECT
+  FD_ZERO(&readfds);
+  timeout.tv_sec = 1;
+  timeout.tv_usec = 0;
+#endif /* DO_SELECT */
+
+  tcp_stream_request	= 
+    (struct tcp_stream_request_struct *)netperf_request.content.test_specific_data;
+  tcp_stream_response	= 
+    (struct tcp_stream_response_struct *)netperf_response.content.test_specific_data;
+  tcp_stream_results	= 
+    (struct tcp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_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_tcp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_STREAM_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_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_tcp_stream: requested alignment of %d\n",
+	    tcp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_stream_request->send_buf_size;
+  lsr_size_req = tcp_stream_request->recv_buf_size;
+  loc_nodelay  = tcp_stream_request->no_delay;
+  loc_rcvavoid = tcp_stream_request->so_rcvavoid;
+  loc_sndavoid = tcp_stream_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_stream_request->ipfamily),
+			tcp_stream_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_stream_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+  
+  /* what sort of sizes did we end-up with? */
+  if (tcp_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = 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,
+				   tcp_stream_request->recv_alignment,
+				   tcp_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_tcp_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  tcp_stream_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&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. */
+  
+  tcp_stream_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (tcp_stream_request->measure_cpu) {
+    tcp_stream_response->measure_cpu = 1;
+    tcp_stream_response->cpu_rate = 
+      calibrate_local_cpu(tcp_stream_request->cpu_rate);
+  }
+  else {
+    tcp_stream_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_stream_response->send_buf_size = lss_size;
+  tcp_stream_response->recv_buf_size = lsr_size;
+  tcp_stream_response->no_delay = loc_nodelay;
+  tcp_stream_response->so_rcvavoid = loc_rcvavoid;
+  tcp_stream_response->so_sndavoid = loc_sndavoid;
+  tcp_stream_response->receive_size = recv_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  if ((s_data=accept(s_listen,
+		     (struct sockaddr *)&peeraddr_in,
+		     &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(tcp_stream_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  /* there used to be an #ifdef DIRTY call to access_buffer() here,
+     but we have switched from accessing the buffer before the recv()
+     call to accessing the buffer after the recv() call.  The
+     accessing before was, IIRC, related to having dirty data when
+     doing page-flipping copy avoidance. */
+
+  bytes_received = 0;
+  receive_calls  = 0;
+
+  while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
+    if (len == SOCKET_ERROR )
+	{
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    bytes_received += len;
+    receive_calls++;
+
+#ifdef DIRTY
+    /* we access the buffer after the recv() call now, rather than before */
+    access_buffer(recv_ring->buffer_ptr,
+		  recv_size,
+		  tcp_stream_request->dirty_count,
+		  tcp_stream_request->clean_count);
+#endif /* DIRTY */
+
+
+    /* move to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+
+#ifdef PAUSE
+    sleep(1);
+#endif /* PAUSE */
+
+#ifdef DO_SELECT
+	FD_SET(s_data,&readfds);
+	select(s_data+1,&readfds,NULL,NULL,&timeout);
+#endif /* DO_SELECT */
+
+  }
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+  
+  cpu_stop(tcp_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_stream: got %g bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_tcp_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  tcp_stream_results->bytes_received	= htond(bytes_received);
+  tcp_stream_results->elapsed_time	= elapsed_time;
+  tcp_stream_results->recv_calls	= receive_calls;
+  
+  tcp_stream_results->cpu_method = cpu_method;
+  tcp_stream_results->num_cpus   = lib_num_loc_cpus;
+  
+  if (tcp_stream_request->measure_cpu) {
+    tcp_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_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);
+  }
+
+  send_response();
+
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  }
+
+/* This is the server-side routine for the tcp maerts test. It is
+   implemented as one routine. I could break things-out somewhat, but
+   didn't feel it was necessary. */ 
+
+void
+recv_tcp_maerts()
+{
+  
+  struct sockaddr_storage myaddr_in, peeraddr_in;
+  struct addrinfo *local_res;
+  char  local_name[BUFSIZ];
+  char  port_buffer[PORTBUFSIZE];
+
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	addrlen;
+  int	len;
+  unsigned int	send_calls;
+  float	elapsed_time;
+  double   bytes_sent = 0.0 ;
+  
+  struct ring_elt *send_ring;
+
+  struct	tcp_maerts_request_struct	*tcp_maerts_request;
+  struct	tcp_maerts_response_struct	*tcp_maerts_response;
+  struct	tcp_maerts_results_struct	*tcp_maerts_results;
+  
+  tcp_maerts_request	= 
+    (struct tcp_maerts_request_struct *)netperf_request.content.test_specific_data;
+  tcp_maerts_response	= 
+    (struct tcp_maerts_response_struct *)netperf_response.content.test_specific_data;
+  tcp_maerts_results	= 
+    (struct tcp_maerts_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_tcp_maerts: 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_tcp_maerts: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_MAERTS_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_maerts: 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_tcp_maerts: requested alignment of %d\n",
+	    tcp_maerts_request->send_alignment);
+    fflush(where);
+  }
+
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_maerts: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  /* create_data_socket 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_req = tcp_maerts_request->send_buf_size;
+  lsr_size_req = tcp_maerts_request->recv_buf_size;
+  loc_nodelay = tcp_maerts_request->no_delay;
+  loc_rcvavoid = tcp_maerts_request->so_rcvavoid;
+  loc_sndavoid = tcp_maerts_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_maerts_request->ipfamily),
+			tcp_maerts_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_maerts_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+  
+  /* what sort of sizes did we end-up with? */
+  if (tcp_maerts_request->send_size == 0) {
+    if (lss_size > 0) {
+      send_size = lss_size;
+    }
+    else {
+      send_size = 4096;
+    }
+  }
+  else {
+    send_size = tcp_maerts_request->send_size;
+  }
+  
+  /* we want to set-up our recv_ring in a manner analagous to what we */
+  /* do on the recving 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 (send_width == 0) {
+    send_width = (lsr_size/send_size) + 1;
+    if (send_width == 1) send_width++;
+  }
+
+  send_ring = allocate_buffer_ring(send_width,
+				   send_size,
+				   tcp_maerts_request->send_alignment,
+				   tcp_maerts_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_tcp_maerts: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  tcp_maerts_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&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. */
+  
+  tcp_maerts_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (tcp_maerts_request->measure_cpu) {
+    tcp_maerts_response->measure_cpu = 1;
+    tcp_maerts_response->cpu_rate = 
+      calibrate_local_cpu(tcp_maerts_request->cpu_rate);
+  }
+  else {
+    tcp_maerts_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_maerts_response->send_buf_size = lss_size;
+  tcp_maerts_response->recv_buf_size = lsr_size;
+  tcp_maerts_response->no_delay = loc_nodelay;
+  tcp_maerts_response->so_rcvavoid = loc_rcvavoid;
+  tcp_maerts_response->so_sndavoid = loc_sndavoid;
+  tcp_maerts_response->send_size = send_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+
+  /* we will start the timer before the accept() to be somewhat
+     analagous to the starting of the timer before the connect() call
+     in the TCP_STREAM test. raj 2002-06-21 */
+
+  start_timer(tcp_maerts_request->test_length);
+
+  /* Now it's time to start receiving data on the connection. We will
+     first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(tcp_maerts_request->measure_cpu);
+  
+
+  if ((s_data=accept(s_listen,
+		     (struct sockaddr *)&peeraddr_in,
+		     &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  
+  /* this is for those systems which *INCORRECTLY* fail to pass
+     attributes across an accept() call. Including this goes against
+     my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  bytes_sent = 0.0;
+  send_calls  = 0;
+
+  len = 0;   /* nt-lint; len is not initialized (printf far below) if
+		times_up initially true.*/
+  times_up = 0; /* must remember to initialize this little beauty */
+  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,
+		tcp_maerts_request->dirty_count,
+		tcp_maerts_request->clean_count);
+
+#endif /* DIRTY */
+
+    if((len=send(s_data,
+		 send_ring->buffer_ptr,
+		 send_size,
+		 0)) != send_size) {
+		if ((len >=0) || SOCKET_EINTR(len)) {
+	      /* the test was interrupted, must be the end of test */
+	      break;
+		}
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+
+    bytes_sent += len;
+    send_calls++;
+
+    /* more to the next buffer in the send_ring */
+    send_ring = send_ring->next;
+
+  }
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+
+  /* hang a recv() off the socket to block until the remote has
+     brought all the data up into the application. it will do a
+     shutdown to cause a FIN to be sent our way. We will assume that
+     any exit from the recv() call is good... raj 4/93 */
+    
+  recv(s_data, send_ring->buffer_ptr, send_size, 0);
+    
+  
+  cpu_stop(tcp_maerts_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_maerts: got %g bytes\n",
+	    bytes_sent);
+    fprintf(where,
+	    "recv_tcp_maerts: got %d sends\n",
+	    send_calls);
+    fflush(where);
+  }
+  
+  tcp_maerts_results->bytes_sent	= htond(bytes_sent);
+  tcp_maerts_results->elapsed_time	= elapsed_time;
+  tcp_maerts_results->send_calls	= send_calls;
+  
+  if (tcp_maerts_request->measure_cpu) {
+    tcp_maerts_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_maerts: test complete, sending results.\n");
+    fprintf(where,
+	    "                 bytes_sent %g send_calls %d\n",
+	    bytes_sent,
+	    send_calls);
+    fprintf(where,
+	    "                 len %d\n",
+	    len);
+    fflush(where);
+  }
+  
+  tcp_maerts_results->cpu_method = cpu_method;
+  tcp_maerts_results->num_cpus   = lib_num_loc_cpus;
+  send_response();
+
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  }
+
+
+ /* this routine implements the sending (netperf) side of the TCP_RR */
+ /* test. */
+
+void
+send_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_title_band = "\
+Local /Remote\n\
+Socket Size   Request  Resp.   Elapsed  \n\
+Send   Recv   Size     Size    Time     Throughput \n\
+bytes  Bytes  bytes    bytes   secs.    %s/sec   \n\n";
+
+  char *tput_fmt_0 =
+    "%7.2f %s\n";
+  
+  char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   %s\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_title_tput = "\
+Local /Remote\n\
+Socket Size   Request Resp.  Elapsed Tput     CPU    CPU    S.dem   S.dem\n\
+Send   Recv   Size    Size   Time    %-8.8s 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 %s\n";
+  
+  char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f %s\n";
+  
+  char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+  
+  char *ksink_fmt = "\
+Alignment      Offset         RoundTrip  Trans    Throughput\n\
+Local  Remote  Local  Remote  Latency    Rate     %-8.8s/s\n\
+Send   Recv    Send   Recv    usec/Tran  per sec  Outbound   Inbound\n\
+%5d  %5d   %5d  %5d   %-6.3f   %-6.3f %-6.3f    %-6.3f\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 addrinfo *local_res;
+  struct addrinfo *remote_res;
+
+  struct	tcp_rr_request_struct	*tcp_rr_request;
+  struct	tcp_rr_response_struct	*tcp_rr_response;
+  struct	tcp_rr_results_struct	*tcp_rr_result;
+
+#ifdef WANT_FIRST_BURST
+#define REQUEST_CWND_INITIAL 2
+  /* "in the beginning..." the WANT_FIRST_BURST stuff was like both
+     Unix and the state of New Jersey - both were simple an unspoiled.
+     then it was realized that some stacks are quite picky about
+     initial congestion windows and a non-trivial initial burst of
+     requests would not be individual segments even with TCP_NODELAY
+     set. so, we have to start tracking a poor-man's congestion window
+     up here in window space because we want to try to make something
+     happen that frankly, we cannot guarantee with the specification
+     of TCP.  ain't that grand?-)  raj 2006-01-30 */
+  int requests_outstanding = 0;
+  int request_cwnd = REQUEST_CWND_INITIAL;  /* we ass-u-me that having
+					       three requests
+					       outstanding at the
+					       beginning of the test
+					       is ok with TCP stacks
+					       of interest. the first
+					       two will come from our
+					       first_burst loop, and
+					       the third from our
+					       regularly scheduled
+					       send */
+#endif
+
+  tcp_rr_request = 
+    (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_rr_response=
+    (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_rr_result	=
+    (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("TCP REQUEST/RESPONSE TEST",local_res,remote_res);
+  }
+  
+  /* 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;
+
+#ifdef WANT_FIRST_BURST
+    /* we have to remember to reset the number of transactions
+       outstanding and the "congestion window for each new
+       iteration. raj 2006-01-31 */
+    requests_outstanding = 0;
+    request_cwnd = REQUEST_CWND_INITIAL;
+#endif
+
+
+    /* 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_data_socket(local_res);
+  
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_tcp_rr: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_tcp_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);
+    }
+    
+    if (!no_control) {
+      /* 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_TCP_RR;
+      tcp_rr_request->recv_buf_size	=	rsr_size_req;
+      tcp_rr_request->send_buf_size	=	rss_size_req;
+      tcp_rr_request->recv_alignment    =	remote_recv_align;
+      tcp_rr_request->recv_offset	=	remote_recv_offset;
+      tcp_rr_request->send_alignment    =	remote_send_align;
+      tcp_rr_request->send_offset	=	remote_send_offset;
+      tcp_rr_request->request_size	=	req_size;
+      tcp_rr_request->response_size	=	rsp_size;
+      tcp_rr_request->no_delay	        =	rem_nodelay;
+      tcp_rr_request->measure_cpu	=	remote_cpu_usage;
+      tcp_rr_request->cpu_rate	        =	remote_cpu_rate;
+      tcp_rr_request->so_rcvavoid	=	rem_rcvavoid;
+      tcp_rr_request->so_sndavoid	=	rem_sndavoid;
+      if (test_time) {
+	tcp_rr_request->test_length	=	test_time;
+      }
+      else {
+	tcp_rr_request->test_length	=	test_trans * -1;
+      }
+      tcp_rr_request->port              =      atoi(remote_data_port);
+      tcp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
+      
+      if (debug > 1) {
+	fprintf(where,"netperf: send_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          = tcp_rr_response->recv_buf_size;
+	rss_size          = tcp_rr_response->send_buf_size;
+	rem_nodelay       = tcp_rr_response->no_delay;
+	remote_cpu_usage  = tcp_rr_response->measure_cpu;
+	remote_cpu_rate   = tcp_rr_response->cpu_rate;
+	/* make sure that port numbers are in network order */
+	set_port_number(remote_res,(short)tcp_rr_response->data_port_number);
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_RR_SETUP(1000)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: data socket connect failed");
+      
+      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
+    INTERVALS_INIT();
+#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. */
+
+#ifdef WANT_DEMO
+      if (demo_mode) {
+	HIST_timestamp(demo_one_ptr);
+      }
+#endif
+
+    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_FIRST_BURST
+      /* we can inject no more than request_cwnd, which will grow with
+	 time, and no more than first_burst_size.  we don't use <= to
+	 account for the "regularly scheduled" send call.  of course
+	 that makes it more a "max_outstanding_ than a
+	 "first_burst_size" but for now we won't fix the names. also,
+	 I suspect the extra check against < first_burst_size is
+	 redundant since later I expect to make sure that request_cwnd
+	 can never get larger than first_burst_size, but just at the
+	 moment I'm feeling like a belt and suspenders kind of
+	 programmer. raj 2006-01-30 */
+      while ((first_burst_size > 0) &&
+	     (requests_outstanding < request_cwnd) &&
+	     (requests_outstanding < first_burst_size)) {
+	if (debug) {
+	  fprintf(where,
+		  "injecting, req_outstndng %d req_cwnd %d burst %d\n",
+		  requests_outstanding,
+		  request_cwnd,
+		  first_burst_size);
+	}
+	if ((len = send(send_socket,
+			send_ring->buffer_ptr,
+			req_size,
+			0)) != req_size) {
+	  /* we should never hit the end of the test in the first burst */
+	  perror("send_tcp_rr: initial burst data send error");
+	  exit(-1);
+	}
+	requests_outstanding += 1;
+      }
+
+#endif /* WANT_FIRST_BURST */
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp just before our call to send, and then again just
+	   after the receive raj 8/94 */
+	/* but only if we are actually going to display one. raj
+	   2007-02-07 */
+
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+      
+      if ((len = send(send_socket,
+		      send_ring->buffer_ptr,
+		      req_size,
+		      0)) != req_size) {
+	if (SOCKET_EINTR(len) || (errno == 0)) {
+	  /* we hit the end of a */
+	  /* timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_tcp_rr: data send error");
+	exit(1);
+      }
+      send_ring = send_ring->next;
+
+#ifdef WANT_FIRST_BURST
+      requests_outstanding += 1;
+#endif
+
+      /* 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 ( SOCKET_EINTR(rsp_bytes_recvd) ) {
+		    /* We hit the end of a timed test. */
+			timed_out = 1;
+			break;
+		}
+	  perror("send_tcp_rr: data recv error");
+	  exit(1);
+	}
+	rsp_bytes_left -= rsp_bytes_recvd;
+	temp_message_ptr  += rsp_bytes_recvd;
+      }	
+      recv_ring = recv_ring->next;
+      
+#ifdef WANT_FIRST_BURST
+      /* so, since we've gotten a response back, update the
+	 bookkeeping accordingly.  there is one less request
+	 outstanding and we can put one more out there than before. */
+      requests_outstanding -= 1;
+      if (request_cwnd < first_burst_size) {
+	request_cwnd += 1;
+	if (debug) {
+	  fprintf(where,
+		  "incr req_cwnd to %d first_burst %d reqs_outstndng %d\n",
+		  request_cwnd,
+		  first_burst_size,
+		  requests_outstanding);
+	}
+      }
+#endif
+      if (timed_out) {
+	/* we may have been in a nested while loop - we need */
+	/* another call to break. */
+	break;
+      }
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+      DEMO_RR_INTERVAL(1);
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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);
+	}
+      }
+    }
+
+    /* At this point we used to call shutdown on the data socket to be
+       sure all the data was delivered, but this was not germane in a
+       request/response test, and it was causing the tests to "hang"
+       when they were being controlled by time. So, I have replaced
+       this shutdown call with a call to close that can be found later
+       in the procedure. */
+    
+    /* 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? */
+    
+    if (!no_control) {
+      /* Get the statistics from the remote end. The remote will have
+	 calculated CPU utilization. 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);
+	fprintf(where,"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	exit(1);
+      }
+    }
+    
+    /* We now calculate what our "throughput" 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = 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,
+						    tcp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    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(tcp_rr_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	if ('x' == libfmt) {
+	  fprintf(where,
+		  cpu_title,
+		  local_cpu_method,
+		  remote_cpu_method);
+	}
+	else {
+	  fprintf(where,
+		  cpu_title_tput,
+		  format_units(),
+		  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 */
+	      ('x' == libfmt) ? thruput : 
+	      calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+					 1.0),
+	      local_cpu_utilization,	/* local cpu */
+	      remote_cpu_utilization,	/* remote cpu */
+	      local_service_demand,	/* local service demand */
+	      remote_service_demand,	/* remote service demand */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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,
+	      ('x' == libfmt) ? thruput :
+	      calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+					 1.0),
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,
+		('x' == libfmt) ? tput_title : tput_title_band,
+		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 */
+	      /* are we trans or do we need to convert to bytes then
+		 bits? at this point, thruput is in our "confident"
+		 transactions per second. we can convert to a
+		 bidirectional bitrate by multiplying that by the sum
+		 of the req_size and rsp_size.  we pass that to
+		 calc_thruput_interval_omni with an elapsed time of
+		 1.0 s to get it converted to [kmg]bits/s or
+		 [KMG]Bytes/s */
+	      ('x' == libfmt) ?  thruput : 
+	      calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+					 1.0),
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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... */
+
+    /* normally, you might think that if we were messing about with
+       the value of libfmt we would need to put it back again, but
+       since this is basically the last thing we are going to do with
+       it, it does not matter.  so there :) raj 2007-06-08 */
+    /* if the user was asking for transactions, then we report
+       megabits per sedcond for the unidirectional throughput,
+       otherwise we use the desired units. */
+    if ('x' == libfmt) {
+      libfmt = 'm';
+    }
+
+    fprintf(where,
+	    ksink_fmt,
+	    format_units(),
+	    local_send_align,
+	    remote_recv_offset,
+	    local_send_offset,
+	    remote_recv_offset,
+	    /* if the user has enable burst mode, we have to remember
+	       to account for that in the number of transactions
+	       outstanding at any one time. otherwise we will
+	       underreport the latency of individual
+	       transactions. learned from saf by raj 2007-06-08  */
+	    (((double)1.0/thruput)*(double)1000000.0) * 
+	    (double) (1+first_burst_size),
+	    thruput,
+	    calc_thruput_interval_omni(thruput * (double)req_size,1.0),
+	    calc_thruput_interval_omni(thruput * (double)rsp_size,1.0));
+
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\nHistogram of request/response times\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+
+  }
+  
+}
+
+void
+send_udp_stream(char remote_host[])
+{
+  /**********************************************************************/
+  /*									*/
+  /*               	UDP Unidirectional Send Test                    */
+  /*									*/
+  /**********************************************************************/
+
+#define UDP_LENGTH_MAX 0XFFFF - 28
+
+  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,  
+        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;
+  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;
+
+  struct addrinfo *local_res;
+  struct addrinfo *remote_res;
+  
+  struct	udp_stream_request_struct	*udp_stream_request;
+  struct	udp_stream_response_struct	*udp_stream_response;
+  struct	udp_stream_results_struct	*udp_stream_results;
+  
+  udp_stream_request	= 
+    (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
+  udp_stream_response	= 
+    (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
+  udp_stream_results	= 
+    (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_DGRAM,
+		     IPPROTO_UDP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("UDP UNIDIRECTIONAL SEND TEST",local_res,remote_res);
+  }
+
+  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_data_socket(local_res);
+    
+    if (data_socket == INVALID_SOCKET){
+      perror("udp_send: data socket");
+      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 < UDP_LENGTH_MAX ? lss_size : UDP_LENGTH_MAX);
+      }
+      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);
+    
+    if (!no_control) {
+      /* 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_UDP_STREAM;
+      udp_stream_request->recv_buf_size  = rsr_size_req;
+      udp_stream_request->message_size   = send_size;
+      udp_stream_request->recv_connected = remote_connected;
+      udp_stream_request->recv_alignment = remote_recv_align;
+      udp_stream_request->recv_offset    = remote_recv_offset;
+      udp_stream_request->measure_cpu    = remote_cpu_usage;
+      udp_stream_request->cpu_rate       = remote_cpu_rate;
+      udp_stream_request->test_length    = test_time;
+      udp_stream_request->so_rcvavoid    = rem_rcvavoid;
+      udp_stream_request->so_sndavoid    = rem_sndavoid;
+      udp_stream_request->port           = atoi(remote_data_port);
+      udp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
+      
+      send_request();
+      
+      recv_response();
+      
+      if (!netperf_response.content.serv_errno) {
+	if (debug)
+	  fprintf(where,"send_udp_stream: remote data connection done.\n");
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	perror("send_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 */
+      set_port_number(remote_res,(short)udp_stream_response->data_port_number);
+      
+      rsr_size        = udp_stream_response->recv_buf_size;
+      rss_size        = udp_stream_response->send_buf_size;
+      remote_cpu_rate = udp_stream_response->cpu_rate;
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lss_size,rsr_size)
+#endif
+
+    /* We "connect" up to the remote post to allow is to use the send */
+    /* call instead of the sendto call. Presumeably, this is a little */
+    /* simpler, and a little more efficient. I think that it also means */
+    /* that we can be informed of certain things, but am not sure */
+    /* yet...also, this is the way I would expect a client to behave */
+    /* when talking to a server */
+    if (local_connected) { 
+       if (connect(data_socket,
+      		   remote_res->ai_addr,
+		   remote_res->ai_addrlen) == INVALID_SOCKET){
+          perror("send_udp_stream: data socket connect failed");
+          exit(1);
+       } else if (debug) {
+          fprintf(where,"send_udp_stream: connected data socket.\n");
+          fflush(where);
+       }
+    }
+    
+    /* 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 UDP_STREAM test to be a timed test. */
+    
+    if (test_time) {
+      times_up = 0;
+      start_timer(test_time);
+    }
+    else {
+      fprintf(where,"Sorry, UDP_STREAM tests must be timed.\n");
+      fflush(where);
+    }
+    
+    /* Get the start count for the idle counter and the start time */
+    
+    cpu_start(local_cpu_usage);
+    
+#ifdef WANT_INTERVALS
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+#ifdef WANT_DEMO
+    if (demo_mode) {
+      HIST_timestamp(demo_one_ptr);
+    }
+#endif
+
+    /* 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
+      if (verbosity > 1) {
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+     
+      if (local_connected) { 
+         len = send(data_socket,
+	  	    send_ring->buffer_ptr,
+		    send_size,
+		    0);
+      } else {
+         len = sendto(data_socket,
+		      send_ring->buffer_ptr,
+		      send_size,
+		      0,
+		      remote_res->ai_addr,
+		      remote_res->ai_addrlen);
+      }
+
+      if (len != send_size) {
+	if ((len >= 0) || 
+	    SOCKET_EINTR(len))
+	  break;
+	if (errno == ENOBUFS) {
+	  failed_sends++;
+	  continue;
+	}
+	perror("udp_send: data send error");
+	exit(1);
+      }
+      messages_sent++;          
+      
+      /* now we want to move our pointer to the next position in the */
+      /* data buffer... */
+      
+      send_ring = send_ring->next;
+      
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* get the second timestamp */
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+      DEMO_STREAM_INTERVAL(send_size)
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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);
+    
+    if (!no_control) {
+      /* Get the statistics from the remote end	*/
+      recv_response();
+      if (!netperf_response.content.serv_errno) {
+	if (debug)
+	  fprintf(where,"send_udp_stream: remote results obtained\n");
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	perror("send_udp_stream: error on remote");
+	exit(1);
+      }
+      messages_recvd = udp_stream_results->messages_recvd;
+      bytes_recvd    = (double) send_size * (double) messages_recvd;
+    }
+    else {
+      /* since there was no control connection, we've no idea what was
+	 actually received. raj 2007-02-08 */
+      messages_recvd = -1;
+      bytes_recvd = -1.0;
+    }
+
+    bytes_sent    = (double) send_size * (double) messages_sent;
+    local_thruput = calc_thruput(bytes_sent);
+    
+    
+    /* 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	= (float) -1.0;
+	local_service_demand	= (float) -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	= udp_stream_results->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_recvd,
+						      0.0,
+						      remote_cpu_utilization,
+						      udp_stream_results->num_cpus);
+      }
+      else {
+	remote_cpu_utilization	= (float) -1.0;
+	remote_service_demand	= (float) -1.0;
+      }
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization  = (float) -1.0;
+      local_service_demand   = (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(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 */
+ /* UDP_STREAM performance test. */
+
+void
+recv_udp_stream()
+{
+  struct ring_elt *recv_ring;
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct sockaddr_storage myaddr_in;
+  SOCKET	s_data;
+  netperf_socklen_t 	addrlen;
+  struct sockaddr_storage remote_addr;
+  netperf_socklen_t remote_addrlen;
+
+  int	len = 0;
+  unsigned int	bytes_received = 0;
+  float	elapsed_time;
+  
+  int	message_size;
+  unsigned int	messages_recvd = 0;
+  
+  struct	udp_stream_request_struct	*udp_stream_request;
+  struct	udp_stream_response_struct	*udp_stream_response;
+  struct	udp_stream_results_struct	*udp_stream_results;
+  
+  udp_stream_request  = 
+    (struct udp_stream_request_struct *)netperf_request.content.test_specific_data;
+  udp_stream_response = 
+    (struct udp_stream_response_struct *)netperf_response.content.test_specific_data;
+  udp_stream_results  = 
+    (struct udp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_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_udp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = UDP_STREAM_RESPONSE;
+  
+  if (debug > 2) {
+    fprintf(where,"recv_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_udp_stream: requested alignment of %d\n",
+	    udp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  if (recv_width == 0) recv_width = 1;
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   udp_stream_request->message_size,
+				   udp_stream_request->recv_alignment,
+				   udp_stream_request->recv_offset);
+
+  if (debug > 1) {
+    fprintf(where,"recv_udp_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_udp_stream: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = udp_stream_request->recv_buf_size;
+  loc_rcvavoid = udp_stream_request->so_rcvavoid;
+  loc_sndavoid = udp_stream_request->so_sndavoid;
+  local_connected = udp_stream_request->recv_connected;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(udp_stream_request->ipfamily),
+			udp_stream_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(udp_stream_request->ipfamily),
+				SOCK_DGRAM,
+				IPPROTO_UDP,
+				0);
+
+  s_data = create_data_socket(local_res);
+  
+  if (s_data == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+
+  udp_stream_response->test_length = udp_stream_request->test_length;
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_data, 
+		  (struct sockaddr *)&myaddr_in,
+		  &addrlen) == SOCKET_ERROR){
+    netperf_response.content.serv_errno = errno;
+    close(s_data);
+    send_response();
+    
+    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. */
+  
+  udp_stream_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&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. */
+  
+  udp_stream_response->cpu_rate    = (float)0.0; /* assume no cpu */
+  udp_stream_response->measure_cpu = 0;
+  if (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... */
+    udp_stream_response->measure_cpu = 1;
+    udp_stream_response->cpu_rate = 
+      calibrate_local_cpu(udp_stream_request->cpu_rate);
+  }
+  
+  message_size	= udp_stream_request->message_size;
+  test_time	= udp_stream_request->test_length;
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  udp_stream_response->send_buf_size = lss_size;
+  udp_stream_response->recv_buf_size = lsr_size;
+  udp_stream_response->so_rcvavoid = loc_rcvavoid;
+  udp_stream_response->so_sndavoid = loc_sndavoid;
+
+  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(udp_stream_request->measure_cpu);
+  
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+  
+  /* 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_udp_stream: about to enter inner sanctum.\n");
+    fflush(where);
+  }
+
+  /* We "connect" up to the remote post to allow us to use the recv */
+  /* call instead of the recvfrom call. Presumeably, this is a little */
+  /* simpler, and a little more efficient. */
+ 
+  if (local_connected) {
+
+    /* Receive the first message using recvfrom to find the remote address */
+    remote_addrlen = sizeof(remote_addr);
+    len = recvfrom(s_data, recv_ring->buffer_ptr,
+                   message_size, 0,
+                   (struct sockaddr*)&remote_addr, &remote_addrlen);
+    if (len != message_size) {
+      if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) {
+            netperf_response.content.serv_errno = errno;
+            send_response();
+            exit(1);
+      }
+    }
+    messages_recvd++;
+    recv_ring = recv_ring->next;
+
+
+    /* Now connect with the remote socket address */
+    if (connect(s_data,
+                (struct sockaddr*)&remote_addr,
+                remote_addrlen )== INVALID_SOCKET) {
+        netperf_response.content.serv_errno = errno;
+        close(s_data);
+        send_response();
+        exit(1);
+    }
+
+    if (debug) {
+        fprintf(where,"recv_udp_stream: connected data socket\n");
+        fflush(where);
+     }
+  }
+  
+  while (!times_up) {
+    if(local_connected) {
+       len = recv(s_data,
+                  recv_ring->buffer_ptr,
+                  message_size,
+                  0);
+    } else {
+       len = recvfrom(s_data,
+                      recv_ring->buffer_ptr,
+    	              message_size, 
+		      0,0,0);
+    }
+       
+    if (len != message_size) {
+      if ((len == SOCKET_ERROR) && !SOCKET_EINTR(len)) {
+            netperf_response.content.serv_errno = errno;
+	    send_response();
+	    exit(1);
+      }
+      break;
+    }
+    messages_recvd++;
+    recv_ring = recv_ring->next;
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_udp_stream: got %d messages.\n",messages_recvd);
+    fflush(where);
+  }
+  
+  
+  /* The loop now exits due timer or < send_size bytes received. in */
+  /* reality, we only really support a timed UDP_STREAM test. raj */
+  /* 12/95 */
+  
+  cpu_stop(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_udp_stream: test ended in %f seconds.\n",elapsed_time);
+    fflush(where);
+  }
+  
+  
+  /* We will count the "off" message that got us out of the loop */
+  bytes_received = (messages_recvd * message_size) + len;
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_udp_stream: got %d bytes\n",
+	    bytes_received);
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type	= UDP_STREAM_RESULTS;
+  udp_stream_results->bytes_received	= htonl(bytes_received);
+  udp_stream_results->messages_recvd	= messages_recvd;
+  udp_stream_results->elapsed_time	= elapsed_time;
+  udp_stream_results->cpu_method        = cpu_method;
+  udp_stream_results->num_cpus          = lib_num_loc_cpus;
+  if (udp_stream_request->measure_cpu) {
+    udp_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  else {
+    udp_stream_results->cpu_util	= (float) -1.0;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_udp_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+
+  close(s_data);
+
+}
+
+void
+send_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";
+  
+  float			elapsed_time;
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  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 addrinfo *local_res;
+  struct addrinfo *remote_res;
+  
+  struct	udp_rr_request_struct	*udp_rr_request;
+  struct	udp_rr_response_struct	*udp_rr_response;
+  struct	udp_rr_results_struct	*udp_rr_result;
+
+  udp_rr_request  =
+    (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
+  udp_rr_response =
+    (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
+  udp_rr_result	 =
+    (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_DGRAM,
+		     IPPROTO_UDP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("UDP REQUEST/RESPONSE TEST",local_res,remote_res);
+  }
+
+  /* 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;
+    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);
+    }
+    
+    /*set up the data socket                        */
+    send_socket = create_data_socket(local_res);
+    
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_udp_rr: udp rr data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_udp_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 */
+    /* 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);
+    }
+    
+    if (!no_control) {
+      /* 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_UDP_RR;
+      udp_rr_request->recv_buf_size	= rsr_size_req;
+      udp_rr_request->send_buf_size	= rss_size_req;
+      udp_rr_request->recv_alignment      = remote_recv_align;
+      udp_rr_request->recv_offset	        = remote_recv_offset;
+      udp_rr_request->send_alignment      = remote_send_align;
+      udp_rr_request->send_offset	        = remote_send_offset;
+      udp_rr_request->request_size	= req_size;
+      udp_rr_request->response_size	= rsp_size;
+      udp_rr_request->measure_cpu	        = remote_cpu_usage;
+      udp_rr_request->cpu_rate	        = remote_cpu_rate;
+      udp_rr_request->so_rcvavoid	        = rem_rcvavoid;
+      udp_rr_request->so_sndavoid	        = rem_sndavoid;
+      if (test_time) {
+	udp_rr_request->test_length	= test_time;
+      }
+      else {
+	udp_rr_request->test_length	= test_trans * -1;
+      }
+      udp_rr_request->port                = atoi(remote_data_port);
+      udp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
+      
+      if (debug > 1) {
+	fprintf(where,"netperf: send_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	       =	udp_rr_response->recv_buf_size;
+	rss_size	       =	udp_rr_response->send_buf_size;
+	remote_cpu_usage =	udp_rr_response->measure_cpu;
+	remote_cpu_rate  = 	udp_rr_response->cpu_rate;
+	/* port numbers in proper order */
+	set_port_number(remote_res,(short)udp_rr_response->data_port_number);
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_RR_SETUP(100)
+#endif
+
+    /* Connect up to the remote port on the data socket. This will set */
+    /* the default destination address on this socket. With UDP, this */
+    /* does make a performance difference as we may not have to do as */
+    /* many routing lookups, however, I expect that a client would */
+    /* behave this way. raj 1/94 */
+    
+    if ( connect(send_socket, 
+		 remote_res->ai_addr,
+		 remote_res->ai_addrlen) == INVALID_SOCKET ) {
+      perror("netperf: data socket connect failed");
+      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_DEMO
+    if (demo_mode) {
+      HIST_timestamp(demo_one_ptr);
+    }
+#endif 
+
+#ifdef WANT_INTERVALS
+    INTERVALS_INIT();
+#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. */
+
+#ifdef WANT_FIRST_BURST
+    {
+      int i;
+      for (i = 0; i < first_burst_size; i++) {
+	if((len=send(send_socket,
+		     send_ring->buffer_ptr,
+		     req_size,
+		     0)) != req_size) {
+	  /* we should never hit the end of the test in the first burst */
+	  perror("send_udp_rr: initial burst data send error");
+	  exit(-1);
+	}
+      }
+    }
+#endif /* WANT_FIRST_BURST */
+
+    while ((!times_up) || (trans_remaining > 0)) {
+      /* send the request */
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_one);
+      }
+#endif
+      if((len=send(send_socket,
+		   send_ring->buffer_ptr,
+		   req_size,
+		   0)) != req_size) {
+        if (SOCKET_EINTR(len)) {
+	      /* We likely hit */
+	      /* test-end time. */
+	      break;
+		}
+	    perror("send_udp_rr: data send error");
+	    exit(1);
+	  }
+      send_ring = send_ring->next;
+      
+      /* receive the response. with UDP we will get it all, or nothing */
+      
+      if((rsp_bytes_recvd=recv(send_socket,
+			       recv_ring->buffer_ptr,
+			       rsp_size,
+			       0)) != rsp_size) {
+	    if (SOCKET_EINTR(rsp_bytes_recvd))
+		{
+    	  /* Again, we have likely hit test-end time */
+	      break;
+		}
+	    perror("send_udp_rr: data recv error");
+	    exit(1);
+      }
+      recv_ring = recv_ring->next;
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+
+#endif
+
+      /* 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.  */
+
+#ifdef WANT_DEMO
+      DEMO_RR_INTERVAL(1);
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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);
+	}
+      }
+      
+    }
+    
+    /* for some strange reason, I used to call shutdown on the UDP */
+    /* data socket here. I'm not sure why, because it would not have */
+    /* any effect... raj 11/94 */
+    
+    /* 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? */
+    
+    if (!no_control) {
+      /* 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);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = 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,
+						     udp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    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(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 UDP_RR */
+ /* test. */
+void
+recv_udp_rr()
+{
+  
+  struct ring_elt *recv_ring;
+  struct ring_elt *send_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct sockaddr_storage        myaddr_in;
+  struct sockaddr_storage    peeraddr; 
+  SOCKET	s_data;
+  netperf_socklen_t 	addrlen;
+  int	trans_received;
+  int	trans_remaining;
+  int   request_bytes_recvd;
+  int   response_bytes_sent;
+  float	elapsed_time;
+  
+  struct	udp_rr_request_struct	*udp_rr_request;
+  struct	udp_rr_response_struct	*udp_rr_response;
+  struct	udp_rr_results_struct	*udp_rr_results;
+  
+  udp_rr_request  = 
+    (struct udp_rr_request_struct *)netperf_request.content.test_specific_data;
+  udp_rr_response = 
+    (struct udp_rr_response_struct *)netperf_response.content.test_specific_data;
+  udp_rr_results  = 
+    (struct udp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_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_udp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = UDP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_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_udp_rr: requested recv alignment of %d offset %d\n",
+	    udp_rr_request->recv_alignment,
+	    udp_rr_request->recv_offset);
+    fprintf(where,"recv_udp_rr: requested send alignment of %d offset %d\n",
+	    udp_rr_request->send_alignment,
+	    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,
+				   udp_rr_request->request_size,
+				   udp_rr_request->recv_alignment,
+				   udp_rr_request->recv_offset);
+
+  send_ring = allocate_buffer_ring(send_width,
+				   udp_rr_request->response_size,
+				   udp_rr_request->send_alignment,
+				   udp_rr_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_udp_rr: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_udp_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+
+  /* create_data_socket 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_req = udp_rr_request->send_buf_size;
+  lsr_size_req = udp_rr_request->recv_buf_size;
+  loc_rcvavoid = udp_rr_request->so_rcvavoid;
+  loc_sndavoid = udp_rr_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(udp_rr_request->ipfamily),
+			udp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(udp_rr_request->ipfamily),
+				SOCK_DGRAM,
+				IPPROTO_UDP,
+				0);
+				
+  s_data = create_data_socket(local_res);
+  
+  if (s_data == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_data, 
+		  (struct sockaddr *)&myaddr_in,
+		  &addrlen) == SOCKET_ERROR){
+    netperf_response.content.serv_errno = errno;
+    close(s_data);
+    send_response();
+    
+    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. */
+  
+  udp_rr_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
+  netperf_response.content.serv_errno   = 0;
+  
+  if (debug) {
+    fprintf(where,
+	    "recv port number %d\n",
+	    ((struct sockaddr_in *)&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. */
+  
+  udp_rr_response->cpu_rate    = (float)0.0; 	/* assume no cpu */
+  udp_rr_response->measure_cpu = 0;
+  if (udp_rr_request->measure_cpu) {
+    udp_rr_response->measure_cpu = 1;
+    udp_rr_response->cpu_rate = calibrate_local_cpu(udp_rr_request->cpu_rate);
+  }
+   
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  udp_rr_response->send_buf_size = lss_size;
+  udp_rr_response->recv_buf_size = lsr_size;
+  udp_rr_response->so_rcvavoid   = loc_rcvavoid;
+  udp_rr_response->so_sndavoid   = loc_sndavoid;
+ 
+  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(udp_rr_request->measure_cpu);
+  
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+  
+  if (udp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(udp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = udp_rr_request->test_length * -1;
+  }
+
+  addrlen = sizeof(peeraddr); 
+  bzero((char *)&peeraddr, addrlen);
+  
+  trans_received = 0;
+
+  while ((!times_up) || (trans_remaining > 0)) {
+    
+    /* receive the request from the other side */
+    if ((request_bytes_recvd = recvfrom(s_data,
+		 recv_ring->buffer_ptr,
+		 udp_rr_request->request_size,
+		 0,
+		 (struct sockaddr *)&peeraddr,
+		 &addrlen)) != udp_rr_request->request_size) {
+	  if ( SOCKET_EINTR(request_bytes_recvd) )
+	  {
+	    /* we must have hit the end of test time. */
+	    break;
+      }
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    recv_ring = recv_ring->next;
+
+    /* Now, send the response to the remote */
+    if ((response_bytes_sent = sendto(s_data,
+				      send_ring->buffer_ptr,
+				      udp_rr_request->response_size,
+				      0,
+				      (struct sockaddr *)&peeraddr,
+				      addrlen)) != 
+	udp_rr_request->response_size) {
+      if ( SOCKET_EINTR(response_bytes_sent) )
+	  {
+	    /* we have hit end of test time. */
+	    break;
+      }
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    send_ring = send_ring->next;
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_udp_rr: Transaction %d complete.\n",
+	      trans_received);
+      fflush(where);
+    }
+    
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(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_udp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  udp_rr_results->bytes_received = (trans_received * 
+				    (udp_rr_request->request_size + 
+				     udp_rr_request->response_size));
+  udp_rr_results->trans_received = trans_received;
+  udp_rr_results->elapsed_time	 = elapsed_time;
+  udp_rr_results->cpu_method     = cpu_method;
+  udp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (udp_rr_request->measure_cpu) {
+    udp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_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 TCP_RR */
+ /* test */
+void
+recv_tcp_rr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct	sockaddr_storage        myaddr_in,
+  peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	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;
+  int   sock_closed = 0;
+  float	elapsed_time;
+  
+  struct	tcp_rr_request_struct	*tcp_rr_request;
+  struct	tcp_rr_response_struct	*tcp_rr_response;
+  struct	tcp_rr_results_struct	*tcp_rr_results;
+  
+  tcp_rr_request = 
+    (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_rr_response =
+    (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_rr_results =
+    (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_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_tcp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_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_tcp_rr: requested recv alignment of %d offset %d\n",
+	    tcp_rr_request->recv_alignment,
+	    tcp_rr_request->recv_offset);
+    fprintf(where,"recv_tcp_rr: requested send alignment of %d offset %d\n",
+	    tcp_rr_request->send_alignment,
+	    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,
+				   tcp_rr_request->response_size,
+				   tcp_rr_request->send_alignment,
+				   tcp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   tcp_rr_request->request_size,
+				   tcp_rr_request->recv_alignment,
+				   tcp_rr_request->recv_offset);
+
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_rr_request->send_buf_size;
+  lsr_size_req = tcp_rr_request->recv_buf_size;
+  loc_nodelay = tcp_rr_request->no_delay;
+  loc_rcvavoid = tcp_rr_request->so_rcvavoid;
+  loc_sndavoid = tcp_rr_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_rr_request->ipfamily),
+			tcp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  tcp_rr_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&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. */
+  
+  tcp_rr_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  tcp_rr_response->measure_cpu = 0;
+
+  if (tcp_rr_request->measure_cpu) {
+    tcp_rr_response->measure_cpu = 1;
+    tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_rr_response->send_buf_size = lss_size;
+  tcp_rr_response->recv_buf_size = lsr_size;
+  tcp_rr_response->no_delay = loc_nodelay;
+  tcp_rr_response->so_rcvavoid = loc_rcvavoid;
+  tcp_rr_response->so_sndavoid = loc_sndavoid;
+  tcp_rr_response->test_length = tcp_rr_request->test_length;
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  if ((s_data = accept(s_listen,
+		       (struct sockaddr *)&peeraddr_in,
+		       &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    
+    exit(1);
+  }
+  
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+
+  if (debug) {
+    fprintf(where,"recv_tcp_rr: accept completes on the data connection.\n");
+    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(tcp_rr_request->measure_cpu);
+  
+  /* The loop will exit when we hit the end of the test time, or when */
+  /* we have exchanged the requested number of transactions. */
+  
+  if (tcp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(tcp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = 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	= tcp_rr_request->request_size;
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	if (SOCKET_EINTR(request_bytes_recvd))
+	{
+	  timed_out = 1;
+	  break;
+	}
+
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      else if( request_bytes_recvd == 0 ) {
+	if (debug) {
+	  fprintf(where,"zero is my hero\n");
+	  fflush(where);
+	}
+	sock_closed = 1;
+	break;
+      }
+      else {
+	request_bytes_remaining -= request_bytes_recvd;
+	temp_message_ptr  += request_bytes_recvd;
+      }
+    }
+
+    recv_ring = recv_ring->next;
+
+    if ((timed_out) || (sock_closed)) {
+      /* we hit the end of the test based on time - or the socket
+	 closed on us along the way.  bail out of here now... */
+      if (debug) {
+	fprintf(where,"yo5\n");
+	fflush(where);
+      }						
+      break;
+    }
+    
+    /* Now, send the response to the remote */
+    if((bytes_sent=send(s_data,
+			send_ring->buffer_ptr,
+			tcp_rr_request->response_size,
+			0)) == SOCKET_ERROR) {
+      if (SOCKET_EINTR(bytes_sent)) {
+	/* the test timer has popped */
+	timed_out = 1;
+	fprintf(where,"yo6\n");
+	fflush(where);						
+	break;
+      }
+      netperf_response.content.serv_errno = 992;
+      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(tcp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer();
+
+  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_tcp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  tcp_rr_results->bytes_received = (trans_received * 
+				    (tcp_rr_request->request_size + 
+				     tcp_rr_request->response_size));
+  tcp_rr_results->trans_received = trans_received;
+  tcp_rr_results->elapsed_time   = elapsed_time;
+  tcp_rr_results->cpu_method     = cpu_method;
+  tcp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (tcp_rr_request->measure_cpu) {
+    tcp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  send_response();
+  
+}
+
+
+void
+loc_cpu_rate()
+{
+#if defined(USE_LOOPER)
+  float dummy;
+#endif
+
+  /* a rather simple little test - it merely calibrates the local cpu */
+  /* and prints the results. There are no headers to allow someone to */
+  /* find a rate and use it in other tests automagically by setting a */
+  /* variable equal to the output of this test. We ignore any rates */
+  /* that may have been specified. In fact, we ignore all of the */
+  /* command line args! */
+  
+  fprintf(where,
+	  "%g",
+	  calibrate_local_cpu(0.0));
+
+  if (verbosity > 1)
+    fprintf(where,
+	    "\nThere %s %d local %s\n",
+	    (lib_num_loc_cpus > 1) ? "are" : "is",
+	    lib_num_loc_cpus,
+	    (lib_num_loc_cpus > 1) ? "cpus" : "cpu");
+	    
+  /* we need the cpu_start, cpu_stop in the looper case to kill the */
+  /* child proceses raj 4/95 */
+
+#ifdef USE_LOOPER
+  cpu_start(1);
+  cpu_stop(1,&dummy);
+#endif /* USE_LOOPER */
+
+}	
+
+void
+rem_cpu_rate()
+{
+  /* this test is much like the local variant, except that it works for */
+  /* the remote system, so in this case, we do pay attention to the */
+  /* value of the '-H' command line argument. */
+  
+  fprintf(where,
+	  "%g",
+	  calibrate_remote_cpu());
+  
+  if (verbosity > 1)
+    fprintf(where,
+	    "\nThere %s %d remote %s\n",
+	    (lib_num_rem_cpus > 1) ? "are" : "is",
+	    lib_num_rem_cpus,
+	    (lib_num_rem_cpus > 1) ? "cpus" : "cpu");
+
+}
+
+
+ /* 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_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 = "\n\
+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;
+  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	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 addrinfo *local_res;
+  struct addrinfo *remote_res;
+
+  int                           myport;
+  int                           ret;
+
+  struct	tcp_conn_rr_request_struct	*tcp_conn_rr_request;
+  struct	tcp_conn_rr_response_struct	*tcp_conn_rr_response;
+  struct	tcp_conn_rr_results_struct	*tcp_conn_rr_result;
+  
+  tcp_conn_rr_request = 
+    (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_conn_rr_response = 
+    (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_conn_rr_result =
+    (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("TCP Connect/Request/Response TEST",local_res,remote_res);
+  }
+  
+  /* 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_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);
+  }
+
+  if (!no_control) {
+  
+    /* 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_TCP_CRR;
+    tcp_conn_rr_request->recv_buf_size	=	rsr_size_req;
+    tcp_conn_rr_request->send_buf_size	=	rss_size_req;
+    tcp_conn_rr_request->recv_alignment	=	remote_recv_align;
+    tcp_conn_rr_request->recv_offset	=	remote_recv_offset;
+    tcp_conn_rr_request->send_alignment	=	remote_send_align;
+    tcp_conn_rr_request->send_offset	=	remote_send_offset;
+    tcp_conn_rr_request->request_size	=	req_size;
+    tcp_conn_rr_request->response_size	=	rsp_size;
+    tcp_conn_rr_request->no_delay	=	rem_nodelay;
+    tcp_conn_rr_request->measure_cpu	=	remote_cpu_usage;
+    tcp_conn_rr_request->cpu_rate	=	remote_cpu_rate;
+    tcp_conn_rr_request->so_rcvavoid	=	rem_rcvavoid;
+    tcp_conn_rr_request->so_sndavoid	=	rem_sndavoid;
+    if (test_time) {
+      tcp_conn_rr_request->test_length	=	test_time;
+    }
+    else {
+      tcp_conn_rr_request->test_length	=	test_trans * -1;
+    }
+    tcp_conn_rr_request->port           = atoi(remote_data_port);
+    tcp_conn_rr_request->ipfamily       = af_to_nf(remote_res->ai_family);
+    
+    if (debug > 1) {
+      fprintf(where,"netperf: send_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	       =	tcp_conn_rr_response->recv_buf_size;
+      rss_size	       =	tcp_conn_rr_response->send_buf_size;
+      rem_nodelay      =	tcp_conn_rr_response->no_delay;
+      remote_cpu_usage =	tcp_conn_rr_response->measure_cpu;
+      remote_cpu_rate  = 	tcp_conn_rr_response->cpu_rate;
+      /* make sure that port numbers are in network order */
+      set_port_number(remote_res,
+		      (unsigned short)tcp_conn_rr_response->data_port_number);
+      
+      if (debug) {
+	fprintf(where,"remote listen done.\n");
+	fprintf(where,"remote port is %u\n",get_port_number(remote_res));
+	fflush(where);
+      }
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      exit(1);
+    }
+  }
+#ifdef WANT_DEMO
+  DEMO_RR_SETUP(100)
+#endif
+
+  /* pick a nice random spot between client_port_min and */
+  /* client_port_max for our initial port number */
+  srand(getpid());
+  if (client_port_max - client_port_min) {
+    myport = client_port_min + 
+      (rand() % (client_port_max - client_port_min));
+  }
+  else {
+    myport = client_port_min;
+  }
+  /* there will be a ++ before the first call to bind, so subtract one */
+  myport--;
+  /* 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_DEMO
+      if (demo_mode) {
+	HIST_timestamp(demo_one_ptr);
+      }
+#endif
+  
+  /* 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)) {
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      /* timestamp just before our call to create the socket, and then */
+      /* again just after the receive raj 3/95 */
+      HIST_timestamp(&time_one);
+    }
+#endif /* WANT_HISTOGRAM */
+
+newport:
+    /* pick a new port number */
+    myport++;
+
+    /* wrap the port number when we get to client_port_max. NOTE, some */
+    /* broken TCP's might treat the port number as a signed 16 bit */
+    /* quantity.  we aren't interested in testing such broken */
+    /* implementations :) so we won't make sure that it is below 32767 */
+    /* raj 8/94  */
+    if (myport >= client_port_max) {
+      myport = client_port_min;
+    }
+
+    /* 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. we */
+    /* could just rely on the failure of the bind to get us past this, */
+    /* but I'm guessing that in this one case at least, it is much */
+    /* faster, given that we *know* that port number is already in use */
+    /* (or rather would be in a loopback test) */
+
+    if (myport == get_port_number(remote_res)) myport++;
+
+    if (debug) {
+      if ((nummessages % 100) == 0) {
+	printf("port %d\n",myport);
+      }
+    }
+
+    /* set up the data socket */
+    set_port_number(local_res, (unsigned short)myport);
+    send_socket = create_data_socket(local_res);
+  
+    if (send_socket == INVALID_SOCKET) {
+      perror("netperf: send_tcp_conn_rr: tcp stream data socket");
+      exit(1);
+    }
+
+
+    /* we used to call bind here, but that is now taken-care-of by the
+       create_data_socket routine. */
+
+    /* Connect up to the remote port on the data socket  */
+    if ((ret = connect(send_socket, 
+		       remote_res->ai_addr,
+		       remote_res->ai_addrlen)) == INVALID_SOCKET){
+      if (SOCKET_EINTR(ret))
+	  {
+	    /* we hit the end of a */
+	    /* timed test. */
+	    timed_out = 1;
+	    break;
+      }
+      if ((SOCKET_EADDRINUSE(ret)) || SOCKET_EADDRNOTAVAIL(ret)) {
+	/* likely something our explicit bind() would have caught in
+           the past, so go get another port, via create_data_socket.
+           yes, this is a bit more overhead than before, but the
+           condition should be rather rare.  raj 2005-02-08 */
+	close(send_socket);
+	goto newport;
+      }
+      perror("netperf: data socket connect failed");
+      printf("\tattempted to connect on socket %d to port %d",
+	     send_socket,
+	     get_port_number(remote_res));
+      printf(" from port %d \n",get_port_number(local_res));
+      exit(1);
+    }
+
+
+    /* send the request */
+    if((len=send(send_socket,
+		 send_ring->buffer_ptr,
+		 req_size,
+		 0)) != req_size) {
+      if (SOCKET_EINTR(len))
+	  {
+	    /* we hit the end of a */
+	    /* timed test. */
+	    timed_out = 1;
+	    break;
+      }
+      perror("send_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;
+
+
+    do {
+      rsp_bytes_recvd = recv(send_socket,
+			     temp_message_ptr,
+			     rsp_bytes_left,
+			     0);
+      if (rsp_bytes_recvd > 0) {
+	rsp_bytes_left -= rsp_bytes_recvd;
+	temp_message_ptr += rsp_bytes_recvd;
+      }
+      else {
+	break;
+      }
+    } while (rsp_bytes_left);
+
+
+    /* OK, we are out of the loop - now what? */
+    if (rsp_bytes_recvd < 0) {
+      /* did the timer hit, or was there an error? */
+      if (SOCKET_EINTR(rsp_bytes_recvd))
+	  {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+	  perror("send_tcp_conn_rr: data recv error");
+	  exit(1);
+    }
+
+    /* if this is a no_control test, we initiate connection close,
+       otherwise the remote netserver does it to remain just like
+       previous behaviour. raj 2007-27-08 */
+    if (!no_control) {
+      shutdown(send_socket,SHUT_WR);
+    }
+
+    /* we are expecting to get either a return of zero indicating
+       connection close, or an error.  */
+    rsp_bytes_recvd = recv(send_socket,
+			   temp_message_ptr,
+			   1,
+			   0);
+
+    /* our exit from the while loop should generally be when */
+    /* tmp_bytes_recvd is equal to zero, which implies the connection */
+    /* has been closed by the server side. By waiting until we get the */
+    /* zero return we can avoid race conditions that stick us with the */
+    /* TIME_WAIT connection and not the server. raj 8/96 */
+
+    if (rsp_bytes_recvd == 0) {
+      /* connection close, call close. we assume that the requisite */
+      /* number of bytes have been received */
+      recv_ring = recv_ring->next;
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+      DEMO_RR_INTERVAL(1)
+#endif
+
+      nummessages++;          
+      if (trans_remaining) {
+	trans_remaining--;
+      }
+    
+      if (debug > 3) {
+	fprintf(where,
+		"Transaction %d completed on local port %d\n",
+		nummessages,
+		get_port_number(local_res));
+	fflush(where);
+      }
+
+      close(send_socket);
+
+    }
+    else {
+      /* it was less than zero - an error occured */
+      if (SOCKET_EINTR(rsp_bytes_recvd))
+	  {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+	  perror("send_tcp_conn_rr: data recv error");
+	  exit(1);
+    }
+      
+  }
+
+  
+  /* 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? */
+  
+  if (!no_control) {
+    /* 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);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      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	= (float) -1.0;
+      local_service_demand	= (float) -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 = 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,
+						  tcp_conn_rr_result->num_cpus);
+    }
+    else {
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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:
+    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;
+    }
+  }
+  
+  /* 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,
+	    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
+recv_tcp_conn_rr()
+{
+  
+  char  *message;
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct	sockaddr_storage        myaddr_in, peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	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	tcp_conn_rr_request_struct	*tcp_conn_rr_request;
+  struct	tcp_conn_rr_response_struct	*tcp_conn_rr_response;
+  struct	tcp_conn_rr_results_struct	*tcp_conn_rr_results;
+  
+  tcp_conn_rr_request = 
+    (struct tcp_conn_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_conn_rr_response = 
+    (struct tcp_conn_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_conn_rr_results = 
+    (struct tcp_conn_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_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_tcp_conn_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_CRR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_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_tcp_conn_rr: requested recv alignment of %d offset %d\n",
+	    tcp_conn_rr_request->recv_alignment,
+	    tcp_conn_rr_request->recv_offset);
+    fprintf(where,
+	    "recv_tcp_conn_rr: requested send alignment of %d offset %d\n",
+	    tcp_conn_rr_request->send_alignment,
+	    tcp_conn_rr_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->recv_alignment, tcp_conn_rr_request->recv_offset);
+  
+  send_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->send_alignment, tcp_conn_rr_request->send_offset);
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_conn_rr: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_conn_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_conn_rr_request->send_buf_size;
+  lsr_size_req = tcp_conn_rr_request->recv_buf_size;
+  loc_nodelay = tcp_conn_rr_request->no_delay;
+  loc_rcvavoid = tcp_conn_rr_request->so_rcvavoid;
+  loc_sndavoid = tcp_conn_rr_request->so_sndavoid;
+  
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_conn_rr_request->ipfamily),
+			tcp_conn_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_conn_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  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);
+  }
+
+#ifdef WIN32
+    /* The test timer can fire during operations on the listening socket,
+       so to make the start_timer below work we have to move
+       it to close s_listen while we are blocked on accept. */
+    win_kludge_socket2 = s_listen;
+#endif
+
+
+  /* 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 getsockname\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. */
+  
+  tcp_conn_rr_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
+  if (debug) {
+    fprintf(where,"telling the remote to call me at %d\n",
+	    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. */
+  
+  tcp_conn_rr_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (tcp_conn_rr_request->measure_cpu) {
+    tcp_conn_rr_response->measure_cpu = 1;
+    tcp_conn_rr_response->cpu_rate = 
+      calibrate_local_cpu(tcp_conn_rr_request->cpu_rate);
+  }
+  
+
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_conn_rr_response->send_buf_size = lss_size;
+  tcp_conn_rr_response->recv_buf_size = lsr_size;
+  tcp_conn_rr_response->no_delay = loc_nodelay;
+  tcp_conn_rr_response->so_rcvavoid = loc_rcvavoid;
+  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(tcp_conn_rr_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (tcp_conn_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(tcp_conn_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = tcp_conn_rr_request->test_length * -1;
+  }
+  
+  trans_received = 0;
+
+  while ((!times_up) || (trans_remaining > 0)) {
+
+    /* accept a connection from the remote */
+#ifdef WIN32
+    /* The test timer will probably fire during this accept, 
+       so to make the start_timer above work we have to move
+       it to close s_listen while we are blocked on accept. */
+    win_kludge_socket = s_listen;
+#endif
+    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_tcp_conn_rr: accept: errno = %d\n",errno);
+      fflush(where);
+      close(s_listen);
+      
+      exit(1);
+    }
+
+    if (debug) {
+      fprintf(where,"recv_tcp_conn_rr: accepted data connection.\n");
+      fflush(where);
+    }
+  
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+    /* this is for those systems which *INCORRECTLY* fail to pass */
+    /* attributes across an accept() call. Including this goes against */
+    /* my better judgement :( raj 11/95 */
+    
+    kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+    temp_message_ptr	= recv_message_ptr;
+    request_bytes_remaining	= tcp_conn_rr_request->request_size;
+    
+    /* receive the request from the other side */
+    while (!times_up && (request_bytes_remaining > 0)) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	if (SOCKET_EINTR(request_bytes_recvd))
+	{
+	  /* 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,
+			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_tcp_conn_rr: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+
+    /* close the connection. the server will likely do a graceful */
+    /* close of the connection, insuring that all data has arrived at */
+    /* the client. for this it will call shutdown(), and then recv() and */
+    /* then close(). I'm reasonably confident that this is the */
+    /* appropriate sequence of calls - I would like to hear of */
+    /* examples in web servers to the contrary. raj 10/95*/
+#ifdef TCP_CRR_SHUTDOWN
+    shutdown(s_data,SHUT_WR);
+    recv(s_data,
+	 recv_message_ptr,
+	 1,
+	 0);
+    close(s_data);
+#else
+    close(s_data);
+#endif /* TCP_CRR_SHUTDOWN */
+
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(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_tcp_conn_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  tcp_conn_rr_results->bytes_received	= (trans_received * 
+					   (tcp_conn_rr_request->request_size + 
+					    tcp_conn_rr_request->response_size));
+  tcp_conn_rr_results->trans_received	= trans_received;
+  tcp_conn_rr_results->elapsed_time	= elapsed_time;
+  if (tcp_conn_rr_request->measure_cpu) {
+    tcp_conn_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_conn_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+
+#ifdef DO_1644
+
+ /* 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. */
+
+int 
+send_tcp_tran_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 = "\n\
+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	tcp_tran_rr_request_struct	*tcp_tran_rr_request;
+  struct	tcp_tran_rr_response_struct	*tcp_tran_rr_response;
+  struct	tcp_tran_rr_results_struct	*tcp_tran_rr_result;
+  
+  tcp_tran_rr_request = 
+    (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_tran_rr_response = 
+    (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_tran_rr_result =
+    (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  myaddr = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
+  if (myaddr == NULL) {
+    printf("malloc(%d) failed!\n", sizeof(struct sockaddr_storage));
+    exit(1);
+  }
+
+  bzero((char *)&server,
+	sizeof(server));
+  bzero((char *)myaddr,
+	sizeof(struct sockaddr_storage));
+  myaddr->sin_family = AF_INET;
+
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("TCP Transactional/Request/Response TEST",local_res,remote_res);
+  }
+  
+  /* 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_tcp_tran_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_TCP_TRR;
+  tcp_tran_rr_request->recv_buf_size	=	rsr_size_req;
+  tcp_tran_rr_request->send_buf_size	=	rss_size_req;
+  tcp_tran_rr_request->recv_alignment	=	remote_recv_align;
+  tcp_tran_rr_request->recv_offset	=	remote_recv_offset;
+  tcp_tran_rr_request->send_alignment	=	remote_send_align;
+  tcp_tran_rr_request->send_offset	=	remote_send_offset;
+  tcp_tran_rr_request->request_size	=	req_size;
+  tcp_tran_rr_request->response_size	=	rsp_size;
+  tcp_tran_rr_request->no_delay	        =	rem_nodelay;
+  tcp_tran_rr_request->measure_cpu	=	remote_cpu_usage;
+  tcp_tran_rr_request->cpu_rate	        =	remote_cpu_rate;
+  tcp_tran_rr_request->so_rcvavoid	=	rem_rcvavoid;
+  tcp_tran_rr_request->so_sndavoid	=	rem_sndavoid;
+  if (test_time) {
+    tcp_tran_rr_request->test_length	=	test_time;
+  }
+  else {
+    tcp_tran_rr_request->test_length	=	test_trans * -1;
+  }
+  tcp_tran_rr_request->port             =       atoi(remote_data_port);
+  tcp_tran_rr_request->ipfamily        =       af_to_nf(remote_res->ai_family);
+
+  if (debug > 1) {
+    fprintf(where,"netperf: send_tcp_tran_rr: requesting TCP_TRR 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	=	tcp_tran_rr_response->recv_buf_size;
+    rss_size	=	tcp_tran_rr_response->send_buf_size;
+    rem_nodelay	=	tcp_tran_rr_response->no_delay;
+    remote_cpu_usage=	tcp_tran_rr_response->measure_cpu;
+    remote_cpu_rate = 	tcp_tran_rr_response->cpu_rate;
+    /* make sure that port numbers are in network order */
+    server.sin_port	=	tcp_tran_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);
+    fprintf(where,
+	    "netperf: remote error %d",
+	    netperf_response.content.serv_errno);
+    perror("");
+    fflush(where);
+    exit(1);
+  }
+
+  /* pick a nice random spot between client_port_min and */
+  /* client_port_max for our initial port number. if they are the */
+  /* same, then just set to _min */
+  if (client_port_max - client_port_min) {
+    srand(getpid());
+    myport = client_port_min + 
+      (rand() % (client_port_max - client_port_min));
+  }
+  else {
+    myport = client_port_min;
+  }
+
+  /* there will be a ++ before the first call to bind, so subtract one */
+  myport--;
+  myaddr->sin_port = htons((unsigned short)myport);
+  
+  /* 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. */
+
+  while ((!times_up) || (trans_remaining > 0)) {
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      /* timestamp just before our call to create the socket, and then */
+      /* again just after the receive raj 3/95 */
+      HIST_timestamp(&time_one);
+    }
+#endif /* WANT_HISTOGRAM */
+
+    /* set up the data socket - is this really necessary or can I just */
+    /* re-use the same socket and move this cal out of the while loop. */
+    /* it does introcudea *boatload* of system calls. I guess that it */
+    /* all depends on "reality of programming." keeping it this way is */
+    /* a bit more conservative I imagine - raj 3/95 */
+    send_socket = create_data_socket(local_res);
+  
+    if (send_socket == INVALID_SOCKET) {
+      perror("netperf: send_tcp_tran_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. 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_tcp_tran_rr: so_reuseaddr");
+      exit(1);
+    }
+
+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. we */
+    /* could just rely on the failure of the bind to get us past this, */
+    /* but I'm guessing that in this one case at least, it is much */
+    /* faster, given that we *know* that port number is already in use */
+    /* (or rather would be 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 broken implementations :) */
+    /* raj 8/94  */
+    if (myport >= client_port_max) {
+      myport = client_port_min;
+    }
+    myaddr->sin_port = htons((unsigned short)myport);
+
+    if (debug) {
+      if ((nummessages % 100) == 0) {
+	printf("port %d\n",myport);
+      }
+    }
+
+    /* we want to bind our socket to a particular port number. */
+    if (bind(send_socket,
+	     (struct sockaddr *)myaddr,
+	     sizeof(struct sockaddr_storage)) == SOCKET_ERROR) {
+      /* if the bind failed, someone else must have that port number */
+      /* - perhaps in the listen state. since we can't use it, skip to */
+      /* the next port number. we may have to do this again later, but */
+      /* that's just too bad :) */
+      if (debug > 1) {
+	fprintf(where,
+		"send_tcp_tran_rr: tried to bind to port %d errno %d\n",
+		ntohs(myaddr->sin_port),
+		errno);
+	fflush(where);
+      }
+	/* yes, goto's are supposed to be evil, but they do have their */
+	/* uses from time to time. the real world doesn't always have */
+	/* to code to ge tthe A in CS 101 :) raj 3/95 */
+	goto newport;
+    }
+
+    /* Connect up to the remote port on the data socket. Since this is */
+    /* a test for RFC_1644-style transactional TCP, we can use the */
+    /* sendto() call instead of calling connect and then send() */
+
+    /* send the request */
+    if((len=sendto(send_socket,
+		   send_ring->buffer_ptr,
+		   req_size,
+		   MSG_EOF, 
+		   (struct sockaddr *)&server,
+		   sizeof(server))) != req_size) {
+      if (SOCKET_EINTR(len))
+	  {
+	    /* we hit the end of a */
+	    /* timed test. */
+	    timed_out = 1;
+	    break;
+      }
+      perror("send_tcp_tran_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 (SOCKET_EINTR(rsp_bytes_recvd))
+		{
+	      /* We hit the end of a timed test. */
+	      timed_out = 1;
+	      break;
+		}
+	    perror("send_tcp_tran_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);
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      HIST_timestamp(&time_two);
+      HIST_add(time_hist,delta_micro(&time_one,&time_two));
+    }
+#endif /* WANT_HISTOGRAM */
+
+    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);
+    }
+
+
+  }
+  
+  /* 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);
+    fprintf(where,
+	    "netperf: remote error %d",
+	    netperf_response.content.serv_errno);
+    perror("");
+    fflush(where);
+    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	= (float) -1.0;
+      local_service_demand	= (float) -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 = tcp_tran_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,
+						  tcp_tran_rr_result->num_cpus);
+    }
+    else {
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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:
+    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;
+    }
+  }
+  
+  /* 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,
+	    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 */
+
+  }
+  
+}
+
+
+int 
+recv_tcp_tran_rr()
+{
+  
+  char  *message;
+  struct	sockaddr_in        myaddr_in,
+  peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	addrlen;
+  int   NoPush = 1;
+
+  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	tcp_tran_rr_request_struct	*tcp_tran_rr_request;
+  struct	tcp_tran_rr_response_struct	*tcp_tran_rr_response;
+  struct	tcp_tran_rr_results_struct	*tcp_tran_rr_results;
+  
+  tcp_tran_rr_request = 
+    (struct tcp_tran_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_tran_rr_response = 
+    (struct tcp_tran_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_tran_rr_results = 
+    (struct tcp_tran_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_tcp_tran_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_tcp_tran_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_TRR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_tran_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_tcp_tran_rr: requested recv alignment of %d offset %d\n",
+	    tcp_tran_rr_request->recv_alignment,
+	    tcp_tran_rr_request->recv_offset);
+    fprintf(where,
+	    "recv_tcp_tran_rr: requested send alignment of %d offset %d\n",
+	    tcp_tran_rr_request->send_alignment,
+	    tcp_tran_rr_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->recv_alignment, tcp_tran_rr_request->recv_offset);
+  
+  send_message_ptr = ALIGN_BUFFER(message, tcp_tran_rr_request->send_alignment, tcp_tran_rr_request->send_offset);
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_tran_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        = htons((unsigned short)tcp_tran_rr_request->port);
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_tran_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_tran_rr_request->send_buf_size;
+  lsr_size_req = tcp_tran_rr_request->recv_buf_size;
+  loc_nodelay = tcp_tran_rr_request->no_delay;
+  loc_rcvavoid = tcp_tran_rr_request->so_rcvavoid;
+  loc_sndavoid = tcp_tran_rr_request->so_sndavoid;
+  
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_tran_rr_request->ipfamily),
+			tcp_tran_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_tran_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  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);
+  }
+
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+
+  /* 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);
+  }
+
+  /* we want to disable the implicit PUSH on all sends. at some point, */
+  /* this might want to be a parm to the test raj 3/95 */
+  if (setsockopt(s_listen,
+		 IPPROTO_TCP,
+		 TCP_NOPUSH, 
+		 (const char *)&NoPush,
+		 sizeof(int)) == SOCKET_ERROR) {
+    fprintf(where,
+	    "recv_tcp_tran_rr: could not set TCP_NOPUSH errno %d\n",
+	    errno);
+    fflush(where);
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+  }
+
+  /* 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. */
+  
+  tcp_tran_rr_response->data_port_number = (int) ntohs(myaddr_in.sin_port);
+  if (debug) {
+    fprintf(where,"telling the remote to call me at %d\n",
+	    tcp_tran_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. */
+  
+  tcp_tran_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (tcp_tran_rr_request->measure_cpu) {
+    tcp_tran_rr_response->measure_cpu = 1;
+    tcp_tran_rr_response->cpu_rate = 
+      calibrate_local_cpu(tcp_tran_rr_request->cpu_rate);
+  }
+  
+
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_tran_rr_response->send_buf_size = lss_size;
+  tcp_tran_rr_response->recv_buf_size = lsr_size;
+  tcp_tran_rr_response->no_delay = loc_nodelay;
+  tcp_tran_rr_response->so_rcvavoid = loc_rcvavoid;
+  tcp_tran_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(tcp_tran_rr_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (tcp_tran_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(tcp_tran_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = tcp_tran_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_tcp_tran_rr: accept: errno = %d\n",errno);
+      fflush(where);
+      close(s_listen);
+      
+      exit(1);
+    }
+  
+    if (debug) {
+      fprintf(where,"recv_tcp_tran_rr: accepted data connection.\n");
+      fflush(where);
+    }
+  
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+    temp_message_ptr	= recv_message_ptr;
+    request_bytes_remaining	= tcp_tran_rr_request->request_size;
+    
+    /* receive the request from the other side. we can just receive */
+    /* until we get zero bytes, but that would be a slight structure */
+    /* change in the code, with minimal perfomance effects. If */
+    /* however, I has variable-length messages, I would want to do */
+    /* this to avoid needing "double reads" - one for the message */
+    /* length, and one for the rest of the message raj 3/95 */
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	    if ( SOCKET_EINTR(request_bytes_recvd) )
+		{
+	      /* 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 we can use sendto here to */
+    /* help remind people that this is an rfc 1644 style of test */
+    if((bytes_sent=sendto(s_data,
+			  send_message_ptr,
+			  tcp_tran_rr_request->response_size,
+			  MSG_EOF,
+			  (struct sockaddr *)&peeraddr_in,
+			  sizeof(struct sockaddr_storage))) == SOCKET_ERROR) {
+      if (SOCKET_EINTR(bytes_sent)) {
+	/* 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_tcp_tran_rr: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+
+    /* close the connection. since we have disable PUSH on sends, the */
+    /* FIN should be tacked-onto our last send instead of being */
+    /* standalone */
+    close(s_data);
+
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(tcp_tran_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_tcp_tran_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  tcp_tran_rr_results->bytes_received	= (trans_received * 
+					   (tcp_tran_rr_request->request_size + 
+					    tcp_tran_rr_request->response_size));
+  tcp_tran_rr_results->trans_received	= trans_received;
+  tcp_tran_rr_results->elapsed_time	= elapsed_time;
+  if (tcp_tran_rr_request->measure_cpu) {
+    tcp_tran_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_tran_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+#endif /* DO_1644 */
+
+#ifdef DO_NBRR
+ /* this routine implements the sending (netperf) side of the TCP_RR */
+ /* test using POSIX-style non-blocking sockets. */
+
+void
+send_tcp_nbrr(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_storage	server;
+  unsigned      int             addr;
+  
+  struct	tcp_rr_request_struct	*tcp_rr_request;
+  struct	tcp_rr_response_struct	*tcp_rr_response;
+  struct	tcp_rr_results_struct	*tcp_rr_result;
+
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+
+  tcp_rr_request = 
+    (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_rr_response=
+    (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_rr_result	=
+    (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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));
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("TCP Non-Blocking REQUEST/RESPONSE TEST",local_res,remote_res);
+  }
+  
+  /* 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_data_socket(local_res);
+  
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_tcp_nbrr: tcp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_tcp_nbrr: 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_TCP_NBRR;
+    tcp_rr_request->recv_buf_size	=	rsr_size_req;
+    tcp_rr_request->send_buf_size	=	rss_size_req;
+    tcp_rr_request->recv_alignment      =	remote_recv_align;
+    tcp_rr_request->recv_offset	        =	remote_recv_offset;
+    tcp_rr_request->send_alignment      =	remote_send_align;
+    tcp_rr_request->send_offset	        =	remote_send_offset;
+    tcp_rr_request->request_size	=	req_size;
+    tcp_rr_request->response_size	=	rsp_size;
+    tcp_rr_request->no_delay	        =	rem_nodelay;
+    tcp_rr_request->measure_cpu	        =	remote_cpu_usage;
+    tcp_rr_request->cpu_rate	        =	remote_cpu_rate;
+    tcp_rr_request->so_rcvavoid	        =	rem_rcvavoid;
+    tcp_rr_request->so_sndavoid	        =	rem_sndavoid;
+    if (test_time) {
+      tcp_rr_request->test_length	=	test_time;
+    }
+    else {
+      tcp_rr_request->test_length	=	test_trans * -1;
+    }
+    
+    if (debug > 1) {
+      fprintf(where,"netperf: send_tcp_nbrr: 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          = tcp_rr_response->recv_buf_size;
+      rss_size          = tcp_rr_response->send_buf_size;
+      rem_nodelay       = tcp_rr_response->no_delay;
+      remote_cpu_usage  = tcp_rr_response->measure_cpu;
+      remote_cpu_rate   = tcp_rr_response->cpu_rate;
+      /* make sure that port numbers are in network order */
+      server.sin_port   = (unsigned short)tcp_rr_response->data_port_number;
+      server.sin_port   = htons(server.sin_port);
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      exit(1);
+    }
+    
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: data socket connect failed");
+      
+      exit(1);
+    }
+    
+    /* now that we are connected, mark the socket as non-blocking */
+    if (!set_nonblock(send_socket)) {
+      perror("netperf: set_nonblock");
+      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
+    INTERVALS_INIT();
+#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
+      if (verbosity > 1) {
+	/* timestamp just before our call to send, and then again just */
+	/* after the receive raj 8/94 */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+
+      /* even though this is a non-blocking socket, we will assume for */
+      /* the time being that we will be able to send an entire request */
+      /* without getting an EAGAIN */
+      if((len=send(send_socket,
+		   send_ring->buffer_ptr,
+		   req_size,
+		   0)) != req_size) {
+	if (SOCKET_EINTR(len)) {
+	  /* we hit the end of a */
+	  /* timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_tcp_nbrr: data send error");
+	exit(1);
+      }
+      send_ring = send_ring->next;
+      
+      /* receive the response. since we are using non-blocking I/O, we */
+      /* will "spin" on the recvs */
+      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 (SOCKET_EINTR(rsp_bytes_recvd))
+	  {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+#ifndef WIN32  // But what does WinNT indicate in this situation...
+	  else if (errno == EAGAIN) {
+	    Set_errno(0);
+	    continue;
+	  }
+#endif
+	  else {
+	    perror("send_tcp_nbrr: 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;
+      }
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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);
+	}
+      }
+    }
+
+    /* At this point we used to call shutdown on the data socket to be */
+    /* sure all the data was delivered, but this was not germane in a */
+    /* request/response test, and it was causing the tests to "hang" when */
+    /* they were being controlled by time. So, I have replaced this */
+    /* shutdown call with a call to close that can be found later in the */
+    /* procedure. */
+    
+    /* 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);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = 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,
+						    tcp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    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(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 */
+
+  }
+  
+}
+
+ /* this routine implements the receive (netserver) side of a TCP_RR */
+ /* test */
+void 
+recv_tcp_nbrr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct	sockaddr_in        myaddr_in,
+  peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	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 addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+  
+  struct	tcp_rr_request_struct	*tcp_rr_request;
+  struct	tcp_rr_response_struct	*tcp_rr_response;
+  struct	tcp_rr_results_struct	*tcp_rr_results;
+  
+  tcp_rr_request = 
+    (struct tcp_rr_request_struct *)netperf_request.content.test_specific_data;
+  tcp_rr_response =
+    (struct tcp_rr_response_struct *)netperf_response.content.test_specific_data;
+  tcp_rr_results =
+    (struct tcp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_tcp_nbrr: 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_tcp_nbrr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_nbrr: 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_tcp_nbrr: requested recv alignment of %d offset %d\n",
+	    tcp_rr_request->recv_alignment,
+	    tcp_rr_request->recv_offset);
+    fprintf(where,"recv_tcp_nbrr: requested send alignment of %d offset %d\n",
+	    tcp_rr_request->send_alignment,
+	    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,
+				   tcp_rr_request->response_size,
+				   tcp_rr_request->send_alignment,
+				   tcp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   tcp_rr_request->request_size,
+				   tcp_rr_request->recv_alignment,
+				   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        = htons((unsigned short)tcp_rr_request->port);
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_nbrr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_rr_request->send_buf_size;
+  lsr_size_req = tcp_rr_request->recv_buf_size;
+  loc_nodelay = tcp_rr_request->no_delay;
+  loc_rcvavoid = tcp_rr_request->so_rcvavoid;
+  loc_sndavoid = tcp_rr_request->so_sndavoid;
+  
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_rr_request->ipfamily),
+			tcp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  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. */
+  
+  if (bind(s_listen,
+	   (struct sockaddr *)&myaddr_in,
+	   sizeof(myaddr_in)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    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();
+    
+    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();
+    
+    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. */
+  
+  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. */
+  
+  tcp_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  tcp_rr_response->measure_cpu = 0;
+
+  if (tcp_rr_request->measure_cpu) {
+    tcp_rr_response->measure_cpu = 1;
+    tcp_rr_response->cpu_rate = calibrate_local_cpu(tcp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_rr_response->send_buf_size = lss_size;
+  tcp_rr_response->recv_buf_size = lsr_size;
+  tcp_rr_response->no_delay = loc_nodelay;
+  tcp_rr_response->so_rcvavoid = loc_rcvavoid;
+  tcp_rr_response->so_sndavoid = loc_sndavoid;
+  tcp_rr_response->test_length = tcp_rr_request->test_length;
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  if ((s_data = accept(s_listen,
+		       (struct sockaddr *)&peeraddr_in,
+		       &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_nbrr: accept completes on the data connection.\n");
+    fflush(where);
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+    
+  /* now that we are connected, mark the socket as non-blocking */
+  if (!set_nonblock(s_data)) {
+    close(s_data);
+    exit(1);
+  }
+
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(tcp_rr_request->measure_cpu);
+
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (tcp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(tcp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = 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	= tcp_rr_request->request_size;
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	    if ( SOCKET_EINTR(request_bytes_recvd))
+		{
+	      /* the timer popped */
+	      timed_out = 1;
+	      break;
+		}
+#ifndef WIN32  // But what does WinNT indicate in this situation...
+	    else if (errno == EAGAIN) {
+	      Set_errno(0);
+	      if (times_up) {
+	        timed_out = 1;
+	        break;
+		  }
+	      continue;
+		}
+#endif
+	    else {
+	      netperf_response.content.serv_errno = 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... */
+      fprintf(where,"yo5\n");
+      fflush(where);						
+      break;
+    }
+    
+    /* Now, send the response to the remote */
+    if((bytes_sent=send(s_data,
+			send_ring->buffer_ptr,
+			tcp_rr_request->response_size,
+			0)) == SOCKET_ERROR) {
+      if (SOCKET_EINTR(bytes_sent)) {
+	/* the test timer has popped */
+	timed_out = 1;
+	fprintf(where,"yo6\n");
+	fflush(where);						
+	break;
+      }
+      netperf_response.content.serv_errno = 992;
+      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(tcp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer();
+
+  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_tcp_nbrr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  tcp_rr_results->bytes_received = (trans_received * 
+				    (tcp_rr_request->request_size + 
+				     tcp_rr_request->response_size));
+  tcp_rr_results->trans_received = trans_received;
+  tcp_rr_results->elapsed_time   = elapsed_time;
+  tcp_rr_results->cpu_method     = cpu_method;
+  tcp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (tcp_rr_request->measure_cpu) {
+    tcp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_nbrr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are done with the socket, free it */
+  close(s_data);
+
+  send_response();
+  
+}
+
+#endif /* DO_NBRR */
+
+
+ /* this test is intended to test the performance of establishing a */
+ /* connection, and then closing it again. this test is of somewhat */
+ /* arcane interest since no packets are exchanged between the */
+ /* user-space processes, but it will show the raw overhead of */
+ /* establishing a TCP connection. that service demand could then be */
+ /* compared with the sum of the service demands of a TCP_CRR and */
+ /* TCP_RR test - presumeably, they would all relate */
+
+void
+send_tcp_cc(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 = "\n\
+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;
+  
+  char	temp_message_ptr[1];
+  int	nummessages;
+  SOCKET	send_socket;
+  int	trans_remaining;
+  double	bytes_xferd;
+  int	rsp_bytes_left = 1;
+  int	rsp_bytes_recvd;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct addrinfo *local_res;
+  struct addrinfo *remote_res;
+
+  int                           myport;
+  int                           ret;
+
+  struct	tcp_cc_request_struct	*tcp_cc_request;
+  struct	tcp_cc_response_struct	*tcp_cc_response;
+  struct	tcp_cc_results_struct	*tcp_cc_result;
+  
+  tcp_cc_request = 
+    (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data;
+  tcp_cc_response = 
+    (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data;
+  tcp_cc_result =
+    (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data;
+  
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("TCP Connect/Close TEST",local_res,remote_res);
+  }
+  
+  /* initialize a few counters */
+  
+  nummessages	=	0;
+  bytes_xferd	=	0.0;
+  times_up 	= 	0;
+  
+  /* since there are no data buffers in this test, we need no send or */
+  /* recv rings */
+
+  if (debug) {
+    fprintf(where,"send_tcp_cc: 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_TCP_CC;
+  tcp_cc_request->recv_buf_size	        =	rsr_size_req;
+  tcp_cc_request->send_buf_size	        =	rss_size_req;
+  tcp_cc_request->recv_alignment	=	remote_recv_align;
+  tcp_cc_request->recv_offset	        =	remote_recv_offset;
+  tcp_cc_request->send_alignment	=	remote_send_align;
+  tcp_cc_request->send_offset	        =	remote_send_offset;
+  tcp_cc_request->request_size	        =	req_size;
+  tcp_cc_request->response_size	        =	rsp_size;
+  tcp_cc_request->no_delay	        =	rem_nodelay;
+  tcp_cc_request->measure_cpu	        =	remote_cpu_usage;
+  tcp_cc_request->cpu_rate	        =	remote_cpu_rate;
+  tcp_cc_request->so_rcvavoid	=	rem_rcvavoid;
+  tcp_cc_request->so_sndavoid	=	rem_sndavoid;
+  if (test_time) {
+    tcp_cc_request->test_length	=	test_time;
+  }
+  else {
+    tcp_cc_request->test_length	=	test_trans * -1;
+  }
+  tcp_cc_request->port          = atoi(remote_data_port);
+  tcp_cc_request->ipfamily  = af_to_nf(remote_res->ai_family);
+
+  if (debug > 1) {
+    fprintf(where,"netperf: send_tcp_cc: 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	=	tcp_cc_response->recv_buf_size;
+    rss_size	=	tcp_cc_response->send_buf_size;
+    rem_nodelay	=	tcp_cc_response->no_delay;
+    remote_cpu_usage=	tcp_cc_response->measure_cpu;
+    remote_cpu_rate = 	tcp_cc_response->cpu_rate;
+    /* make sure that port numbers are in network order */
+    set_port_number(remote_res,(unsigned short)tcp_cc_response->data_port_number);
+
+    if (debug) {
+      fprintf(where,"remote listen done.\n");
+      fprintf(where,"remote port is %d\n",get_port_number(remote_res));
+      fflush(where);
+    }
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    fprintf(where,
+	    "netperf: remote error %d",
+	    netperf_response.content.serv_errno);
+    perror("");
+    fflush(where);
+    exit(1);
+  }
+
+#ifdef WANT_DEMO
+  DEMO_RR_SETUP(100)
+#endif
+  
+  /* pick a nice random spot between client_port_min and */
+  /* client_port_max for our initial port number */
+  srand(getpid());
+  if (client_port_max - client_port_min) {
+    myport = client_port_min + 
+      (rand() % (client_port_max - client_port_min));
+  }
+  else {
+    myport = client_port_min;
+  }
+  /* there will be a ++ before the first call to bind, so subtract one */
+  myport--;
+  
+  /* 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_DEMO
+  if (demo_mode) {
+    HIST_timestamp(demo_one_ptr);
+  }
+#endif
+
+  /* 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)) {
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      /* timestamp just before our call to create the socket, and then */
+      /* again just after the receive raj 3/95 */
+      HIST_timestamp(&time_one);
+    }
+#endif /* WANT_HISTOGRAM */
+
+    /* set up the data socket */
+    /* newport: is this label really required any longer? */
+    /* pick a new port number */
+    myport++;
+
+    /* wrap the port number when we get to client_port_max. NOTE, some */
+    /* broken TCP's might treat the port number as a signed 16 bit */
+    /* quantity.  we aren't interested in testing such broken */
+    /* implementations :) so we won't make sure that it is below 32767 */
+    /* raj 8/94  */
+    if (myport >= client_port_max) {
+      myport = client_port_min;
+    }
+
+    /* 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. we */
+    /* could just rely on the failure of the bind to get us past this, */
+    /* but I'm guessing that in this one case at least, it is much */
+    /* faster, given that we *know* that port number is already in use */
+    /* (or rather would be in a loopback test) */
+
+    if (myport == get_port_number(remote_res)) myport++;
+
+    if (debug) {
+      if ((nummessages % 100) == 0) {
+	printf("port %d\n",myport);
+      }
+    }
+    set_port_number(local_res, (unsigned short)myport);
+    send_socket = create_data_socket(local_res);
+
+    if (send_socket == INVALID_SOCKET) {
+      perror("netperf: send_tcp_cc: tcp stream data socket");
+      exit(1);
+    }
+
+    /* we used to have a call to bind() here, but that is being
+       taken care of by create_data_socket(). raj 2005-02-08 */
+
+    /* Connect up to the remote port on the data socket  */
+    if ((ret = connect(send_socket, 
+		       remote_res->ai_addr,
+		       remote_res->ai_addrlen)) == INVALID_SOCKET){
+      if (SOCKET_EINTR(ret))
+	  {
+	    /* 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,
+	     get_port_number(remote_res));
+      printf(" from port %u \n",get_port_number(local_res));
+      exit(1);
+    }
+
+    /* we hang in a recv() to get the remote's close indication */
+
+    rsp_bytes_recvd=recv(send_socket,
+			 temp_message_ptr,
+			 rsp_bytes_left,
+			 0);
+
+
+    if (rsp_bytes_recvd == 0) {
+      /* connection close, call close. we assume that the requisite */
+      /* number of bytes have been received */
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+      DEMO_RR_INTERVAL(1)
+#endif
+
+      nummessages++;          
+      if (trans_remaining) {
+	trans_remaining--;
+      }
+    
+      if (debug > 3) {
+	fprintf(where,
+		"Transaction %d completed on local port %u\n",
+		nummessages,
+		get_port_number(local_res));
+	fflush(where);
+      }
+
+      close(send_socket);
+
+    }
+    else {
+      /* it was less than zero - an error occured */
+      if (SOCKET_EINTR(rsp_bytes_recvd))
+	  {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+	  perror("send_tcp_cc: data recv error");
+	  exit(1);
+    }
+      
+  }
+
+  
+  /* 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);
+    fprintf(where,
+	    "netperf: remote error %d",
+	     netperf_response.content.serv_errno);
+    perror("");
+    fflush(where);
+      
+    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	= (float) -1.0;
+      local_service_demand	= (float) -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 = tcp_cc_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,
+						  tcp_cc_result->num_cpus);
+    }
+    else {
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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:
+    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;
+    }
+  }
+  
+  /* 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,
+	    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
+recv_tcp_cc()
+{
+  
+  char  *message;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct	sockaddr_storage        myaddr_in,  peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	addrlen;
+  char	*recv_message_ptr;
+  char	*send_message_ptr;
+  int	trans_received;
+  int	trans_remaining;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	tcp_cc_request_struct	*tcp_cc_request;
+  struct	tcp_cc_response_struct	*tcp_cc_response;
+  struct	tcp_cc_results_struct	*tcp_cc_results;
+  
+  tcp_cc_request = 
+    (struct tcp_cc_request_struct *)netperf_request.content.test_specific_data;
+  tcp_cc_response = 
+    (struct tcp_cc_response_struct *)netperf_response.content.test_specific_data;
+  tcp_cc_results = 
+    (struct tcp_cc_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_tcp_cc: 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_tcp_cc: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = TCP_CC_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_cc: 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_tcp_cc: requested recv alignment of %d offset %d\n",
+	    tcp_cc_request->recv_alignment,
+	    tcp_cc_request->recv_offset);
+    fprintf(where,
+	    "recv_tcp_cc: requested send alignment of %d offset %d\n",
+	    tcp_cc_request->send_alignment,
+	    tcp_cc_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->recv_alignment, tcp_cc_request->recv_offset);
+  
+  send_message_ptr = ALIGN_BUFFER(message, tcp_cc_request->send_alignment, tcp_cc_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_tcp_cc: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_tcp_cc: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = tcp_cc_request->send_buf_size;
+  lsr_size_req = tcp_cc_request->recv_buf_size;
+  loc_nodelay = tcp_cc_request->no_delay;
+  loc_rcvavoid = tcp_cc_request->so_rcvavoid;
+  loc_sndavoid = tcp_cc_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(tcp_cc_request->ipfamily),
+			tcp_cc_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(tcp_cc_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  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);
+  }
+
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+
+  /* 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. */
+  
+  tcp_cc_response->data_port_number = 
+    (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
+  if (debug) {
+    fprintf(where,"telling the remote to call me at %d\n",
+	    tcp_cc_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. */
+  
+  tcp_cc_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (tcp_cc_request->measure_cpu) {
+    tcp_cc_response->measure_cpu = 1;
+    tcp_cc_response->cpu_rate = 
+      calibrate_local_cpu(tcp_cc_request->cpu_rate);
+  }
+  
+
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  tcp_cc_response->send_buf_size = lss_size;
+  tcp_cc_response->recv_buf_size = lsr_size;
+  tcp_cc_response->no_delay = loc_nodelay;
+  tcp_cc_response->so_rcvavoid = loc_rcvavoid;
+  tcp_cc_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(tcp_cc_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (tcp_cc_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(tcp_cc_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = tcp_cc_request->test_length * -1;
+  }
+  
+  trans_received = 0;
+
+  while ((!times_up) || (trans_remaining > 0)) {
+#ifdef WIN32
+    /* The test timer will probably fire during this accept, 
+       so to make the start_timer above work we have to move
+       it to close s_listen while we are blocked on accept. */
+    win_kludge_socket = s_listen;
+#endif
+    /* 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_tcp_cc: accept: errno = %d\n",errno);
+      fflush(where);
+      close(s_listen);
+      
+      exit(1);
+    }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+    /* this is for those systems which *INCORRECTLY* fail to pass */
+    /* attributes across an accept() call. Including this goes against */
+    /* my better judgement :( raj 11/95 */
+    
+    kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+
+    if (debug) {
+      fprintf(where,"recv_tcp_cc: accepted data connection.\n");
+      fflush(where);
+    }
+  
+
+    /* close the connection. the server will likely do a graceful */
+    /* close of the connection, insuring that all data has arrived at */
+    /* the client. for this it will call shutdown(), and then recv() and */
+    /* then close(). I'm reasonably confident that this is the */
+    /* appropriate sequence of calls - I would like to hear of */
+    /* examples in web servers to the contrary. raj 10/95*/
+    close(s_data);
+
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_tcp_cc: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(tcp_cc_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_tcp_cc: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  tcp_cc_results->bytes_received	= (trans_received * 
+					   (tcp_cc_request->request_size + 
+					    tcp_cc_request->response_size));
+  tcp_cc_results->trans_received	= trans_received;
+  tcp_cc_results->elapsed_time	= elapsed_time;
+  if (tcp_cc_request->measure_cpu) {
+    tcp_cc_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_tcp_cc: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+void
+print_sockets_usage()
+{
+
+  fwrite(sockets_usage, sizeof(char), strlen(sockets_usage), stdout);
+  exit(1);
+
+}
+
+void
+scan_sockets_args(int argc, char *argv[])
+
+{
+
+#define SOCKETS_ARGS "b:CDnNhH:L:m:M:p:P:r:s:S:T:Vw:W:z46"
+
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	
+    arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+
+  if (debug) {
+    int i;
+    printf("%s called with the following argument vector\n",
+	   __func__);
+    for (i = 0; i< argc; i++) {
+      printf("%s ",argv[i]);
+    }
+    printf("\n");
+  }
+
+  strncpy(local_data_port,"0",sizeof(local_data_port));
+  strncpy(remote_data_port,"0",sizeof(remote_data_port));
+
+  /* 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, SOCKETS_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case '4':
+      remote_data_family = AF_INET;
+      local_data_family = AF_INET;
+      break;
+    case '6':
+#if defined(AF_INET6)
+      remote_data_family = AF_INET6;
+      local_data_family = AF_INET6;
+#else
+      fprintf(stderr,
+	      "This netperf was not compiled on an IPv6 capable host!\n");
+      fflush(stderr);
+      exit(-1);
+#endif
+      break;
+    case 'h':
+      print_sockets_usage();
+      exit(1);
+    case 'b':
+#ifdef WANT_FIRST_BURST
+      first_burst_size = atoi(optarg);
+#else /* WANT_FIRST_BURST */
+      printf("Initial request burst functionality not compiled-in!\n");
+#endif /* WANT_FIRST_BURST */
+      break;
+    case 'C':
+#ifdef TCP_CORK
+      /* set TCP_CORK */
+      loc_tcpcork = 1;
+      rem_tcpcork = 1; /* however, at first, we ony have cork affect loc */
+#else 
+      printf("WARNING: TCP_CORK not available on this platform!\n");
+#endif /* TCP_CORK */
+      break;
+    case 'D':
+      /* set the TCP nodelay flag */
+      loc_nodelay = 1;
+      rem_nodelay = 1;
+      break;
+    case 'H':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	remote_data_address = malloc(strlen(arg1)+1);
+	strncpy(remote_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	remote_data_family = parse_address_family(arg2);
+      break;
+    case 'L':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	local_data_address = malloc(strlen(arg1)+1);
+	strncpy(local_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	local_data_family = parse_address_family(arg2);
+      break;
+    case 's':
+      /* set local socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lss_size_req = convert(arg1);
+      if (arg2[0])
+	lsr_size_req = convert(arg2);
+      break;
+    case 'S':
+      /* set remote socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rss_size_req = convert(arg1);
+      if (arg2[0])
+	rsr_size_req = 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 'n':
+      /* set the local socket type*/
+      local_connected = 1;
+      break;
+    case 'N':
+      /* set the remote socket type*/
+      remote_connected = 1;
+      break;
+    case 'p':
+      /* set the min and max port numbers for the TCP_CRR and TCP_TRR */
+      /* tests. */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	client_port_min = atoi(arg1);
+      if (arg2[0])	
+	client_port_max = atoi(arg2);
+      break;
+    case 'P':
+      /* set the local and remote data port numbers for the tests to
+	 allow them to run through those blankety blank end-to-end
+	 breaking firewalls. raj 2004-06-15 */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(local_data_port,arg1,sizeof(local_data_port));
+      if (arg2[0])	
+	strncpy(remote_data_port,arg2,sizeof(remote_data_port));
+      break;
+    case 't':
+      /* set the test name */
+      strcpy(test_name,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;
+    };
+  }
+
+#if defined(WANT_FIRST_BURST) 
+#if defined(WANT_HISTOGRAM)
+  /* if WANT_FIRST_BURST and WANT_HISTOGRAM are defined and the user
+     indeed wants a non-zero first burst size, and we would emit a
+     histogram, then we should emit a warning that the two are not
+     compatible. raj 2006-01-31 */
+  if ((first_burst_size > 0) && (verbosity >= 2)) {
+    fprintf(stderr,
+	    "WARNING! Histograms and first bursts are incompatible!\n");
+    fflush(stderr);
+  }
+#endif
+#endif
+
+  /* we do not want to make remote_data_address non-NULL because if
+     the user has not specified a remote adata address, we want to
+     take it from the hostname in the -H global option. raj
+     2005-02-08 */
+
+  /* so, if there is to be no control connection, we want to have some
+     different settings for a few things */
+
+  if (no_control) {
+
+    if (strcmp(remote_data_port,"0") == 0) {
+      /* we need to select either the discard port, echo port or
+	 chargen port dedepending on the test name. raj 2007-02-08 */
+      if (strstr(test_name,"STREAM") ||
+	  strstr(test_name,"SENDFILE")) {
+	strncpy(remote_data_port,"discard",sizeof(remote_data_port));
+      }
+      else if (strstr(test_name,"RR")) {
+	strncpy(remote_data_port,"echo",sizeof(remote_data_port));
+      }
+      else if (strstr(test_name,"MAERTS")) {
+	strncpy(remote_data_port,"chargen",sizeof(remote_data_port));
+      }
+      else {
+	printf("No default port known for the %s test, please set one yourself\n",test_name);
+	exit(-1);
+      }
+    }
+    remote_data_port[sizeof(remote_data_port) - 1] = '\0';
+
+    /* I go back and forth on whether these should become -1 or if
+       they should become 0 for a no_control test. what do you think?
+       raj 2006-02-08 */
+
+    rem_rcvavoid = -1;
+    rem_sndavoid = -1;
+    rss_size_req = -1;
+    rsr_size_req = -1;
+    rem_nodelay = -1;
+
+    if (strstr(test_name,"STREAM") ||
+	strstr(test_name,"SENDFILE")) {
+      recv_size = -1;
+    }
+    else if (strstr(test_name,"RR")) {
+      /* I am however _certain_ that for a no control RR test the
+	 response size must equal the request size since 99 times out
+	 of ten we will be speaking to the echo service somewhere */
+      rsp_size = req_size;
+    }
+    else if (strstr(test_name,"MAERTS")) {
+      send_size = -1;
+    }
+    else {
+      printf("No default port known for the %s test, please set one yourself\n",test_name);
+      exit(-1);
+    }
+  }
+}
diff --git a/nettest_bsd.h b/nettest_bsd.h
new file mode 100644
index 0000000..5491290
--- /dev/null
+++ b/nettest_bsd.h
@@ -0,0 +1,471 @@
+/*
+        Copyright (C) 1993-2004 Hewlett-Packard Company
+*/
+
+ /* This file contains the test-specific definitions for netperf's BSD */
+ /* sockets tests */
+
+/* well boys and girls, seems that while AF_INET is "2" and AF_UNSPEC
+   is "0" the world over, AF_INET6 is different values depending on
+   the platform... grrr.  On HP-UX 11i it is "22" and on Linux 2.6 it
+   is "10" sooooo... we have to define our own space for netperf to
+   enable us to pass values around from machine to machine. raj
+   2005-02-08 */
+#define NF_UNSPEC 0
+#define NF_INET   4
+#define NF_INET6  6
+
+struct	tcp_stream_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	receive_size;   /* how many bytes do we want to receive at one */
+			/* time? */ 
+  int	recv_alignment; /* what is the alignment of the receive */
+			/* buffer? */ 
+  int	recv_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;       /* the address family of ipaddress */
+};
+
+struct	tcp_stream_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	receive_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_stream_results_struct {
+  double         bytes_received;
+  unsigned int	 recv_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	tcp_maerts_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	send_size;      /* how many bytes do we want netserver to send
+			   at one time? */
+  int	send_alignment; /* what is the alignment of the send */
+			/* buffer? */ 
+  int	send_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the send buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+struct	tcp_maerts_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_maerts_results_struct {
+  double         bytes_sent;
+  unsigned int	 send_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	tcp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+struct	tcp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_rr_results_struct {
+  unsigned int  bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	tcp_conn_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+
+struct	tcp_conn_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_conn_rr_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	tcp_tran_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+
+struct	tcp_tran_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_tran_rr_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+
+};
+
+struct	udp_stream_request_struct {
+  int	recv_buf_size;
+  int	message_size;
+  int   recv_connected;
+  int	recv_alignment;
+  int	recv_offset;
+  int	checksum_off;
+  int	measure_cpu;
+  float	cpu_rate;
+  int	test_length;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+  
+};
+
+struct	udp_stream_response_struct {
+  int	recv_buf_size;
+  int	send_buf_size;
+  int	measure_cpu;
+  int	test_length;
+  int	data_port_number;
+  float	cpu_rate;
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct	udp_stream_results_struct {
+  unsigned int	messages_recvd;
+  unsigned int	bytes_received;
+  float	        elapsed_time;
+  float	        cpu_util;
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+
+struct	udp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+struct	udp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct udp_rr_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	tcp_cc_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+
+struct	tcp_cc_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct tcp_cc_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+extern int   rss_size_req,     /* requested remote socket send buffer size */
+	     rsr_size_req,     /* requested remote socket recv buffer size */
+	     rss_size,         /* remote socket send buffer size       */
+	     rsr_size,         /* remote socket recv buffer size       */
+	     lss_size_req,     /* requested local socket send buffer size */
+	     lsr_size_req,     /* requested local socket recv buffer size */
+	     lss_size,         /* local  socket send buffer size       */
+	     lsr_size,         /* local  socket recv buffer size       */
+	     req_size,         /* request size                         */
+	     rsp_size,         /* response size                        */
+	     send_size,        /* how big are individual sends         */
+	     recv_size,        /* how big are individual receives      */
+	     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           */
+
+
+extern void scan_sockets_args(int argc, char *argv[]);
+extern struct addrinfo *complete_addrinfo(char *controlhost, 
+				   char *data_address, 
+				   char *port, 
+				   int family, 
+				   int type, 
+				   int protocol, 
+				   int flags);
+extern void complete_addrinfos(struct addrinfo **remote,
+			       struct addrinfo **local, 
+			       char remote_host[], 
+			       int type, 
+			       int protocol, 
+			       int flags);
+extern int af_to_nf(int af);
+extern int nf_to_af(int nf);
+extern void print_top_test_header(char test_name[], 
+				  struct addrinfo *source, 
+				  struct addrinfo *destination);
+extern void set_port_number(struct addrinfo *res, 
+			    unsigned short port);
+extern void set_hostname_and_port(char *hostname, 
+				  char *portstr, 
+				  int family, 
+				  int port);
+extern void send_tcp_stream(char remote_host[]);
+extern void send_tcp_maerts(char remote_host[]);
+extern void send_tcp_rr(char remote_host[]);
+extern void send_tcp_conn_rr(char remote_host[]);
+extern void send_tcp_cc(char remote_host[]);
+extern void send_udp_stream(char remote_host[]);
+extern void send_udp_rr(char remote_host[]);
+
+extern void recv_tcp_stream();
+extern void recv_tcp_maerts();
+extern void recv_tcp_rr();
+extern void recv_tcp_conn_rr();
+extern void recv_tcp_cc();
+extern void recv_udp_stream();
+extern void recv_udp_rr();
+
+extern void loc_cpu_rate();
+extern void rem_cpu_rate();
+
+#ifdef HAVE_ICSC_EXS
+extern void send_exs_tcp_stream(char remotehost[]);
+#endif /* HAVE_ICSC_EXS */
+
+#ifdef HAVE_SENDFILE
+extern void sendfile_tcp_stream(char remotehost[]);
+#endif /* HAVE_SENDFILE */
+
+#if !defined(HAVE_STRUCT_SOCKADDR_STORAGE) && !defined(sockaddr_storage)
+#define sockaddr_storage sockaddr_in
+#endif
+
+#ifdef DO_NBRR
+extern void send_tcp_nbrr(char remote_host[]);
+
+extern void recv_tcp_nbrr();
+#endif
+
diff --git a/nettest_dlpi.c b/nettest_dlpi.c
new file mode 100644
index 0000000..ab3e79f
--- /dev/null
+++ b/nettest_dlpi.c
@@ -0,0 +1,3798 @@
+
+/****************************************************************/
+/*								*/
+/*	nettest_dlpi.c						*/
+/*								*/
+/*	the actual test routines...				*/
+/*								*/
+/*	send_dlpi_co_stream()	perform a CO DLPI stream test	*/
+/*	recv_dlpi_co_stream()					*/
+/*	send_dlpi_co_rr()	perform a CO DLPI req/res	*/
+/*	recv_dlpi_co_rr()					*/
+/*	send_dlpi_cl_stream()	perform a CL DLPI stream test	*/
+/*	recv_dlpi_cl_stream()					*/
+/*	send_dlpi_cl_rr()	perform a CL DLPI req/res	*/
+/*	recv_dlpi_cl_rr()					*/
+/*								*/
+/****************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WANT_DLPI
+char	nettest_dlpi_id[]="\
+@(#)nettest_dlpi.c (c) Copyright 1993,1995,2004 Hewlett-Packard Co. Version 2.4.3";
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <malloc.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/poll.h>
+#ifdef __osf__
+#include <sys/dlpihdr.h>
+#else /* __osf__ */
+#include <sys/dlpi.h>
+#ifdef __hpux__
+#include <sys/dlpi_ext.h>
+#endif /* __hpux__ */
+#endif /* __osf__ */
+
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_dlpi.h"
+
+/* these are some variables global to all the DLPI tests. declare */
+/* them static to make them global only to this file */
+
+static int 
+  rsw_size,		/* remote send window size	*/
+  rrw_size,		/* remote recv window size	*/
+  lsw_size,		/* local  send window size 	*/
+  lrw_size,		/* local  recv window size 	*/
+  req_size = 100,	/* request size                   	*/
+  rsp_size = 200,	/* response size			*/
+  send_size,		/* how big are individual sends		*/
+  recv_size;		/* how big are individual receives	*/
+
+int
+  loc_ppa = 4,          /* the ppa for the local interface, */
+  /* as shown as the NM Id in lanscan */
+  rem_ppa = 4,          /* the ppa for the remote interface */
+  dlpi_sap = 84;        /* which 802.2 SAP should we use?   */
+
+char loc_dlpi_device[32] = "/dev/dlpi";
+char rem_dlpi_device[32] = "/dev/dlpi";
+
+char dlpi_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+CO/CL DLPI Test Options:\n\
+    -D dev[,dev]      Set the local/remote DLPI device file name\n\
+    -h                Display this text\n\
+    -M bytes          Set the recv size (DLCO_STREAM, DLCL_STREAM)\n\
+    -m bytes          Set the send size (DLCO_STREAM, DLCL_STREAM)\n\
+    -p loc[,rem]      Set the local/remote PPA for the test\n\
+    -R bytes          Set response size (DLCO_RR, DLCL_RR)\n\
+    -r bytes          Set request size (DLCO_RR, DLCL_RR)\n\
+    -s sap            Set the 802.2 sap for the test\n\
+    -W send[,recv]    Set remote send/recv window sizes\n\
+    -w send[,recv]    Set local send/recv window sizes\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 implements the CO unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_dlpi_co_stream()
+{
+  
+  char *tput_title = "\
+Recv   Send    Send                          \n\
+Window Window  Message  Elapsed              \n\
+Size   Size    Size     Time     Throughput  \n\
+frames frames  bytes    secs.    %s/sec  \n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1 =
+    "%5d  %5d  %6d    %-6.2f   %7.2f   \n";
+  
+  char *cpu_title = "\
+Recv   Send    Send                          Utilization    Service Demand\n\
+Window Window  Message  Elapsed              Send   Recv    Send    Recv\n\
+Size   Size    Size     Time     Throughput  local  remote  local   remote\n\
+frames frames  bytes    secs.    %-8.8s/s  %%      %%       us/KB   us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f\n";
+  
+  char *cpu_fmt_1 =
+    "%5d  %5d  %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";
+  
+  
+  float			elapsed_time;
+  
+#ifdef WANT_INTERVALS
+  int interval_count;
+#endif /* WANT_INTERVALS */
+  
+  /* 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. */
+  
+  struct ring_elt *send_ring;
+  char	*message;
+  char	*message_ptr;
+  struct strbuf send_message;
+  char  dlsap[BUFSIZ];
+  int   dlsap_len;
+  int	*message_int_ptr;
+  int	message_offset;
+  int	malloc_size;
+  
+  int	len;
+  int	nummessages;
+  int	send_descriptor;
+  int	bytes_remaining;
+  /* with links like fddi, one can send > 32 bits worth of bytes */
+  /* during a test... ;-) */
+  double	bytes_sent;
+  
+#ifdef DIRTY
+  int	i;
+#endif /* DIRTY */
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct	dlpi_co_stream_request_struct	*dlpi_co_stream_request;
+  struct	dlpi_co_stream_response_struct	*dlpi_co_stream_response;
+  struct	dlpi_co_stream_results_struct	*dlpi_co_stream_result;
+  
+  dlpi_co_stream_request	= 
+    (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_co_stream_response	=
+    (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_co_stream_result	        = 
+    (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if ( print_headers ) {
+    fprintf(where,"DLPI CO STREAM 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_sent	=	0.0;
+  times_up 	= 	0;
+  
+  /*set up the data descriptor                        */
+  send_descriptor = dl_open(loc_dlpi_device,loc_ppa);  
+  if (send_descriptor < 0){
+    perror("netperf: send_dlpi_co_stream: dlpi stream data descriptor");
+    exit(1);
+  }
+  
+  /* bind the puppy and get the assigned dlsap */
+  dlsap_len = BUFSIZ;
+  if (dl_bind(send_descriptor, 
+              dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
+    fprintf(where,"send_dlpi_co_rr: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_dlpi_co_stream: send_descriptor obtained...\n");
+  }
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  if (lsw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_co_stream: window send size altered from system default...\n");
+      fprintf(where,"                          send: %d\n",lsw_size);
+    }
+  }
+  if (lrw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: send_dlpi_co_stream: window recv size altered from system default...\n");
+      fprintf(where,"                          recv: %d\n",lrw_size);
+    }
+  }
+  
+  
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+  
+  
+  if (debug) {
+    fprintf(where,
+	    "netperf: send_dlpi_co_stream: window sizes determined...\n");
+    fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
+    ffluch(where);
+  }
+  
+#else /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  lsw_size = -1;
+  lrw_size = -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* we should pick a default send_size, it should not be larger than */
+  /* the min of the two interface MTU's, and should perhaps default to */
+  /* the Interface MTU, but for now, we will default it to 1024... if */
+  /* someone wants to change this, the should change the corresponding */
+  /* lines in the recv_dlpi_co_stream routine */
+  
+  if (send_size == 0) {
+    send_size = 1024;
+  }
+  
+  /* set-up the data buffer with the requested alignment and offset. */
+  /* After we have calculated the proper starting address, we want to */
+  /* put that back into the message variable so we go back to the */
+  /* proper place. note that this means that only the first send is */
+  /* guaranteed to be at the alignment specified by the -a parameter. I */
+  /* think that this is a little more "real-world" than what was found */
+  /* in previous versions. 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 = (lsw_size/send_size) + 1;
+    if (send_width == 1) send_width++;
+  }
+  
+  send_ring = allocate_buffer_ring(send_width,
+				   send_size,
+				   local_send_align,
+				   local_send_offset);
+  
+  send_message.maxlen = send_size;
+  send_message.len = send_size;
+  send_message.buf = send_ring->buffer_ptr;
+  
+  /* 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. */
+  
+  netperf_request.content.request_type	 =	DO_DLPI_CO_STREAM;
+  dlpi_co_stream_request->send_win_size =	rsw_size;
+  dlpi_co_stream_request->recv_win_size =	rrw_size;
+  dlpi_co_stream_request->receive_size	 =	recv_size;
+  dlpi_co_stream_request->recv_alignment=	remote_recv_align;
+  dlpi_co_stream_request->recv_offset	 =	remote_recv_offset;
+  dlpi_co_stream_request->measure_cpu	 =	remote_cpu_usage;
+  dlpi_co_stream_request->cpu_rate	 =	remote_cpu_rate;
+  dlpi_co_stream_request->ppa           =      rem_ppa;
+  dlpi_co_stream_request->sap           =      dlpi_sap;
+  dlpi_co_stream_request->dev_name_len  =      strlen(rem_dlpi_device);
+  strcpy(dlpi_co_stream_request->dlpi_device,
+	 rem_dlpi_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 *) dlpi_co_stream_request->dlpi_device;
+    lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = ntohl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  if (test_time) {
+    dlpi_co_stream_request->test_length	=	test_time;
+  }
+  else {
+    dlpi_co_stream_request->test_length	=	test_bytes;
+  }
+#ifdef DIRTY
+  dlpi_co_stream_request->dirty_count       =       rem_dirty_count;
+  dlpi_co_stream_request->clean_count       =       rem_clean_count;
+#endif /* DIRTY */
+  
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "netperf: send_dlpi_co_stream: requesting DLPI CO stream test\n");
+  }
+  
+  send_request();
+  
+  /* The response from the remote will contain all of the relevant 	*/
+  /* 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");
+    rrw_size	=	dlpi_co_stream_response->recv_win_size;
+    rsw_size	=	dlpi_co_stream_response->send_win_size;
+    remote_cpu_usage=	dlpi_co_stream_response->measure_cpu;
+    remote_cpu_rate = 	dlpi_co_stream_response->cpu_rate;
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    exit(1);
+  }
+  
+  /* Connect up to the remote port on the data descriptor */
+  if(dl_connect(send_descriptor,
+		dlpi_co_stream_response->station_addr,
+		dlpi_co_stream_response->station_addr_len) != 0) {
+    fprintf(where,"recv_dlpi_co_stream: connect failure\n");
+    fflush(where);
+    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;
+    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);
+  
+  /* 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. */
+  
+#ifdef DIRTY
+  /* initialize the random number generator for putting dirty stuff */
+  /* into the send buffer. raj */
+  srand((int) getpid());
+#endif /* DIRTY */
+  
+  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. */
+    message_int_ptr = (int *)message_ptr;
+    for (i = 0; i < loc_dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < loc_clean_count; i++) {
+      loc_dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+    
+    if((putmsg(send_descriptor,
+	       0,
+	       &send_message,
+	       0)) != 0) {
+      if (errno == EINTR)
+	break;
+      perror("netperf: data send error");
+      exit(1);
+    }
+    send_ring = send_ring->next;
+    send_message.buf = send_ring->buffer_ptr;
+#ifdef WANT_INTERVALS
+    for (interval_count = 0;
+	 interval_count < interval_wate;
+	 interval_count++);
+#endif /* WANT_INTERVALS */
+    
+    if (debug > 4) {
+      fprintf(where,"netperf: send_clpi_co_stream: putmsg called ");
+      fprintf(where,"len is %d\n",send_message.len);
+      fflush(where);
+    }
+    
+    nummessages++;          
+    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. this needs a little work - there is no three-way */
+  /* handshake with type two as there is with TCP, so there really */
+  /* should be a message exchange here. however, we will finesse it by */
+  /* saying that the tests shoudl run for a while. */ 
+  
+  if (debug) {
+    fprintf(where,"sending test end signal \n");
+    fflush(where);
+  }
+  
+  send_message.len = (send_size - 1);
+  if (send_message.len == 0) send_message.len = 2;
+  
+  if((putmsg(send_descriptor,
+	     0,
+	     &send_message,
+	     0)) != 0) {
+    perror("netperf: data send error");
+    exit(1);
+  }
+  
+  /* 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 ;-) */
+  
+  bytes_sent	= ((double) send_size * (double) nummessages) + (double) len;
+  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) {
+      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);
+      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) {
+      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	= dlpi_co_stream_result->cpu_util;
+      remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      dlpi_co_stream_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:
+    case 2:
+      fprintf(where,
+	      cpu_fmt_1,		/* the format string */
+	      rrw_size,		/* remote recvbuf size */
+	      lsw_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:
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      rrw_size, 		/* remote recvbuf size */
+	      lsw_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... */
+    
+    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)dlpi_co_stream_result->recv_calls,
+	    dlpi_co_stream_result->recv_calls);
+  }
+  
+}
+
+
+/* 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. */
+
+int 
+  recv_dlpi_co_stream()
+{
+  
+  int	data_descriptor;
+  int	flags = 0;
+  int	measure_cpu;
+  int	bytes_received;
+  int	receive_calls;
+  float	elapsed_time;
+  
+  struct ring_elt *recv_ring;
+  char	*message_ptr;
+  char	*message;
+  int   *message_int_ptr;
+  struct strbuf recv_message;
+  int   dirty_count;
+  int   clean_count;
+  int   i;
+  
+  struct	dlpi_co_stream_request_struct	*dlpi_co_stream_request;
+  struct	dlpi_co_stream_response_struct	*dlpi_co_stream_response;
+  struct	dlpi_co_stream_results_struct	*dlpi_co_stream_results;
+  
+  dlpi_co_stream_request	= (struct dlpi_co_stream_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_co_stream_response	= (struct dlpi_co_stream_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_co_stream_results	= (struct dlpi_co_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dlpi_co_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. */
+  
+  netperf_response.content.response_type = DLPI_CO_STREAM_RESPONSE;
+  
+  /* We now alter the message_ptr variable to be at the desired */
+  /* alignment with the desired offset. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_dlpi_co_stream: requested alignment of %d\n",
+	    dlpi_co_stream_request->recv_alignment);
+    fflush(where);
+  }
+  
+  
+  /* Grab a descriptor to listen on, and then listen on it. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_dlpi_co_stream: grabbing a descriptor...\n");
+    fflush(where);
+  }
+  
+  
+  
+#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 *) dlpi_co_stream_request->dlpi_device;
+    lastword = initword + ((dlpi_co_stream_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  data_descriptor = dl_open(dlpi_co_stream_request->dlpi_device,
+			    dlpi_co_stream_request->ppa);
+  if (data_descriptor < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* Let's get an address assigned to this descriptor so we can tell the */
+  /* initiator how to reach the data descriptor. There may be a desire to */
+  /* nail this descriptor to a specific address in a multi-homed, */
+  /* multi-connection situation, but for now, we'll ignore the issue */
+  /* and concentrate on single connection testing. */
+  
+  /* bind the sap and retrieve the dlsap assigned by the system  */
+  dlpi_co_stream_response->station_addr_len = 14; /* arbitrary */
+  if (dl_bind(data_descriptor,
+	      dlpi_co_stream_request->sap,
+	      DL_CODLS,
+	      (char *)dlpi_co_stream_response->station_addr,
+	      &dlpi_co_stream_response->station_addr_len) != 0) {
+    fprintf(where,"recv_dlpi_co_stream: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  /* The initiator may have wished-us to modify the socket buffer */
+  /* sizes. We should give it a shot. If he didn't ask us to change the */
+  /* sizes, we should let him know what sizes were in use at this end. */
+  /* If none of this code is compiled-in, then we will tell the */
+  /* initiator that we were unable to play with the socket buffer by */
+  /* setting the size in the response to -1. */
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  
+  if (dlpi_co_stream_request->recv_win_size) {
+  }
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+  
+#else /* the system won't let us play with the buffers */
+  
+  dlpi_co_stream_response->recv_win_size	= -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* what sort of sizes did we end-up with? */
+  /* this bit of code whould default to the Interface MTU */
+  if (dlpi_co_stream_request->receive_size == 0) {
+    recv_size = 1024;
+  }
+  else {
+    recv_size = dlpi_co_stream_request->receive_size;
+  }
+  
+  /* tell the other fellow what our receive size became */
+  dlpi_co_stream_response->receive_size = recv_size;
+  
+  /* just a little prep work for when we may have to behave like the */
+  /* sending side... */
+  message = (char *)malloc(recv_size * 2);
+  if (message == NULL) {
+    printf("malloc(%d) failed!\n", recv_size * 2);
+    exit(1);
+  }
+
+  message_ptr = ALIGN_BUFFER(message, dlpi_co_stream_request->recv_alignment, dlpi_co_stream_request->recv_offset);
+  recv_message.maxlen = recv_size;
+  recv_message.len = 0;
+  recv_message.buf = message_ptr;
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_dlpi_co_stream: receive alignment and offset set...\n");
+    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 -1 to */
+  /* the initiator. */
+  
+  dlpi_co_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dlpi_co_stream_request->measure_cpu) {
+    dlpi_co_stream_response->measure_cpu = 1;
+    dlpi_co_stream_response->cpu_rate = 
+      calibrate_local_cpu(dlpi_co_stream_request->cpu_rate);
+  }
+  
+  send_response();
+  
+  /* accept a connection on this file descriptor. at some point, */
+  /* dl_accept will "do the right thing" with the last two parms, but */
+  /* for now it ignores them, so we will pass zeros. */
+  
+  if(dl_accept(data_descriptor, 0, 0) != 0) {
+    fprintf(where,
+	    "recv_dlpi_co_stream: error in accept, errno %d\n",
+	    errno);
+    fflush(where);
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"netserver:recv_dlpi_co_stream: connection accepted\n");
+    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(dlpi_co_stream_request->measure_cpu);
+  
+#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. */
+  
+  dirty_count = dlpi_co_stream_request->dirty_count;
+  clean_count = dlpi_co_stream_request->clean_count;
+  message_int_ptr = (int *)message_ptr;
+  for (i = 0; i < dirty_count; i++) {
+    *message_int_ptr = rand();
+    message_int_ptr++;
+  }
+  for (i = 0; i < clean_count; i++) {
+    dirty_count = *message_int_ptr;
+    message_int_ptr++;
+  }
+#endif /* DIRTY */
+  
+  recv_message.len = recv_size; 
+  while (recv_message.len == recv_size) {
+    if (getmsg(data_descriptor, 
+	       0,
+	       &recv_message, 
+	       &flags) != 0) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    bytes_received += recv_message.len;
+    receive_calls++;
+    
+    if (debug) {
+      fprintf(where,
+	      "netserver:recv_dlpi_co_stream: getmsg accepted %d bytes\n",
+	      recv_message.len);
+      fflush(where);
+    }
+    
+    
+#ifdef DIRTY
+    message_int_ptr = (int *)message_ptr;
+    for (i = 0; i < dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < clean_count; i++) {
+      dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+    
+  }
+  
+  /* The loop now exits due to zero bytes received. */
+  /* should perform a disconnect to signal the sender that */
+  /* we have received all the data sent. */
+  
+  if (close(data_descriptor) == -1) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  cpu_stop(dlpi_co_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dlpi_co_stream: got %d bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_dlpi_co_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  dlpi_co_stream_results->bytes_received	= bytes_received;
+  dlpi_co_stream_results->elapsed_time	= elapsed_time;
+  dlpi_co_stream_results->recv_calls		= receive_calls;
+  
+  if (dlpi_co_stream_request->measure_cpu) {
+    dlpi_co_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_dlpi_co_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+}
+
+/*********************************/
+
+int send_dlpi_co_rr(char remote_host[])
+{
+  
+  char *tput_title = "\
+ Local /Remote\n\
+ Window Size   Request  Resp.   Elapsed  Trans.\n\
+ Send   Recv   Size     Size    Time     Rate         \n\
+ frames frames 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\
+ Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
+ Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
+ frames frames 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			timed_out = 0;
+  float			elapsed_time;
+  int	    dlsap_len;
+  char      dlsap[BUFSIZ];
+  
+  int   flags = 0;
+  char	*send_message_ptr;
+  char	*recv_message_ptr;
+  char	*temp_message_ptr;
+  struct strbuf send_message;
+  struct strbuf recv_message;
+  
+  int	nummessages;
+  int	send_descriptor;
+  int	trans_remaining;
+  double	bytes_xferd;
+  
+  int	rsp_bytes_left;
+  
+  /* we assume that station adresses fit within two ints */
+  unsigned int   remote_address[1];
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct	dlpi_co_rr_request_struct	*dlpi_co_rr_request;
+  struct	dlpi_co_rr_response_struct	*dlpi_co_rr_response;
+  struct	dlpi_co_rr_results_struct	*dlpi_co_rr_result;
+  
+  dlpi_co_rr_request	= 
+    (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_co_rr_response	= 
+    (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_co_rr_result	= 
+    (struct dlpi_co_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. */
+  
+  if ( print_headers ) {
+    fprintf(where,"DLPI CO 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 */
+  temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
+    exit(1);
+  }
+  send_message_ptr = (char *)(( (long) temp_message_ptr + 
+			       (long) local_send_align - 1) &	
+			      ~((long) local_send_align - 1));
+  send_message_ptr = send_message_ptr + local_send_offset;
+  send_message.maxlen = req_size+MAXALIGNMENT+MAXOFFSET;
+  send_message.len    = req_size;
+  send_message.buf    = send_message_ptr;
+  
+  temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
+    exit(1);
+  }
+  recv_message_ptr = (char *)(( (long) temp_message_ptr + 
+			       (long) local_recv_align - 1) &	
+			      ~((long) local_recv_align - 1));
+  recv_message_ptr = recv_message_ptr + local_recv_offset;
+  recv_message.maxlen = rsp_size+MAXALIGNMENT+MAXOFFSET;
+  recv_message.len    = 0;
+  recv_message.buf    = send_message_ptr;
+  
+  /*set up the data socket                        */
+  
+  send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
+  if (send_descriptor < 0){
+    perror("netperf: send_dlpi_co_rr: tcp stream data descriptor");
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_dlpi_co_rr: send_descriptor obtained...\n");
+  }
+  
+  /* bind the puppy and get the assigned dlsap */
+  
+  dlsap_len = BUFSIZ;
+  if (dl_bind(send_descriptor, 
+	      dlpi_sap, DL_CODLS, dlsap, &dlsap_len) != 0) {
+    fprintf(where,"send_dlpi_co_rr: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  /* 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 DL_HP_SET_LOCAL_WIN_REQ
+  if (lsw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_co_rr: socket send size altered from system default...\n");
+      fprintf(where,"                          send: %d\n",lsw_size);
+    }
+  }
+  if (lrw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_co_rr: socket recv size altered from system default...\n");
+      fprintf(where,"                          recv: %d\n",lrw_size);
+    }
+  }
+  
+  
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+  
+  
+  if (debug) {
+    fprintf(where,"netperf: send_dlpi_co_rr: socket sizes determined...\n");
+    fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
+  }
+  
+#else /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  lsw_size = -1;
+  lrw_size = -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* 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_DLPI_CO_RR;
+  dlpi_co_rr_request->recv_win_size	=	rrw_size;
+  dlpi_co_rr_request->send_win_size	=	rsw_size;
+  dlpi_co_rr_request->recv_alignment	=	remote_recv_align;
+  dlpi_co_rr_request->recv_offset	=	remote_recv_offset;
+  dlpi_co_rr_request->send_alignment	=	remote_send_align;
+  dlpi_co_rr_request->send_offset	=	remote_send_offset;
+  dlpi_co_rr_request->request_size	=	req_size;
+  dlpi_co_rr_request->response_size	=	rsp_size;
+  dlpi_co_rr_request->measure_cpu	=	remote_cpu_usage;
+  dlpi_co_rr_request->cpu_rate	        =	remote_cpu_rate;
+  dlpi_co_rr_request->ppa               =       rem_ppa;
+  dlpi_co_rr_request->sap               =       dlpi_sap;
+  dlpi_co_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
+  strcpy(dlpi_co_rr_request->dlpi_device,
+	 rem_dlpi_device);
+#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 *) dlpi_co_rr_request->dlpi_device;
+    lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = ntohl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  if (test_time) {
+    dlpi_co_rr_request->test_length	=	test_time;
+  }
+  else {
+    dlpi_co_rr_request->test_length	=	test_trans * -1;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"netperf: send_dlpi_co_rr: 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");
+    rrw_size	=	dlpi_co_rr_response->recv_win_size;
+    rsw_size	=	dlpi_co_rr_response->send_win_size;
+    remote_cpu_usage=	dlpi_co_rr_response->measure_cpu;
+    remote_cpu_rate = 	dlpi_co_rr_response->cpu_rate;
+    
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    
+    exit(1);
+  }
+  
+  /*Connect up to the remote port on the data descriptor  */
+  
+  if(dl_connect(send_descriptor,
+		dlpi_co_rr_response->station_addr,
+		dlpi_co_rr_response->station_addr_len) != 0) {
+    fprintf(where,"send_dlpi_co_rr: connect failure\n");
+    fflush(where);
+    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);
+  
+  /* 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 */
+    if((putmsg(send_descriptor,
+	       0,
+	       &send_message,
+	       0)) != 0) {
+      if (errno == EINTR) {
+	/* we hit the end of a */
+	/* timed test. */
+	timed_out = 1;
+	break;
+      }
+      perror("send_dlpi_co_rr: putmsg error");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"recv_message.len %d\n",recv_message.len);
+      fprintf(where,"send_message.len %d\n",send_message.len);
+      fflush(where);
+    }
+    
+    /* receive the response */
+    /* this needs some work with streams buffers if we are going to */
+    /* support requests and responses larger than the MTU of the */
+    /* network, but this can wait until later */
+    rsp_bytes_left = rsp_size;
+    recv_message.len = rsp_size;
+    while(rsp_bytes_left > 0) {
+      if((getmsg(send_descriptor,
+		 0,
+		 &recv_message,
+		 &flags)) < 0) {
+	if (errno == EINTR) {
+	  /* We hit the end of a timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_dlpi_co_rr: data recv error");
+	exit(1);
+      }
+      rsp_bytes_left -= recv_message.len;
+    }	
+    
+    if (timed_out) {
+      /* we may have been in a nested while loop - we need */
+      /* another call to break. */
+      break;
+    }
+    
+    nummessages++;          
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug > 3) {
+      fprintf(where,
+	      "Transaction %d completed\n",
+	      nummessages);
+      fflush(where);
+    }
+  }
+  
+  /* At this point we used to call shutdown onthe data socket to be */
+  /* sure all the data was delivered, but this was not germane in a */
+  /* request/response test, and it was causing the tests to "hang" when */
+  /* they were being controlled by time. So, I have replaced this */
+  /* shutdown call with a call to close that can be found later in the */
+  /* procedure. */
+  
+  /* 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 = dlpi_co_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,
+						  dlpi_co_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 */
+	      lsw_size,		/* local sendbuf size */
+	      lrw_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,
+	      rsw_size,
+	      rrw_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 */
+	      lsw_size,
+	      lrw_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,
+	      rsw_size, 		/* remote recvbuf size */
+	      rrw_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);
+  }
+  /* The test is over. Kill the data descriptor */
+  
+  if (close(send_descriptor) == -1) {
+    perror("send_dlpi_co_rr: cannot shutdown tcp stream descriptor");
+  }
+  
+}
+
+void
+  send_dlpi_cl_stream(char remote_host[])
+{
+  /************************************************************************/
+  /*									*/
+  /*               	UDP Unidirectional Send Test                    */
+  /*									*/
+  /************************************************************************/
+  char *tput_title =
+    "Window  Message  Elapsed      Messages                \n\
+Size    Size     Time         Okay Errors   Throughput\n\
+frames  bytes    secs            #      #   %s/sec\n\n";
+  
+  char *tput_fmt_0 =
+    "%7.2f\n";
+  
+  char *tput_fmt_1 =
+    "%5d   %5d    %-7.2f   %7d %6d    %7.2f\n\
+%5d            %-7.2f   %7d           %7.2f\n\n";
+  
+  
+  char *cpu_title =
+    "Window  Message  Elapsed      Messages                   CPU     Service\n\
+Size    Size     Time         Okay Errors   Throughput   Util    Demand\n\
+frames  bytes    secs            #      #   %s/sec   %%       us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.2f\n";
+  
+  char *cpu_fmt_1 =
+    "%5d   %5d    %-7.2f   %7d %6d    %7.1f      %-6.2f  %-6.3f\n\
+%5d            %-7.2f   %7d           %7.1f      %-6.2f  %-6.3f\n\n";
+  
+  int	messages_recvd;
+  float	elapsed_time,
+  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	*message_int_ptr;
+  char	*message_ptr;
+  char	*message;
+  char  sctl_data[BUFSIZ];
+  struct strbuf send_message;
+  struct strbuf sctl_message;
+  dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
+  
+  char dlsap[BUFSIZ];
+  int  dlsap_len;
+  int	message_offset;
+  int	message_max_offset;
+  int	failed_sends;
+  int	failed_cows;
+  int 	messages_sent;
+  int 	data_descriptor;
+  
+  
+#ifdef WANT_INTERVALS
+  int	interval_count;
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY
+  int	i;
+#endif /* DIRTY */
+  
+  struct	dlpi_cl_stream_request_struct	*dlpi_cl_stream_request;
+  struct	dlpi_cl_stream_response_struct	*dlpi_cl_stream_response;
+  struct	dlpi_cl_stream_results_struct	*dlpi_cl_stream_results;
+  
+  dlpi_cl_stream_request	= (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_cl_stream_response	= (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_cl_stream_results	= (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if ( print_headers ) {
+    printf("DLPI CL UNIDIRECTIONAL SEND TEST\n");
+    if (local_cpu_usage || remote_cpu_usage)
+      printf(cpu_title,format_units());
+    else
+      printf(tput_title,format_units());
+  }	
+  
+  failed_sends	= 0;
+  messages_sent	= 0;
+  times_up	= 0;
+  
+  /*set up the data descriptor			*/
+  
+  data_descriptor = dl_open(loc_dlpi_device,loc_ppa);
+  if (data_descriptor < 0){
+    perror("send_dlpi_cl_stream: data descriptor");
+    exit(1);
+  }
+  
+  /* bind the puppy and get the assigned dlsap */
+  dlsap_len = BUFSIZ;
+  if (dl_bind(data_descriptor, 
+              dlpi_sap, DL_CLDLS, dlsap, &dlsap_len) != 0) {
+    fprintf(where,"send_dlpi_cl_stream: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  /* Modify the local socket size (SNDBUF size)    */
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  if (lsw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_cl_stream: descriptor send size altered from system default...\n");
+      fprintf(where,"                          send: %d\n",lsw_size);
+    }
+  }
+  if (lrw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_cl_stream: descriptor recv size altered from system default...\n");
+      fprintf(where,"                          recv: %d\n",lrw_size);
+    }
+  }
+  
+  
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+  
+#else /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  lsw_size = -1;
+  lrw_size = -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* now, we want to see if we need to set the send_size */
+  if (send_size == 0) {
+    send_size = 1024;
+  }
+  
+  
+  /* 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;
+  message = (char *)malloc(send_size * (send_width + 1) + local_send_align + local_send_offset);
+  if (message == NULL) {
+    printf("malloc(%d) failed!\n", send_size * (send_width + 1) + local_send_align + local_send_offset);
+    exit(1);
+  }
+  message_ptr = (char *)(( (long) message + 
+			  (long) local_send_align - 1) &	
+			 ~((long) local_send_align - 1));
+  message_ptr = message_ptr + local_send_offset;
+  message = message_ptr;
+  send_message.maxlen = send_size;
+  send_message.len = send_size;
+  send_message.buf = message;
+  
+  sctl_message.maxlen = BUFSIZ;
+  sctl_message.len    = 0;
+  sctl_message.buf    = sctl_data;
+  
+  /* 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_DLPI_CL_STREAM;
+  dlpi_cl_stream_request->recv_win_size	        = rrw_size;
+  dlpi_cl_stream_request->message_size	        = send_size;
+  dlpi_cl_stream_request->recv_alignment	= remote_recv_align;
+  dlpi_cl_stream_request->recv_offset		= remote_recv_offset;
+  dlpi_cl_stream_request->measure_cpu		= remote_cpu_usage;
+  dlpi_cl_stream_request->cpu_rate		= remote_cpu_rate;
+  dlpi_cl_stream_request->ppa                   = rem_ppa;
+  dlpi_cl_stream_request->sap                   = dlpi_sap;
+  dlpi_cl_stream_request->dev_name_len          = strlen(rem_dlpi_device);
+  strcpy(dlpi_cl_stream_request->dlpi_device,
+	 rem_dlpi_device);
+  
+#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 *) dlpi_cl_stream_request->dlpi_device;
+    lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = ntohl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  if (test_time) {
+    dlpi_cl_stream_request->test_length	=	test_time;
+  }
+  else {
+    dlpi_cl_stream_request->test_length	=	test_bytes * -1;
+  }
+  
+  
+  send_request();
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"send_dlpi_cl_stream: remote data connection done.\n");
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("send_dlpi_cl_stream: error on remote");
+    exit(1);
+  }
+  
+  /* place some of the remote's addressing information into the send */
+  /* structure so our sends can be sent to the correct place. Also get */
+  /* some of the returned socket buffer information for user display. */
+  
+  /* set-up the destination addressing control info */
+  data_req->dl_primitive = DL_UNITDATA_REQ;
+  bcopy((char *)(dlpi_cl_stream_response->station_addr),
+	((char *)data_req + sizeof(dl_unitdata_req_t)),
+	dlpi_cl_stream_response->station_addr_len);
+  data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
+  data_req->dl_dest_addr_length = dlpi_cl_stream_response->station_addr_len;
+  /* there is a dl_priority structure too, but I am ignoring it for */
+  /* the time being. */
+  /* however... it is best to put some value in there lest some code
+     get grumpy about it - fix from Nicolas Thomas */
+  data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
+  data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
+
+  sctl_message.len = sizeof(dl_unitdata_req_t) + 
+    data_req->dl_dest_addr_length;
+  
+  rrw_size	        = dlpi_cl_stream_response->recv_win_size;
+  rsw_size	        = dlpi_cl_stream_response->send_win_size;
+  remote_cpu_rate	= dlpi_cl_stream_response->cpu_rate;
+  
+  
+  /* set up the timer to call us after test_time	*/
+  start_timer(test_time);
+  
+  /* Get the start count for the idle counter and the start time */
+  
+  cpu_start(local_cpu_usage);
+  
+#ifdef WANT_INTERVALS
+  interval_count = interval_burst;
+#endif /* WANT_INTERVALS */
+  
+  /* Send datagrams like there was no tomorrow */
+  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. */
+    message_int_ptr = (int *)message_ptr;
+    for (i = 0; i < loc_dirty_count; i++) {
+      *message_int_ptr = 4;
+      message_int_ptr++;
+    }
+    for (i = 0; i < loc_clean_count; i++) {
+      loc_dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+    if (putmsg(data_descriptor,
+	       &sctl_message,
+	       &send_message,
+	       0)  != 0) {
+      if (errno == EINTR) {
+	break;
+      }
+      if (errno == ENOBUFS) {
+	/* we might not ever hit this with STREAMS, it would probably */
+	/* be better to do a getinfo request at the end of the test to */
+	/* get all sorts of gory statistics. in the meantime, we will */
+	/* keep this code in place. */
+	failed_sends++;
+	continue;
+      }
+      perror("send_dlpi_cl_stream: data send error");
+      if (debug) {
+	fprintf(where,"messages_sent %u\n",messages_sent);
+	fflush(where);
+      }
+      exit(1);
+    }
+    messages_sent++;          
+    
+    /* now we want to move our pointer to the next position in the */
+    /* data buffer...since there was a successful send */
+    
+    
+#ifdef WANT_INTERVALS
+    /* 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 the sleep routine for some milliseconds, if our */
+      /* timer popped while we were in there, we want to */
+      /* break out of the loop. */
+      if (msec_sleep(interval_wate)) {
+	break;
+      }
+      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_dlpi_cl_stream: remote results obtained\n");
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("send_dlpi_cl_stream: error on remote");
+    exit(1);
+  }
+  
+  bytes_sent	= send_size * messages_sent;
+  local_thruput	= calc_thruput(bytes_sent);
+  
+  messages_recvd	= dlpi_cl_stream_results->messages_recvd;
+  bytes_recvd	= send_size * 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 descriptor 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) {
+      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);
+      local_service_demand	= calc_service_demand(bytes_sent,
+						      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) {
+      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	= dlpi_cl_stream_results->cpu_util;
+      remote_service_demand	= calc_service_demand(bytes_recvd,
+						      0.0,
+						      remote_cpu_utilization,
+						      dlpi_cl_stream_results->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,		/* the format string */
+	      lsw_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 */
+	      rrw_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:
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      lsw_size, 		/* local sendbuf size */
+	      send_size,		/* how large were the sends */
+	      elapsed_time, 		/* how long did it take */
+	      messages_sent,
+	      failed_sends,
+	      local_thruput,
+	      rrw_size, 		/* remote recvbuf size */
+	      elapsed_time,
+	      messages_recvd,
+	      remote_thruput
+	      );
+      break;
+    }
+  }
+}
+
+int
+  recv_dlpi_cl_stream()
+{
+  
+  char  *message;
+  int	data_descriptor;
+  int	len;
+  char	*message_ptr;
+  char  rctl_data[BUFSIZ];
+  struct strbuf recv_message;
+  struct strbuf rctl_message;
+  int flags = 0;
+  /* these are to make reading some of the DLPI control messages easier */
+  dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
+  dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
+  
+  int	bytes_received = 0;
+  float	elapsed_time;
+  
+  int	message_size;
+  int	messages_recvd = 0;
+  int	measure_cpu;
+  
+  struct	dlpi_cl_stream_request_struct	*dlpi_cl_stream_request;
+  struct	dlpi_cl_stream_response_struct	*dlpi_cl_stream_response;
+  struct	dlpi_cl_stream_results_struct	*dlpi_cl_stream_results;
+  
+  dlpi_cl_stream_request	= (struct dlpi_cl_stream_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_cl_stream_response	= (struct dlpi_cl_stream_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_cl_stream_results	= (struct dlpi_cl_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dlpi_cl_stream: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen descriptor 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_dlpi_cl_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = DLPI_CL_STREAM_RESPONSE;
+  
+  if (debug > 2) {
+    fprintf(where,"recv_dlpi_cl_stream: 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 variable to be at the desired */
+  /* alignment with the desired offset. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_dlpi_cl_stream: requested alignment of %d\n",
+	    dlpi_cl_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  message_ptr = ALIGN_BUFFER(message, dlpi_cl_stream_request->recv_alignment, dlpi_cl_stream_request->recv_offset);
+  
+  if (dlpi_cl_stream_request->message_size > 0) {
+    recv_message.maxlen = dlpi_cl_stream_request->message_size;
+  }
+  else {
+    recv_message.maxlen = 4096;
+  }
+  recv_message.len    = 0;
+  recv_message.buf    = message_ptr;
+  
+  rctl_message.maxlen = BUFSIZ;
+  rctl_message.len    = 0;
+  rctl_message.buf    = rctl_data;
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_dlpi_cl_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"recv_dlpi_cl_stream: grabbing a descriptor...\n");
+    fflush(where);
+  }
+  
+#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 *) dlpi_cl_stream_request->dlpi_device;
+    lastword = initword + ((dlpi_cl_stream_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  data_descriptor = dl_open(dlpi_cl_stream_request->dlpi_device,
+			    dlpi_cl_stream_request->ppa);
+  if (data_descriptor < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* The initiator may have wished-us to modify the window */
+  /* sizes. We should give it a shot. If he didn't ask us to change the */
+  /* sizes, we should let him know what sizes were in use at this end. */
+  /* If none of this code is compiled-in, then we will tell the */
+  /* initiator that we were unable to play with the sizes by */
+  /* setting the size in the response to -1. */
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  
+  if (dlpi_cl_stream_request->recv_win_size) {
+    dlpi_cl_stream_response->recv_win_size	= -1;
+  }
+  
+#else /* the system won't let us play with the buffers */
+  
+  dlpi_cl_stream_response->recv_win_size	= -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  dlpi_cl_stream_response->test_length = dlpi_cl_stream_request->test_length;
+  
+  /* bind the sap and retrieve the dlsap assigned by the system  */
+  dlpi_cl_stream_response->station_addr_len = 14; /* arbitrary */
+  if (dl_bind(data_descriptor,
+	      dlpi_cl_stream_request->sap,
+	      DL_CLDLS,
+	      (char *)dlpi_cl_stream_response->station_addr,
+	      &dlpi_cl_stream_response->station_addr_len) != 0) {
+    fprintf(where,"send_dlpi_cl_stream: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  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. */
+  
+  dlpi_cl_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dlpi_cl_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... */
+    dlpi_cl_stream_response->measure_cpu = 1;
+    dlpi_cl_stream_response->cpu_rate = calibrate_local_cpu(dlpi_cl_stream_request->cpu_rate);
+  }
+  
+  message_size	= dlpi_cl_stream_request->message_size;
+  test_time	= dlpi_cl_stream_request->test_length;
+  
+  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(dlpi_cl_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_dlpi_cl_stream: about to enter inner sanctum.\n");
+    fflush(where);
+  }
+  
+  while (!times_up) {
+    if((getmsg(data_descriptor, 
+	       &rctl_message,    
+	       &recv_message,
+	       &flags) != 0) || 
+       (data_ind->dl_primitive != DL_UNITDATA_IND)) {
+      if (errno == EINTR) {
+	/* Again, we have likely hit test-end time */
+	break;
+      }
+      fprintf(where,
+	      "dlpi_recv_cl_stream: getmsg failure: errno %d primitive 0x%x\n",
+	      errno,
+	      data_ind->dl_primitive);
+      fflush(where);
+      netperf_response.content.serv_errno = 996;
+      send_response();
+      exit(1);
+    }
+    messages_recvd++;
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_cl_stream: got %d messages.\n",messages_recvd);
+    fflush(where);
+  }
+  
+  
+  /* The loop now exits due timer or < send_size bytes received. */
+  
+  cpu_stop(dlpi_cl_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_dlpi_cl_stream: test ended in %f seconds.\n",elapsed_time);
+    fflush(where);
+  }
+  
+  
+  /* We will count the "off" message */
+  bytes_received = (messages_recvd * message_size) + len;
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dlpi_cl_stream: got %d bytes\n",
+	    bytes_received);
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type		= DLPI_CL_STREAM_RESULTS;
+  dlpi_cl_stream_results->bytes_received	= bytes_received;
+  dlpi_cl_stream_results->messages_recvd	= messages_recvd;
+  dlpi_cl_stream_results->elapsed_time	= elapsed_time;
+  if (dlpi_cl_stream_request->measure_cpu) {
+    dlpi_cl_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  else {
+    dlpi_cl_stream_results->cpu_util	= -1.0;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_dlpi_cl_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+int send_dlpi_cl_rr(char remote_host[])
+{
+  
+  char *tput_title = "\
+Local /Remote\n\
+Window Size   Request  Resp.   Elapsed  Trans.\n\
+Send   Recv   Size     Size    Time     Rate         \n\
+frames frames 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\
+Window Size   Request Resp.  Elapsed Trans.   CPU    CPU    S.dem   S.dem\n\
+Send   Recv   Size    Size   Time    Rate     local  remote local   remote\n\
+frames frames 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";
+  
+  
+  float			elapsed_time;
+  
+  int   dlsap_len;
+  int   flags = 0;
+  char	*send_message_ptr;
+  char	*recv_message_ptr;
+  char	*temp_message_ptr;
+  char  sctl_data[BUFSIZ];
+  char  rctl_data[BUFSIZ];
+  char  dlsap[BUFSIZ];
+  struct strbuf send_message;
+  struct strbuf recv_message;
+  struct strbuf sctl_message;
+  struct strbuf rctl_message;
+  
+  /* these are to make reading some of the DLPI control messages easier */
+  dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
+  dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
+  dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
+  
+  int	nummessages;
+  int	send_descriptor;
+  int	trans_remaining;
+  int	bytes_xferd;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double thruput;
+  
+#ifdef WANT_INTERVALS
+  /* timing stuff */
+#define	MAX_KEPT_TIMES	1024
+  int	time_index = 0;
+  int	unused_buckets;
+  int	kept_times[MAX_KEPT_TIMES];
+  int	sleep_usecs;
+  unsigned	int	total_times=0;
+  struct	timezone	dummy_zone;
+  struct	timeval		send_time;
+  struct	timeval		recv_time;
+  struct	timeval		sleep_timeval;
+#endif /* WANT_INTERVALS */
+  
+  struct	dlpi_cl_rr_request_struct	*dlpi_cl_rr_request;
+  struct	dlpi_cl_rr_response_struct	*dlpi_cl_rr_response;
+  struct	dlpi_cl_rr_results_struct	*dlpi_cl_rr_result;
+  
+  dlpi_cl_rr_request	= 
+    (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_cl_rr_response	= 
+    (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_cl_rr_result	= 
+    (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  /* we want to zero out the times, so we can detect unused entries. */
+#ifdef WANT_INTERVALS
+  time_index = 0;
+  while (time_index < MAX_KEPT_TIMES) {
+    kept_times[time_index] = 0;
+    time_index += 1;
+  }
+  time_index = 0;
+#endif /* WANT_INTERVALS */
+  
+  if (print_headers) {
+    fprintf(where,"DLPI CL 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;
+  times_up 	= 	0;
+  
+  /* set-up the data buffer with the requested alignment and offset */
+  temp_message_ptr = (char *)malloc(req_size+MAXALIGNMENT+MAXOFFSET);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", req_size+MAXALIGNMENT+MAXOFFSET);
+    exit(1);
+  }
+  send_message_ptr = (char *)(( (long)temp_message_ptr + 
+			       (long) local_send_align - 1) &	
+			      ~((long) local_send_align - 1));
+  send_message_ptr = send_message_ptr + local_send_offset;
+  send_message.maxlen = req_size;
+  send_message.len    = req_size;
+  send_message.buf    = send_message_ptr;
+  
+  temp_message_ptr = (char *)malloc(rsp_size+MAXALIGNMENT+MAXOFFSET);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", rsp_size+MAXALIGNMENT+MAXOFFSET);
+    exit(1);
+  }
+  recv_message_ptr = (char *)(( (long)temp_message_ptr + 
+			       (long) local_recv_align - 1) &	
+			      ~((long) local_recv_align - 1));
+  recv_message_ptr = recv_message_ptr + local_recv_offset;
+  recv_message.maxlen = rsp_size;
+  recv_message.len    = 0;
+  recv_message.buf    = recv_message_ptr;
+  
+  sctl_message.maxlen = BUFSIZ;
+  sctl_message.len    = 0;
+  sctl_message.buf    = sctl_data;
+  
+  rctl_message.maxlen = BUFSIZ;
+  rctl_message.len    = 0;
+  rctl_message.buf    = rctl_data;
+  
+  /* lets get ourselves a file descriptor */
+  
+  send_descriptor = dl_open(loc_dlpi_device,loc_ppa);
+  if (send_descriptor < 0){
+    perror("netperf: send_dlpi_cl_rr: dlpi cl rr send descriptor");
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_dlpi_cl_rr: send_descriptor obtained...\n");
+  }
+  
+  /* bind the sap to the descriptor and get the dlsap */
+  dlsap_len = BUFSIZ;
+  if (dl_bind(send_descriptor,
+	      dlpi_sap,
+	      DL_CLDLS,
+	      dlsap,
+	      &dlsap_len) != 0) {
+    fprintf(where,"send_dlpi_cl_rr: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  /* Modify the local socket size. 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.  The receive socket */
+  /* must have enough space to hold addressing information so += a */
+  /* sizeof struct sockaddr_in to it. */ 
+  
+  /* this is actually nothing code, and should be replaced with the */
+  /* alalagous calls in the STREAM test where the window size is set */
+  /* with the HP DLPI Extension. raj 8/94 */
+#ifdef SO_SNDBUF
+  if (lsw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_cl_rr: local window size altered from system default...\n");
+      fprintf(where,"                          window: %d\n",lsw_size);
+    }
+  }
+  if (lrw_size > 0) {
+    if (debug > 1) {
+      fprintf(where,"netperf: send_dlpi_cl_rr: remote window size altered from system default...\n");
+      fprintf(where,"                          remote: %d\n",lrw_size);
+    }
+  }
+  
+  
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the user. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+  
+  if (debug) {
+    fprintf(where,"netperf: send_dlpi_cl_rr: socket sizes determined...\n");
+    fprintf(where,"         send: %d recv: %d\n",lsw_size,lrw_size);
+  }
+  
+#else /* SO_SNDBUF */
+  
+  lsw_size = -1;
+  lrw_size = -1;
+  
+#endif /* SO_SNDBUF */
+  
+  /* 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_DLPI_CL_RR;
+  dlpi_cl_rr_request->recv_win_size	=	rrw_size;
+  dlpi_cl_rr_request->send_win_size	=	rsw_size;
+  dlpi_cl_rr_request->recv_alignment	=	remote_recv_align;
+  dlpi_cl_rr_request->recv_offset	=	remote_recv_offset;
+  dlpi_cl_rr_request->send_alignment	=	remote_send_align;
+  dlpi_cl_rr_request->send_offset	=	remote_send_offset;
+  dlpi_cl_rr_request->request_size	=	req_size;
+  dlpi_cl_rr_request->response_size	=	rsp_size;
+  dlpi_cl_rr_request->measure_cpu	=	remote_cpu_usage;
+  dlpi_cl_rr_request->cpu_rate	        =	remote_cpu_rate;
+  dlpi_cl_rr_request->ppa               =       rem_ppa;
+  dlpi_cl_rr_request->sap               =       dlpi_sap;
+  dlpi_cl_rr_request->dev_name_len      =       strlen(rem_dlpi_device);
+  strcpy(dlpi_cl_rr_request->dlpi_device,
+	 rem_dlpi_device);
+  
+#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 *) dlpi_cl_rr_request->dlpi_device;
+    lastword = initword + ((strlen(rem_dlpi_device) + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = ntohl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  if (test_time) {
+    dlpi_cl_rr_request->test_length	=	test_time;
+  }
+  else {
+    dlpi_cl_rr_request->test_length	=	test_trans * -1;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"netperf: send_dlpi_cl_rr: requesting DLPI CL request/response 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 tests.                                          */
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"remote listen done.\n");
+    rrw_size	=	dlpi_cl_rr_response->recv_win_size;
+    rsw_size	=	dlpi_cl_rr_response->send_win_size;
+    remote_cpu_usage=	dlpi_cl_rr_response->measure_cpu;
+    remote_cpu_rate = 	dlpi_cl_rr_response->cpu_rate;
+    
+    /* set-up the destination addressing control info */
+    data_req->dl_primitive = DL_UNITDATA_REQ;
+    bcopy((char *)(dlpi_cl_rr_response->station_addr),
+	  ((char *)data_req + sizeof(dl_unitdata_req_t)),
+	  dlpi_cl_rr_response->station_addr_len);
+    data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
+    data_req->dl_dest_addr_length = dlpi_cl_rr_response->station_addr_len;
+    /* there is a dl_priority structure too, but I am ignoring it for */
+    /* the time being. */
+    sctl_message.len = sizeof(dl_unitdata_req_t) + 
+      data_req->dl_dest_addr_length;
+    /* famous last words - some DLPI providers get unhappy if the
+       priority stuff is not initialized.  fix from Nicolas Thomas. */
+    data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
+    data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
+
+  }
+  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);
+  
+  /* 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_INTERVALS
+    gettimeofday(&send_time,&dummy_zone);
+#endif /* WANT_INTERVALS */
+    if(putmsg(send_descriptor,
+	      &sctl_message,
+	      &send_message,
+	      0) != 0) {
+      if (errno == EINTR) {
+	/* We likely hit */
+	/* test-end time. */
+	break;
+      }
+      /* there is more we could do here, but it can wait */
+      perror("send_dlpi_cl_rr: data send error");
+      exit(1);
+    }
+    
+    /* receive the response. at some point, we will need to handle */
+    /* sending responses which are greater than the datalink MTU. we */
+    /* may also want to add some DLPI error checking, but for now we */
+    /* will ignore that and just let errors stop the test with little */
+    /* indication of what might actually be wrong. */
+    
+    if((getmsg(send_descriptor, 
+	       &rctl_message,    
+	       &recv_message,
+	       &flags) != 0) || 
+       (data_ind->dl_primitive != DL_UNITDATA_IND)) {
+      if (errno == EINTR) {
+	/* Again, we have likely hit test-end time */
+	break;
+      }
+      fprintf(where,
+	      "send_dlpi_cl_rr: recv error: errno %d primitive 0x%x\n",
+	      errno,
+	      data_ind->dl_primitive);
+      fflush(where);
+      exit(1);
+    }
+#ifdef WANT_INTERVALS
+    gettimeofday(&recv_time,&dummy_zone);
+    
+    /* now we do some arithmatic on the two timevals */
+    if (recv_time.tv_usec < send_time.tv_usec) {
+      /* we wrapped around a second */
+      recv_time.tv_usec += 1000000;
+      recv_time.tv_sec  -= 1;
+    }
+    
+    /* and store it away */
+    kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
+    kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
+    
+    /* 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.  */
+    if (interval_usecs > 0) {
+      sleep_usecs = interval_usecs - kept_times[time_index];
+      if (sleep_usecs > 1000) {
+	/* we sleep */
+	sleep_timeval.tv_sec = sleep_usecs / 1000000;
+	sleep_timeval.tv_usec = sleep_usecs % 1000000;
+	select(0,
+	       0,
+	       0,
+	       0,
+	       &sleep_timeval);
+      }
+    }
+    
+    /* now up the time index */
+    time_index = (time_index +1)%MAX_KEPT_TIMES;
+#endif /* WANT_INTERVALS */
+    nummessages++;          
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug > 3) {
+      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 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 */
+  
+  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 = dlpi_cl_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,
+						   dlpi_cl_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:
+    case 2:
+      fprintf(where,
+	      cpu_fmt_1_line_1,		/* the format string */
+	      lsw_size,		/* local sendbuf size */
+	      lrw_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,
+	      rsw_size,
+	      rrw_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:
+      fprintf(where,
+	      tput_fmt_1_line_1,	/* the format string */
+	      lsw_size,
+	      lrw_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,
+	      rsw_size, 		/* remote recvbuf size */
+	      rrw_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 */
+    /* UDP statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+#ifdef WANT_INTERVALS
+    kept_times[MAX_KEPT_TIMES] = 0;
+    time_index = 0;
+    while (time_index < MAX_KEPT_TIMES) {
+      if (kept_times[time_index] > 0) {
+	total_times += kept_times[time_index];
+      }
+      else
+	unused_buckets++;
+      time_index += 1;
+    }
+    total_times /= (MAX_KEPT_TIMES-unused_buckets);
+    fprintf(where,
+	    "Average response time %d usecs\n",
+	    total_times);
+#endif
+  }
+}
+
+int 
+  recv_dlpi_cl_rr()
+{
+  
+  char  *message;
+  int	data_descriptor;
+  int   flags = 0;
+  int	measure_cpu;
+  
+  char	*recv_message_ptr;
+  char	*send_message_ptr;
+  char  sctl_data[BUFSIZ];
+  char  rctl_data[BUFSIZ];
+  char  dlsap[BUFSIZ];
+  struct strbuf send_message;
+  struct strbuf recv_message;
+  struct strbuf sctl_message;
+  struct strbuf rctl_message;
+  
+  /* these are to make reading some of the DLPI control messages easier */
+  dl_unitdata_ind_t *data_ind = (dl_unitdata_ind_t *)rctl_data;
+  dl_unitdata_req_t *data_req = (dl_unitdata_req_t *)sctl_data;
+  dl_uderror_ind_t  *uder_ind = (dl_uderror_ind_t *)rctl_data;
+  
+  int	trans_received;
+  int	trans_remaining;
+  float	elapsed_time;
+  
+  struct	dlpi_cl_rr_request_struct	*dlpi_cl_rr_request;
+  struct	dlpi_cl_rr_response_struct	*dlpi_cl_rr_response;
+  struct	dlpi_cl_rr_results_struct	*dlpi_cl_rr_results;
+  
+  dlpi_cl_rr_request  = 
+    (struct dlpi_cl_rr_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_cl_rr_response = 
+    (struct dlpi_cl_rr_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_cl_rr_results  = 
+    (struct dlpi_cl_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dlpi_cl_rr: entered...\n");
+    fflush(where);
+  }
+  
+  /* We want to set-up the listen descriptor 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 descriptor 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_dlpi_cl_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = DLPI_CL_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_cl_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_dlpi_cl_rr: requested recv alignment of %d offset %d\n",
+	    dlpi_cl_rr_request->recv_alignment,
+	    dlpi_cl_rr_request->recv_offset);
+    fprintf(where,
+	    "recv_dlpi_cl_rr: requested send alignment of %d offset %d\n",
+	    dlpi_cl_rr_request->send_alignment,
+	    dlpi_cl_rr_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->recv_alignment, dlpi_cl_rr_request->recv_offset);
+  recv_message.maxlen = dlpi_cl_rr_request->request_size;
+  recv_message.len    = 0;
+  recv_message.buf    = recv_message_ptr;
+  
+  send_message_ptr = ALIGN_BUFFER(message, dlpi_cl_rr_request->send_alignment, dlpi_cl_rr_request->send_offset);
+  send_message.maxlen = dlpi_cl_rr_request->response_size;
+  send_message.len    = dlpi_cl_rr_request->response_size;
+  send_message.buf    = send_message_ptr;
+  
+  sctl_message.maxlen = BUFSIZ;
+  sctl_message.len    = 0;
+  sctl_message.buf    = sctl_data;
+  
+  rctl_message.maxlen = BUFSIZ;
+  rctl_message.len    = 0;
+  rctl_message.buf    = rctl_data;
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_cl_rr: receive alignment and offset set...\n");
+    fprintf(where,"recv_dlpi_cl_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  
+#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 *) dlpi_cl_rr_request->dlpi_device;
+    lastword = initword + ((dlpi_cl_rr_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  data_descriptor = dl_open(dlpi_cl_rr_request->dlpi_device,
+			    dlpi_cl_rr_request->ppa);
+  if (data_descriptor < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  
+  /* The initiator may have wished-us to modify the window */
+  /* sizes. We should give it a shot. If he didn't ask us to change the */
+  /* sizes, we should let him know what sizes were in use at this end. */
+  /* If none of this code is compiled-in, then we will tell the */
+  /* initiator that we were unable to play with the sizes by */
+  /* setting the size in the response to -1. */
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  
+  if (dlpi_cl_rr_request->recv_win_size) {
+  }
+  
+  if (dlpi_cl_rr_request->send_win_size) {
+  }
+  
+  /* Now, we will find-out what the sizes actually became, and report */
+  /* them back to the user. If the calls fail, we will just report a -1 */
+  /* back to the initiator for the buffer size. */
+  
+#else /* the system won't let us play with the buffers */
+  
+  dlpi_cl_rr_response->recv_win_size	= -1;
+  dlpi_cl_rr_response->send_win_size	= -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* bind the sap and retrieve the dlsap assigned by the system  */
+  dlpi_cl_rr_response->station_addr_len = 14; /* arbitrary */
+  if (dl_bind(data_descriptor,
+	      dlpi_cl_rr_request->sap,
+	      DL_CLDLS,
+	      (char *)dlpi_cl_rr_response->station_addr,
+	      &dlpi_cl_rr_response->station_addr_len) != 0) {
+    fprintf(where,"send_dlpi_cl_rr: bind failure\n");
+    fflush(where);
+    exit(1);
+  }
+  
+  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. */
+  
+  dlpi_cl_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dlpi_cl_rr_request->measure_cpu) {
+    dlpi_cl_rr_response->measure_cpu = 1;
+    dlpi_cl_rr_response->cpu_rate = calibrate_local_cpu(dlpi_cl_rr_request->cpu_rate);
+  }
+  
+  send_response();
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start receiving. */
+  
+  cpu_start(dlpi_cl_rr_request->measure_cpu);
+  
+  if (dlpi_cl_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(dlpi_cl_rr_request->test_length + PAD_TIME);
+  }
+else {
+  times_up = 1;
+  trans_remaining = dlpi_cl_rr_request->test_length * -1;
+}
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    
+    /* receive the request from the other side. at some point we need */
+    /* to handle "logical" requests and responses which are larger */
+    /* than the data link MTU */
+    
+    if((getmsg(data_descriptor, 
+	       &rctl_message,    
+	       &recv_message,
+	       &flags) != 0) || 
+       (data_ind->dl_primitive != DL_UNITDATA_IND)) {
+      if (errno == EINTR) {
+	/* Again, we have likely hit test-end time */
+	break;
+      }
+      fprintf(where,
+	      "dlpi_recv_cl_rr: getmsg failure: errno %d primitive 0x%x\n",
+	      errno,
+	      data_ind->dl_primitive);
+      fprintf(where,
+	      "                 recevied %u transactions\n",
+	      trans_received);
+      fflush(where);
+      netperf_response.content.serv_errno = 995;
+      send_response();
+      exit(1);
+    }
+    
+    /* Now, send the response to the remote. first copy the dlsap */
+    /* information from the receive to the sending control message */
+    
+    data_req->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
+    bcopy((char *)data_ind + data_ind->dl_src_addr_offset,
+	  (char *)data_req + data_req->dl_dest_addr_offset,
+	  data_ind->dl_src_addr_length);
+    data_req->dl_dest_addr_length = data_ind->dl_src_addr_length;
+    data_req->dl_primitive = DL_UNITDATA_REQ;
+    /* be sure to initialize the priority fields. fix from Nicholas
+       Thomas */
+    data_req->dl_priority.dl_min = DL_QOS_DONT_CARE;
+    data_req->dl_priority.dl_max = DL_QOS_DONT_CARE;
+
+    sctl_message.len = sizeof(dl_unitdata_req_t) +
+      data_ind->dl_src_addr_length;
+    if(putmsg(data_descriptor,
+	      &sctl_message,
+	      &send_message,
+	      0) != 0) {
+      if (errno == EINTR) {
+	/* We likely hit */
+	/* test-end time. */
+	break;
+      }
+      /* there is more we could do here, but it can wait */
+      fprintf(where,
+	      "dlpi_recv_cl_rr: putmsg failure: errno %d\n",
+	      errno);
+      fflush(where);
+      netperf_response.content.serv_errno = 993;
+      send_response();
+      exit(1);
+    }
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_dlpi_cl_rr: Transaction %d complete.\n",
+	      trans_received);
+      fflush(where);
+    }
+    
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(dlpi_cl_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_dlpi_cl_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  dlpi_cl_rr_results->bytes_received	= (trans_received * 
+					   (dlpi_cl_rr_request->request_size + 
+					    dlpi_cl_rr_request->response_size));
+  dlpi_cl_rr_results->trans_received	= trans_received;
+  dlpi_cl_rr_results->elapsed_time	= elapsed_time;
+  if (dlpi_cl_rr_request->measure_cpu) {
+    dlpi_cl_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dlpi_cl_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+int 
+  recv_dlpi_co_rr()
+{
+  
+  char  *message;
+  SOCKET	s_listen,data_descriptor;
+  
+  int	measure_cpu;
+  
+  int   flags = 0;
+  char	*recv_message_ptr;
+  char	*send_message_ptr;
+  struct strbuf send_message;
+  struct strbuf recv_message;
+  
+  int	trans_received;
+  int	trans_remaining;
+  int	request_bytes_remaining;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	dlpi_co_rr_request_struct	*dlpi_co_rr_request;
+  struct	dlpi_co_rr_response_struct	*dlpi_co_rr_response;
+  struct	dlpi_co_rr_results_struct	*dlpi_co_rr_results;
+  
+  dlpi_co_rr_request	= (struct dlpi_co_rr_request_struct *)netperf_request.content.test_specific_data;
+  dlpi_co_rr_response	= (struct dlpi_co_rr_response_struct *)netperf_response.content.test_specific_data;
+  dlpi_co_rr_results	= (struct dlpi_co_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dlpi_co_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_dlpi_co_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = DLPI_CO_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_co_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_dlpi_co_rr: requested recv alignment of %d offset %d\n",
+	    dlpi_co_rr_request->recv_alignment,
+	    dlpi_co_rr_request->recv_offset);
+    fprintf(where,
+	    "recv_dlpi_co_rr: requested send alignment of %d offset %d\n",
+	    dlpi_co_rr_request->send_alignment,
+	    dlpi_co_rr_request->send_offset);
+    fflush(where);
+  }
+
+  recv_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->recv_alignment, dlpi_co_rr_request->recv_offset);
+  recv_message.maxlen = dlpi_co_rr_request->request_size;
+  recv_message.len    = 0;
+  recv_message.buf    = recv_message_ptr;
+  
+  send_message_ptr = ALIGN_BUFFER(message, dlpi_co_rr_request->send_alignment, dlpi_co_rr_request->send_offset);
+  send_message.maxlen = dlpi_co_rr_request->response_size;
+  send_message.len    = dlpi_co_rr_request->response_size;
+  send_message.buf    = send_message_ptr;
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_co_rr: receive alignment and offset set...\n");
+    fprintf(where,"recv_dlpi_co_rr: send_message.buf %x .len %d .maxlen %d\n",
+	    send_message.buf,send_message.len,send_message.maxlen);
+    fprintf(where,"recv_dlpi_co_rr: recv_message.buf %x .len %d .maxlen %d\n",
+	    recv_message.buf,recv_message.len,recv_message.maxlen);
+    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. */
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_dlpi_co_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  /* lets grab a file descriptor for a particular link */
+  
+#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 *) dlpi_co_rr_request->dlpi_device;
+    lastword = initword + ((dlpi_co_rr_request->dev_name_len + 3) / 4);
+    
+    for (charword = initword;
+	 charword < lastword;
+	 charword++) {
+      
+      *charword = htonl(*charword);
+    }
+  }
+#endif /* __alpha */
+  
+  if ((data_descriptor = dl_open(dlpi_co_rr_request->dlpi_device,
+				 dlpi_co_rr_request->ppa)) < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* bind the file descriptor to a sap and get the resultant dlsap */
+  dlpi_co_rr_response->station_addr_len = 14; /*arbitrary needs fixing */
+  if (dl_bind(data_descriptor, 
+              dlpi_co_rr_request->sap, 
+              DL_CODLS,
+              (char *)dlpi_co_rr_response->station_addr,
+              &dlpi_co_rr_response->station_addr_len) != 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* The initiator may have wished-us to modify the socket buffer */
+  /* sizes. We should give it a shot. If he didn't ask us to change the */
+  /* sizes, we should let him know what sizes were in use at this end. */
+  /* If none of this code is compiled-in, then we will tell the */
+  /* initiator that we were unable to play with the socket buffer by */
+  /* setting the size in the response to -1. */
+  
+#ifdef DL_HP_SET_LOCAL_WIN_REQ
+  
+  if (dlpi_co_rr_request->recv_win_size) {
+    /* SMOP */
+  }
+  
+  if (dlpi_co_rr_request->send_win_size) {
+    /* SMOP */
+  }
+  
+  /* Now, we will find-out what the sizes actually became, and report */
+  /* them back to the user. If the calls fail, we will just report a -1 */
+  /* back to the initiator for the buffer size. */
+  
+#else /* the system won't let us play with the buffers */
+  
+  dlpi_co_rr_response->recv_win_size	= -1;
+  dlpi_co_rr_response->send_win_size	= -1;
+  
+#endif /* DL_HP_SET_LOCAL_WIN_REQ */
+  
+  /* we may have been requested to enable the copy avoidance features. */
+  /* can we actually do this with DLPI, the world wonders */
+  
+  if (dlpi_co_rr_request->so_rcvavoid) {
+#ifdef SO_RCV_COPYAVOID
+    dlpi_co_rr_response->so_rcvavoid = 0;
+#else
+    /* it wasn't compiled in... */
+    dlpi_co_rr_response->so_rcvavoid = 0;
+#endif
+  }
+  
+  if (dlpi_co_rr_request->so_sndavoid) {
+#ifdef SO_SND_COPYAVOID
+    dlpi_co_rr_response->so_sndavoid = 0;
+#else
+    /* it wasn't compiled in... */
+    dlpi_co_rr_response->so_sndavoid = 0;
+#endif
+  }
+  
+  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. */
+  
+  dlpi_co_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dlpi_co_rr_request->measure_cpu) {
+    dlpi_co_rr_response->measure_cpu = 1;
+    dlpi_co_rr_response->cpu_rate = calibrate_local_cpu(dlpi_co_rr_request->cpu_rate);
+  }
+  
+  send_response();
+  
+  /* accept a connection on this file descriptor. at some point, */
+  /* dl_accept will "do the right thing" with the last two parms, but */
+  /* for now it ignores them, so we will pass zeros. */
+  
+  if(dl_accept(data_descriptor, 0, 0) != 0) {
+    fprintf(where,
+	    "recv_dlpi_co_rr: error in accept, errno %d\n",
+	    errno);
+    fflush(where);
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dlpi_co_rr: accept completes on the data connection.\n");
+    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(dlpi_co_rr_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (dlpi_co_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(dlpi_co_rr_request->test_length + PAD_TIME);
+  }
+else {
+  times_up = 1;
+  trans_remaining = dlpi_co_rr_request->test_length * -1;
+}
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    request_bytes_remaining	= dlpi_co_rr_request->request_size;
+    
+    /* receive the request from the other side. there needs to be some */
+    /* more login in place for handling messages larger than link mtu, */
+    /* but that can wait for later */
+    while(request_bytes_remaining > 0) {
+      if((getmsg(data_descriptor,
+		 0,
+		 &recv_message,
+		 &flags)) < 0) {
+	if (errno == EINTR) {
+	  /* the timer popped */
+	  timed_out = 1;
+	  break;
+	}
+	
+        if (debug) {
+	  fprintf(where,"failed getmsg call errno %d\n",errno);
+	  fprintf(where,"recv_message.len %d\n",recv_message.len);
+	  fprintf(where,"send_message.len %d\n",send_message.len);
+	  fflush(where);
+        }
+	
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      else {
+	request_bytes_remaining -= recv_message.len;
+      }
+    }
+    
+    if (timed_out) {
+      /* we hit the end of the test based on time - lets bail out of */
+      /* here now... */ 
+      break;
+    }
+    
+    if (debug) {
+      fprintf(where,"recv_message.len %d\n",recv_message.len);
+      fprintf(where,"send_message.len %d\n",send_message.len);
+      fflush(where);
+    }
+    
+    /* Now, send the response to the remote */
+    if((putmsg(data_descriptor,
+	       0,
+	       &send_message,
+	       0)) != 0) {
+      if (errno == EINTR) {
+	/* the test timer has popped */
+	timed_out = 1;
+	break;
+      }
+      netperf_response.content.serv_errno = 994;
+      send_response();
+      exit(1);
+    }
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_dlpi_co_rr: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(dlpi_co_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_dlpi_co_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  dlpi_co_rr_results->bytes_received	= (trans_received * 
+					   (dlpi_co_rr_request->request_size + 
+					    dlpi_co_rr_request->response_size));
+  dlpi_co_rr_results->trans_received	= trans_received;
+  dlpi_co_rr_results->elapsed_time	= elapsed_time;
+  if (dlpi_co_rr_request->measure_cpu) {
+    dlpi_co_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dlpi_co_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+/* this routine will display the usage string for the DLPI tests */
+void
+  print_dlpi_usage()
+
+{
+  fwrite(dlpi_usage, sizeof(char), strlen(dlpi_usage), stdout);
+}
+
+
+/* this routine will scan the command line for DLPI test arguments */
+void
+  scan_dlpi_args(int argc, char *argv[])
+{
+  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 DLPI 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.. */
+  
+#define DLPI_ARGS "D:hM:m:p:r:s:W:w:"
+  
+  while ((c= getopt(argc, argv, DLPI_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case 'h':
+      print_dlpi_usage();
+      exit(1);
+    case 'D':
+      /* set the dlpi device file name(s) */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	strcpy(loc_dlpi_device,arg1);
+      if (arg2[0])
+	strcpy(rem_dlpi_device,arg2);
+      break;
+    case 'm':
+      /* set the send size */
+      send_size = atoi(optarg);
+      break;
+    case 'M':
+      /* set the recv size */
+      recv_size = atoi(optarg);
+      break;
+    case 'p':
+      /* set the local/remote ppa */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	loc_ppa = atoi(arg1);
+      if (arg2[0])
+	rem_ppa = atoi(arg2);
+      break;
+    case 'r':
+      /* set the request/response sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	req_size = atoi(arg1);
+      if (arg2[0])	
+	rsp_size = atoi(arg2);
+      break;
+    case 's':
+      /* set the 802.2 sap for the test */
+      dlpi_sap = atoi(optarg);
+      break;
+    case 'w':
+      /* set local window sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lsw_size = atoi(arg1);
+      if (arg2[0])
+	lrw_size = atoi(arg2);
+      break;
+    case 'W':
+      /* set remote window sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rsw_size = atoi(arg1);
+      if (arg2[0])
+	rrw_size = atoi(arg2);
+      break;
+    };
+  }
+}
+
+
+#endif /* WANT_DLPI */
diff --git a/nettest_dlpi.h b/nettest_dlpi.h
new file mode 100644
index 0000000..8169237
--- /dev/null
+++ b/nettest_dlpi.h
@@ -0,0 +1,215 @@
+/*
+        Copyright (C) 1993, Hewlett-Packard Company
+*/
+
+ /* This file contains the test-specific definitions for netperf's */
+ /* DLPI tests */
+
+
+struct	dlpi_co_stream_request_struct {
+  int	recv_win_size;
+  int	send_win_size;
+  int	receive_size;   /* how many bytes do we want to */
+                        /* receive at one time? */
+  int	recv_alignment; /* what is the alignment of the */
+                        /* receive buffer? */
+  int	recv_offset;    /* and at what offset from that */
+                        /* alignment? */
+  int	measure_cpu;	/* does the client want server cpu */
+                        /* utilization measured? */
+  float	cpu_rate;	/* do we know how fast the cpu is */
+                        /* already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid */
+                        /* copies on receives? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   sap;            /* */
+  int   ppa;            /* which device do we wish to use? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  dlpi_device[32]; /* the path to the dlpi device */
+};
+
+struct	dlpi_co_stream_response_struct {
+  int	recv_win_size;	/* how big does the client want it	*/
+  int	send_win_size;
+  int	receive_size;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   station_addr_len;
+  int   station_addr[1];/* what is the station address for the */
+			/* specified ppa? */
+};
+
+struct dlpi_co_stream_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   cpu_method;     /* how was CPU util measured? */
+  int   num_cpus;       /* how many CPUs were there? */
+};
+
+struct	dlpi_co_rr_request_struct {
+  int	recv_win_size;	/* how big does the client want it	*/
+  int	send_win_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   ppa;            /* which device do we wish to use? */
+  int   sap;            /* which sap should be used? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  dlpi_device[32]; /* the path to the dlpi device */
+};
+
+struct	dlpi_co_rr_response_struct {
+  int	recv_win_size;	/* how big does the client want it	*/
+  int	send_win_size;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   station_addr_len;    /* the length of the station address */
+  int   station_addr[1];     /* the remote's station address */
+};
+
+struct dlpi_co_rr_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  int	trans_received;	/* not ignored  */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   cpu_method;     /* how was CPU util measured? */
+  int   num_cpus;       /* how many CPUs were there? */
+};
+
+struct	dlpi_cl_stream_request_struct {
+  int	recv_win_size;
+  int	message_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	checksum_off;
+  int	measure_cpu;
+  float	cpu_rate;
+  int	test_length;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   ppa;            /* which device do we wish to use? */
+  int   sap;
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  dlpi_device[32]; /* the path to the dlpi device */
+};
+
+struct	dlpi_cl_stream_response_struct {
+  int	recv_win_size;
+  int	send_win_size;
+  int	measure_cpu;
+  int	test_length;
+  int	data_port_number;
+  float	cpu_rate;
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   station_addr_len;    /* the length of the station address */
+  int   station_addr[1];     /* the remote's station address */
+};
+
+struct	dlpi_cl_stream_results_struct {
+  int	messages_recvd;
+  int	bytes_received;
+  float	elapsed_time;
+  float	cpu_util;
+  int   num_cpus;
+};
+
+
+struct	dlpi_cl_rr_request_struct {
+  int	recv_win_size;	/* how big does the client want it	*/
+  int	send_win_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   ppa;            /* which device do we wish to use? */
+  int   sap;            /* which sap? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  dlpi_device[32]; /* the path to the dlpi device */
+};
+
+struct	dlpi_cl_rr_response_struct {
+  int	recv_win_size;	/* how big does the client want it	*/
+  int	send_win_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   station_addr_len;    /* the length of the station address */
+  int   station_addr[1];     /* the remote's station address */
+};
+
+struct dlpi_cl_rr_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  int	trans_received;	/* not ignored  */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   cpu_method;     /* how was CPU util measured? */
+  int   num_cpus;       /* how many CPUs were there? */
+};
+
+extern void send_dlpi_co_stream();
+
+extern int recv_dlpi_co_stream();
+
+extern int send_dlpi_co_rr(char remote_host[]);
+
+extern void send_dlpi_cl_stream(char remote_host[]);
+
+extern int recv_dlpi_cl_stream();
+
+extern int send_dlpi_cl_rr(char remote_host[]);
+
+extern int recv_dlpi_cl_rr();
+
+extern int recv_dlpi_co_rr();
+
+extern void scan_dlpi_args(int argc, char *argv[]);
diff --git a/nettest_sctp.c b/nettest_sctp.c
new file mode 100644
index 0000000..7cfcd9f
--- /dev/null
+++ b/nettest_sctp.c
@@ -0,0 +1,4869 @@
+#ifndef lint
+char	nettest_sctp[]="\
+@(#)nettest_sctp.c (c) Copyright 2005-2007 Hewlett-Packard Co. Version 2.4.3";
+#else
+#define DIRTY
+#define WANT_HISTOGRAM
+#define WANT_INTERVALS
+#endif /* lint */
+
+/****************************************************************/
+/*								*/
+/*	nettest_sctp.c						*/
+/*								*/
+/*                                                              */
+/*      scan_sctp_args()        get the sctp command line args  */
+/*                                                              */
+/*	the actual test routines...				*/
+/*								*/
+/*	send_sctp_stream()	perform a sctp stream test	*/
+/*	recv_sctp_stream()					*/
+/*	send_sctp_rr()		perform a sctp request/response	*/
+/*	recv_sctp_rr()						*/
+/*	send_sctp_stream_udp()	perform a sctp request/response	*/
+/*	recv_sctp_stream_upd()	using UDP style API		*/
+/*	send_sctp_rr_udp()	perform a sctp request/response	*/
+/*	recv_sctp_rr_upd()	using UDP style API		*/
+/*								*/
+/*      relies on create_data_socket in nettest_bsd.c           */
+/****************************************************************/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(WANT_SCTP)
+     
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#else /* NOSTDLIBH */
+#include <stdlib.h>
+#endif /* NOSTDLIBH */
+
+#if !defined(__VMS)
+#include <sys/ipc.h>
+#endif /* !defined(__VMS) */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/sctp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+/* would seem that not all sctp.h files define a MSG_EOF, but that
+   MSG_EOF can be the same as MSG_FIN so lets work with that
+   assumption.  initial find by Jon Pedersen. raj 2006-02-01 */
+#ifndef MSG_EOF
+#ifdef MSG_FIN
+#define MSG_EOF MSG_FIN
+#else
+#error Must have either MSG_EOF or MSG_FIN defined
+#endif
+#endif 
+
+#include "netlib.h"
+#include "netsh.h"
+/* get some of the functions from nettest_bsd.c */
+#include "nettest_bsd.h"
+#include "nettest_sctp.h"
+
+#ifdef WANT_HISTOGRAM
+#ifdef __sgi
+#include <sys/time.h>
+#endif /* __sgi */
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_FIRST_BURST
+extern int first_burst_size;
+#endif /* WANT_FIRST_BURST */
+
+
+
+/* these variables are specific to SCTP tests. declare */
+/* them static to make them global only to this file. */
+
+static int	
+  msg_count = 0,	/* number of messages to transmit on association */
+  non_block = 0,	/* default to blocking sockets */
+  num_associations = 1; /* number of associations on the endpoint */
+
+static  int confidence_iteration;
+static  char  local_cpu_method;
+static  char  remote_cpu_method;
+
+#ifdef WANT_HISTOGRAM
+static struct timeval time_one;
+static struct timeval time_two;
+static HIST time_hist;
+#endif /* WANT_HISTOGRAM */
+
+
+char sctp_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+SCTP Sockets Test Options:\n\
+    -b number         Send number requests at the start of _RR tests\n\
+    -D [L][,R]        Set SCTP_NODELAY locally and/or remotely\n\
+    -h                Display this text\n\
+    -H name,fam       Use name (or IP) and family as target of data connection\n\
+    -L name,fam       Use name (or IP) and family as source of data connextion\n\
+    -m bytes          Set the size of each sent message\n\
+    -M bytes          Set the size of each received messages\n\
+    -P local[,remote] Set the local/remote port for the data socket\n\
+    -r req,[rsp]      Set request/response sizes (_RR tests)\n\
+    -s send[,recv]    Set local socket send/recv buffer sizes\n\
+    -S send[,recv]    Set remote socket send/recv buffer sizes\n\
+    -V 		      Enable copy avoidance if supported\n\
+    -N number	      Specifies the number of messages to send (_STREAM tests)\n\
+    -B		      run the test in non-blocking mode\n\
+    -T number	      Number of associations to create (_MANY tests)\n\
+    -4                Use AF_INET (eg IPv4) on both ends of the data conn\n\
+    -6                Use AF_INET6 (eg IPv6) on both ends of the data conn\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 */
+static
+void
+get_sctp_info(socket, mss)
+     int socket;
+     int *mss;
+{
+
+  int sock_opt_len;
+
+  if (sctp_opt_info(socket,
+		    0,
+		    SCTP_MAXSEG,
+		    mss,
+		    &sock_opt_len) < 0) {
+    lss_size = -1;
+  }
+}
+
+
+static
+void
+sctp_enable_events(socket, ev_mask)
+    int socket;
+    int ev_mask;
+{
+    struct sctp_event_subscribe ev;
+
+    bzero(&ev, sizeof(ev));
+
+    if (ev_mask & SCTP_SNDRCV_INFO_EV)
+	ev.sctp_data_io_event = 1;
+
+    if (ev_mask & SCTP_ASSOC_CHANGE_EV)
+	ev.sctp_association_event = 1;
+
+    if (ev_mask & SCTP_PEERADDR_CHANGE_EV)
+	ev.sctp_address_event = 1;
+
+    if (ev_mask & SCTP_SND_FAILED_EV)
+	ev.sctp_send_failure_event = 1;
+
+    if (ev_mask & SCTP_REMOTE_ERROR_EV)
+	ev.sctp_peer_error_event = 1;
+
+    if (ev_mask & SCTP_SHUTDOWN_EV)
+	ev.sctp_shutdown_event = 1;
+
+    if (ev_mask & SCTP_PD_EV)
+	ev.sctp_partial_delivery_event = 1;
+
+    if (ev_mask & SCTP_ADAPT_EV)
+#ifdef HAVE_SCTP_ADAPTATION_LAYER_EVENT
+	ev.sctp_adaptation_layer_event = 1;
+#else
+	ev.sctp_adaption_layer_event = 1;
+#endif
+
+    if (setsockopt(socket,
+		   IPPROTO_SCTP,
+#ifdef SCTP_EVENTS
+		   SCTP_EVENTS,
+#else
+		   SCTP_SET_EVENTS,
+#endif
+		   (const char*)&ev,
+		   sizeof(ev)) != 0 ) {
+      fprintf(where,
+	      "sctp_enable_event: could not set sctp events errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+}
+
+
+static
+sctp_disposition_t
+sctp_process_event(socket, buf)
+    int socket;
+    void *buf;
+{
+
+    struct sctp_assoc_change *sac;
+    struct sctp_send_failed *ssf;
+    struct sctp_paddr_change *spc;
+    struct sctp_remote_error *sre;
+    union sctp_notification *snp;
+
+    snp = buf;
+
+    switch (snp->sn_header.sn_type) {
+    case SCTP_ASSOC_CHANGE:
+	if (debug) {
+	    fprintf(where, "\tSCTP_ASSOC_CHANGE event, type:");
+	    fflush(where);
+	}
+	sac = &snp->sn_assoc_change;
+	switch (sac->sac_type) {
+	    case SCTP_COMM_UP:
+		if (debug) {
+		    fprintf(where, "  SCTP_COMM_UP\n");
+		    fflush(where);
+		}
+		break;
+	    case SCTP_RESTART:
+		if (debug) {
+		    fprintf(where, "  SCTP_RESTART\n");
+		    fflush(where);
+		}
+		break;
+	    case SCTP_CANT_STR_ASSOC:
+		if (debug) {
+		    fprintf(where, "  SCTP_CANT_STR_ASSOC\n");
+		    fflush(where);
+		}
+		break;	/* FIXME ignore above status changes */
+	    case SCTP_COMM_LOST:
+		if (debug) {
+		    fprintf(where, "  SCTP_COMM_LOST\n");
+		    fflush(where);
+		}
+		return SCTP_CLOSE;
+	    case SCTP_SHUTDOWN_COMP:
+		if (debug) {
+		    fprintf(where, "  SCTP_SHUTDOWN_COMPLETE\n");
+		    fflush(where);
+		}
+		return SCTP_CLOSE;
+		break;
+	}
+
+    case SCTP_SEND_FAILED:
+	if (debug) {
+	    fprintf(where, "\tSCTP_SEND_FAILED event\n");
+	    fflush(where);
+	}
+	ssf = &snp->sn_send_failed;
+	break;  /* FIXME ??? ignore this for now */
+
+    case SCTP_PEER_ADDR_CHANGE:
+	if (debug) {
+	    fprintf(where, "\tSCTP_PEER_ADDR_CHANGE event\n");
+	    fflush(where);
+	}
+	spc = &snp->sn_paddr_change;
+	break;	/* FIXME ??? ignore this for now */
+
+    case SCTP_REMOTE_ERROR:
+	if (debug) {
+	    fprintf(where, "\tSCTP_REMOTE_ERROR event\n");
+	    fflush(where);
+	}
+	sre = &snp->sn_remote_error;
+	break;	/* FIXME ??? ignore this for now */
+    case SCTP_SHUTDOWN_EVENT:
+	if (debug) {
+	    fprintf(where, "\tSCTP_SHUTDOWN event\n");
+	    fflush(where);
+	}
+	return SCTP_CLOSE;
+    default:
+	fprintf(where, "unknown type: %hu\n", snp->sn_header.sn_type);
+	fflush(where);
+	break;
+    }
+    return SCTP_OK;
+}
+
+
+
+/* This routine implements the SCTP unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_sctp_stream(remote_host)
+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. */
+  
+#ifdef DIRTY
+  int	*message_int_ptr;
+#endif
+
+  struct ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  int send_socket;
+  int bytes_remaining;
+  int sctp_mss;
+  int timed_out;
+
+  /* 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 = 0.0;
+  
+#ifdef DIRTY
+  int	i;
+#endif /* DIRTY */
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo	*remote_res;
+  struct addrinfo	*local_res;
+  struct addrinfo	*local_remote_res;
+  struct addrinfo	*local_local_res;
+
+  struct	sctp_stream_request_struct	*sctp_stream_request;
+  struct	sctp_stream_response_struct	*sctp_stream_response;
+  struct	sctp_stream_results_struct	*sctp_stream_result;
+  
+  sctp_stream_request  = 
+    (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sctp_stream_response =
+    (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sctp_stream_result   = 
+    (struct sctp_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. */
+  
+  /* complete_addrinfos will either succede or exit the process */
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_SCTP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("SCTP STREAM TEST", local_res, remote_res);
+  }
+
+  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;
+    timed_out	   =    0;
+    
+    /*set up the data socket                        */
+    send_socket = create_data_socket(local_res);
+    
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_sctp_stream: sctp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_sctp_stream: send_socket obtained...\n");
+    }
+    
+    /* 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_SCTP_STREAM;
+    sctp_stream_request->send_buf_size	=	rss_size_req;
+    sctp_stream_request->recv_buf_size	=	rsr_size_req;
+    sctp_stream_request->receive_size	=	recv_size;
+    sctp_stream_request->no_delay	=	rem_nodelay;
+    sctp_stream_request->recv_alignment	=	remote_recv_align;
+    sctp_stream_request->recv_offset	=	remote_recv_offset;
+    sctp_stream_request->measure_cpu	=	remote_cpu_usage;
+    sctp_stream_request->cpu_rate	=	remote_cpu_rate;
+    if (test_time) {
+      sctp_stream_request->test_length	=	test_time;
+    }
+    else {
+      if (msg_count)
+	  test_bytes = send_size * msg_count;
+
+      sctp_stream_request->test_length	=	test_bytes;
+    }
+    sctp_stream_request->so_rcvavoid	=	rem_rcvavoid;
+    sctp_stream_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+    sctp_stream_request->dirty_count    =       rem_dirty_count;
+    sctp_stream_request->clean_count    =       rem_clean_count;
+#endif /* DIRTY */
+    sctp_stream_request->port		=	htonl(atoi(remote_data_port));
+    sctp_stream_request->ipfamily	=	af_to_nf(remote_res->ai_family);
+    sctp_stream_request->non_blocking   =	non_block;
+    
+    
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: send_sctp_stream: requesting sctp 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 sctp tests.					*/
+    
+    recv_response();
+    
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote listen done.\n");
+      rsr_size	      =	sctp_stream_response->recv_buf_size;
+      rss_size	      =	sctp_stream_response->send_buf_size;
+      rem_nodelay     =	sctp_stream_response->no_delay;
+      remote_cpu_usage=	sctp_stream_response->measure_cpu;
+      remote_cpu_rate = sctp_stream_response->cpu_rate;
+
+      /* we have to make sure that the server port number is in */
+      /* network order */
+      set_port_number(remote_res, (short)sctp_stream_response->data_port_number);
+
+      rem_rcvavoid	= sctp_stream_response->so_rcvavoid;
+      rem_sndavoid	= sctp_stream_response->so_sndavoid;
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      exit(1);
+    }
+    
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET) {
+      perror("netperf: send_sctp_stream: data socket connect failed");
+      exit(1);
+    }
+
+    sctp_enable_events(send_socket, SCTP_ASSOC_CHANGE_EV);
+
+    if (non_block) {
+	/* now that we are connected, mark the socket as non-blocking */
+	if (!set_nonblock(send_socket)) {
+	  perror("netperf: fcntl");
+	  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_sctp_stream: unable to get sigmask errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+
+#ifdef DIRTY
+    /* initialize the random number generator for putting dirty stuff */
+    /* into the send buffer. raj */
+    srand((int) getpid());
+#endif
+    
+    /* 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. */
+      message_int_ptr = (int *)(send_ring->buffer_ptr);
+      for (i = 0; i < loc_dirty_count; i++) {
+	*message_int_ptr = rand();
+	message_int_ptr++;
+      }
+      for (i = 0; i < loc_clean_count; i++) {
+	loc_dirty_count = *message_int_ptr;
+	message_int_ptr++;
+      }
+#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 */
+      
+      while ((len=sctp_sendmsg(send_socket,
+			       send_ring->buffer_ptr, send_size,
+			       NULL, 0,
+			       0, 0, 0, 0, 0)) != send_size) {
+	if (non_block && errno == EAGAIN)
+	    continue;
+	else if ((len >=0) || SOCKET_EINTR(len)) {
+	  /* the test was interrupted, must be the end of test */
+	  timed_out = 1;
+	  break;
+	}
+	perror("netperf: data send error");
+	printf("len was %d\n",len);
+	exit(1);
+      }
+
+      if (timed_out)
+	  break;	/* we timed out durint sendmsg, done with test */
+
+#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 > 1) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_sctp_stream: fault with sigsuspend.\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 sctp maximum segment_size was (if possible) */
+    if (verbosity > 1) {
+      sctp_mss = -1;
+      get_sctp_info(send_socket, &sctp_mss);
+    }
+
+    shutdown(send_socket, SHUT_WR);
+
+    /* The test server will signal to us when it wants to shutdown.
+     * In blocking mode, we can call recvmsg.  In non-blocking
+     * mode, we need to select on the socket for reading.
+     * We'll assume that all returns are succefull
+     */
+    if (non_block) {
+	fd_set readfds;
+
+	FD_ZERO(&readfds);
+	FD_SET(send_socket, &readfds);
+	select(send_socket+1, &readfds, NULL, NULL, NULL);
+    } else {
+	sctp_recvmsg(send_socket, send_ring->buffer_ptr, send_size, NULL, 
+		0, NULL, 0);
+    }
+    
+    /* 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+    close(send_socket);
+
+    /* 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);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      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 sctp 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	= ntohd(sctp_stream_result->bytes_received);
+
+    thruput	= (double) 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= sctp_stream_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      sctp_stream_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(sctp_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 */
+    /* sctp 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)sctp_stream_result->recv_calls,
+	    sctp_stream_result->recv_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    sctp_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 sctp stream test. It is */
+/* implemented as one routine. I could break things-out somewhat, but */
+/* didn't feel it was necessary. */
+
+void
+recv_sctp_stream()
+{
+  
+  struct sockaddr_in myaddr_in; /* needed to get port number */
+  struct sockaddr_storage peeraddr;	/* used in accept */
+  int	s_listen,s_data;
+  int 	addrlen;
+  int	len;
+  unsigned int	receive_calls;
+  float	elapsed_time;
+  double   bytes_received;
+  
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+  int  msg_flags = 0;
+
+#ifdef DIRTY
+  int   *message_int_ptr;
+  int   dirty_count;
+  int   clean_count;
+  int   i;
+#endif
+  
+#ifdef DO_SELECT
+  fd_set readfds;
+  struct timeval timeout;
+#endif /* DO_SELECT */
+
+  struct	sctp_stream_request_struct	*sctp_stream_request;
+  struct	sctp_stream_response_struct	*sctp_stream_response;
+  struct	sctp_stream_results_struct	*sctp_stream_results;
+  
+#ifdef DO_SELECT
+  FD_ZERO(&readfds);
+  timeout.tv_sec = 1;
+  timeout.tv_usec = 0;
+#endif /* DO_SELECT */
+
+  sctp_stream_request	= 
+    (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sctp_stream_response	= 
+    (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sctp_stream_results	= 
+    (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sctp_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_sctp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SCTP_STREAM_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sctp_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_sctp_stream: requested alignment of %d\n",
+	    sctp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = sctp_stream_request->send_buf_size;
+  lsr_size_req = sctp_stream_request->recv_buf_size;
+  loc_nodelay = sctp_stream_request->no_delay;
+  loc_rcvavoid = sctp_stream_request->so_rcvavoid;
+  loc_sndavoid = sctp_stream_request->so_sndavoid;
+  non_block = sctp_stream_request->non_blocking;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sctp_stream_request->ipfamily),
+			sctp_stream_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sctp_stream_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_SCTP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* what sort of sizes did we end-up with? */
+  if (sctp_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = sctp_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,
+				   sctp_stream_request->recv_alignment,
+				   sctp_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_sctp_stream: set recv_size = %d, align = %d, offset = %d.\n",
+		   recv_size, sctp_stream_request->recv_alignment,
+		   sctp_stream_request->recv_offset);
+    fflush(where);
+  }
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_listen, 
+		  (struct sockaddr *)&myaddr_in,
+		  &addrlen) == -1){
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    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. */
+  
+  sctp_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. */
+  
+  sctp_stream_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (sctp_stream_request->measure_cpu) {
+    sctp_stream_response->measure_cpu = 1;
+    sctp_stream_response->cpu_rate = 
+      calibrate_local_cpu(sctp_stream_request->cpu_rate);
+  }
+  else {
+    sctp_stream_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sctp_stream_response->send_buf_size = lss_size;
+  sctp_stream_response->recv_buf_size = lsr_size;
+  sctp_stream_response->no_delay = loc_nodelay;
+  sctp_stream_response->so_rcvavoid = loc_rcvavoid;
+  sctp_stream_response->so_sndavoid = loc_sndavoid;
+  sctp_stream_response->receive_size = recv_size;
+
+  /* Now, let's set-up the socket to listen for connections */
+  if (listen(s_listen, 5) == -1) {
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+  
+  send_response();
+  
+  addrlen = sizeof(peeraddr);
+  
+  if ((s_data = accept(s_listen,
+		      (struct sockaddr *)&peeraddr,
+		      &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+
+  sctp_enable_events(s_data, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
+
+  /* now that we are connected, mark the socket as non-blocking */
+  if (non_block) {
+      fprintf(where, "setting socket as nonblocking\n");
+      fflush(where);
+      if (!set_nonblock(s_data)) {
+	close(s_data);
+	exit(1);
+      }
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(sctp_stream_request->measure_cpu);
+
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+#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. */
+
+  dirty_count = sctp_stream_request->dirty_count;
+  clean_count = sctp_stream_request->clean_count;
+  message_int_ptr = (int *)recv_ring->buffer_ptr;
+  for (i = 0; i < dirty_count; i++) {
+    *message_int_ptr = rand();
+    message_int_ptr++;
+  }
+  for (i = 0; i < clean_count; i++) {
+    dirty_count = *message_int_ptr;
+    message_int_ptr++;
+  }
+#endif /* DIRTY */
+
+  bytes_received = 0;
+  receive_calls  = 0;
+  
+  while ((len = sctp_recvmsg(s_data,
+			    recv_ring->buffer_ptr, recv_size,
+			    NULL, 0, NULL, &msg_flags)) != 0) {
+    if (len == SOCKET_ERROR) {
+	if (non_block && errno == EAGAIN) {
+	   if (debug){
+	     fprintf(where,
+		    "recv_sctp_stream: sctp_recvmsg timed out, trying again\n");
+	     fflush(where);
+	   }
+	   Set_errno(0);
+	   continue;
+	}
+	if (debug) {
+	    fprintf(where,
+		    "recv_sctp_stream: sctp_recvmsg error %d, exiting",
+		    errno);
+	    fflush(where);
+        }
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	close(s_data);
+	exit(1);
+    }
+
+    if (msg_flags & MSG_NOTIFICATION) {
+	 msg_flags = 0;
+	 if (debug) {
+	   fprintf(where,
+		    "recv_sctp_stream: Got notification... processing\n");
+	     fflush(where);
+	}
+	if (sctp_process_event(s_data, recv_ring->buffer_ptr) == SCTP_CLOSE)
+	    break;	/* break out of the recvmsg loop */
+
+	continue;
+    }
+
+    bytes_received += len;
+    receive_calls++;
+
+    /* more to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+
+#ifdef PAUSE
+    sleep(1);
+#endif /* PAUSE */
+
+#ifdef DIRTY
+    message_int_ptr = (int *)(recv_ring->buffer_ptr);
+    for (i = 0; i < dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < clean_count; i++) {
+      dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+
+#ifdef DO_SELECT
+	FD_SET(s_data,&readfds);
+	select(s_data+1,&readfds,NULL,NULL,&timeout);
+#endif /* DO_SELECT */
+
+  }
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (close(s_data) == -1) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+  
+  cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_stream: got %g bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_sctp_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  sctp_stream_results->bytes_received	= htond(bytes_received);
+  sctp_stream_results->elapsed_time	= elapsed_time;
+  sctp_stream_results->recv_calls	= receive_calls;
+  
+  if (sctp_stream_request->measure_cpu) {
+    sctp_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_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);
+  }
+  
+  sctp_stream_results->cpu_method = cpu_method;
+  sctp_stream_results->num_cpus   = lib_num_loc_cpus;
+  send_response();
+
+  /* we are now done with the sockets */
+  close(s_listen);
+
+}
+
+
+/* This routine implements the SCTP unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_sctp_stream_1toMany(remote_host)
+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. */
+  
+#ifdef DIRTY
+  int	*message_int_ptr;
+#endif
+
+  struct ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  int *send_socket;
+  int bytes_remaining;
+  int sctp_mss;
+
+  /* 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 = 0.0;
+  
+#ifdef DIRTY
+  int	i;
+#endif /* DIRTY */
+  int j;
+
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+  struct addrinfo *last_remote_res;
+  struct addrinfo *last_local_res;
+
+  struct	sctp_stream_request_struct	*sctp_stream_request;
+  struct	sctp_stream_response_struct	*sctp_stream_response;
+  struct	sctp_stream_results_struct	*sctp_stream_result;
+  
+  sctp_stream_request  = 
+    (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sctp_stream_response =
+    (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sctp_stream_result   = 
+    (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
+
+#ifdef WANT_HISTOGRAM
+  time_hist = HIST_new();
+#endif /* WANT_HISTOGRAM */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_SEQPACKET,
+		     IPPROTO_SCTP,
+		     0);
+  
+  if ( print_headers ) {
+    print_top_test_header("SCTP 1-TO-MANY STREAM TEST",local_res,remote_res);
+  }
+
+  send_ring = NULL;
+  confidence_iteration = 1;
+  init_stat();
+
+  send_socket = malloc(sizeof (int) * num_associations);
+  if (send_socket == NULL) {
+      fprintf(where, "send_sctp_stream_1toMany: failed to allocation sockets!\n");
+      exit(1);
+  }
+
+  /* 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)) {
+
+    int		j=0;
+    int		timed_out = 0;
+    
+
+    /* 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;
+    
+    /* 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_SCTP_STREAM_MANY;
+    sctp_stream_request->send_buf_size	=	rss_size_req;
+    sctp_stream_request->recv_buf_size	=	rsr_size_req;
+    sctp_stream_request->receive_size	=	recv_size;
+    sctp_stream_request->no_delay	=	rem_nodelay;
+    sctp_stream_request->recv_alignment	=	remote_recv_align;
+    sctp_stream_request->recv_offset	=	remote_recv_offset;
+    sctp_stream_request->measure_cpu	=	remote_cpu_usage;
+    sctp_stream_request->cpu_rate	=	remote_cpu_rate;
+    if (test_time) {
+      sctp_stream_request->test_length	=	test_time;
+    }
+    else {
+      if (msg_count)
+	  test_bytes = send_size * msg_count;
+
+      sctp_stream_request->test_length	=	test_bytes*num_associations;
+    }
+    sctp_stream_request->so_rcvavoid	=	rem_rcvavoid;
+    sctp_stream_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+    sctp_stream_request->dirty_count    =       rem_dirty_count;
+    sctp_stream_request->clean_count    =       rem_clean_count;
+#endif /* DIRTY */
+    sctp_stream_request->port		= 	(atoi(remote_data_port));
+    sctp_stream_request->ipfamily	=	af_to_nf(remote_res->ai_family);
+    sctp_stream_request->non_blocking   =	non_block;
+    
+    
+    if (debug > 1) {
+      fprintf(where,
+	      "netperf: send_sctp_stream_1toMany: requesting sctp 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 sctp tests.					*/
+    
+    recv_response();
+    
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote listen done.\n");
+      rsr_size	      =	sctp_stream_response->recv_buf_size;
+      rss_size	      =	sctp_stream_response->send_buf_size;
+      rem_nodelay     =	sctp_stream_response->no_delay;
+      remote_cpu_usage=	sctp_stream_response->measure_cpu;
+      remote_cpu_rate = sctp_stream_response->cpu_rate;
+
+      /* we have to make sure that the server port number is in */
+      /* network order */
+      set_port_number(remote_res, (unsigned short)sctp_stream_response->data_port_number);
+      rem_rcvavoid	= sctp_stream_response->so_rcvavoid;
+      rem_sndavoid	= sctp_stream_response->so_sndavoid;
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      exit(1);
+    }
+    
+    /*set up the the array of data sockets  and connect them to the server */
+
+    for (j = 0; j < num_associations; j++) {
+	send_socket[j] = create_data_socket(local_res);
+    
+	if (send_socket[j] < 0){
+	  perror("netperf: send_sctp_stream_1toMany: sctp stream data socket");
+	  exit(1);
+	}
+	
+	if (debug) {
+	  fprintf(where,"send_sctp_stream_1toMany: send_socket obtained...\n");
+	}
+
+	/*Connect up to the remote port on the data socket  */
+	if (connect(send_socket[j], 
+		    remote_res->ai_addr,
+		    remote_res->ai_addrlen) == INVALID_SOCKET){
+	  perror("netperf: send_sctp_stream_1toMany: data socket connect failed");
+	  exit(1);
+	}
+
+	/* Do it after connect is successfull, so that we don't see COMM_UP */
+	sctp_enable_events(send_socket[j], SCTP_ASSOC_CHANGE_EV);
+
+	if (non_block) {
+	    /* now that we are connected, mark the socket as non-blocking */
+	    if (!set_nonblock(send_socket[j])) {
+	      perror("netperf: fcntl");
+	      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 * num_associations;
+      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_sctp_stream_1toMany: unable to get sigmask errno %d\n",
+	      errno);
+      fflush(where);
+      exit(1);
+    }
+#endif /* WANT_INTERVALS */
+
+#ifdef DIRTY
+    /* initialize the random number generator for putting dirty stuff */
+    /* into the send buffer. raj */
+    srand((int) getpid());
+#endif
+    
+    /* 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. */
+      message_int_ptr = (int *)(send_ring->buffer_ptr);
+      for (i = 0; i < loc_dirty_count; i++) {
+	*message_int_ptr = rand();
+	message_int_ptr++;
+      }
+      for (i = 0; i < loc_clean_count; i++) {
+	loc_dirty_count = *message_int_ptr;
+	message_int_ptr++;
+      }
+#endif /* DIRTY */
+      
+#ifdef WANT_HISTOGRAM
+      /* timestamp just before we go into send and then again just after */
+      /* we come out raj 8/94 */
+      gettimeofday(&time_one,NULL);
+#endif /* WANT_HISTOGRAM */
+      
+      for (j = 0; j < num_associations; j++) {
+
+	  if((len=sctp_sendmsg(send_socket[j],
+			       send_ring->buffer_ptr,
+			       send_size,
+			       (struct sockaddr *)remote_res->ai_addr,
+			       remote_res->ai_addrlen,
+			       0, 0, 0, 0, 0)) != send_size) {
+	    if ((len >=0) || SOCKET_EINTR(len)) {
+	      /* the test was interrupted, must be the end of test */
+	      timed_out = 1;
+	      break;
+	    } else if (non_block && errno == EAGAIN) {
+		j--;	 /* send again on the same socket */
+		Set_errno(0);
+		continue;
+	    }
+	    perror("netperf: data send error");
+	    printf("len was %d\n",len);
+	    exit(1);
+	  }
+      }
+
+      if (timed_out)
+	  break;	/* test is over, try next iteration */
+
+#ifdef WANT_HISTOGRAM
+      /* timestamp the exit from the send call and update the histogram */
+      gettimeofday(&time_two,NULL);
+      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 > 1) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_sctp_stream_1toMany: fault with sigsuspend.\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 sctp maximum segment_size was (if possible) */
+    if (verbosity > 1) {
+      sctp_mss = -1;
+      get_sctp_info(send_socket[0], &sctp_mss);
+    }
+
+    /* signal the server that we are all done writing, this will
+     * initiate a shutdonw of one of the associations on the
+     * server and trigger an event telling the server it's all done
+     */ 
+    sctp_sendmsg(send_socket[0], NULL, 0, remote_res->ai_addr,
+		 remote_res->ai_addrlen, 0, MSG_EOF, 0, 0, 0);
+
+    
+    /* The test server will initiate closure of all associations
+     * when it's done reading. We want a basic mechanism to catch this
+     * and are using SCTP events for this.
+     * In blocking mode, we can call recvmsg with the last socket we created.
+     * In non-blocking  mode, we need to select on the socket for reading.
+     * We'll assume that all returns are succefull and signify
+     * closure.
+     * It is sufficient to do this on a single socket in the client.
+     * We choose to do it on a socket other then the one that send MSG_EOF.
+     * This means that anything comming in on that socket will be a shutdown.
+     */
+    if (non_block) {
+	fd_set readfds;
+
+	FD_ZERO(&readfds);
+	FD_SET(send_socket[num_associations-1], &readfds);
+	select(send_socket[num_associations-1]+1, &readfds, NULL, NULL, NULL);
+    } else {
+	sctp_recvmsg(send_socket[num_associations], send_ring->buffer_ptr,
+		     send_size, NULL, 0, NULL, 0);
+    }
+    
+    /* 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? */
+    
+    /* we are finished with our sockets, so close them to prevent hitting */
+    /* the limit on maximum open files. */
+    for (j = 0; j < num_associations; j++)
+	close(send_socket[j]);
+
+    /* 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);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      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 sctp 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	= ntohd(sctp_stream_result->bytes_received);
+
+    thruput	= (double) 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= sctp_stream_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      sctp_stream_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(sctp_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 */
+    /* sctp 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)sctp_stream_result->recv_calls,
+	    sctp_stream_result->recv_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    sctp_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 sctp stream test. It is */
+/* implemented as one routine. I could break things-out somewhat, but */
+/* didn't feel it was necessary. */
+
+void
+recv_sctp_stream_1toMany()
+{
+  
+  struct sockaddr_in myaddr_in;
+  int	s_recv;
+  int 	addrlen;
+  int	len;
+  unsigned int	receive_calls;
+  float	elapsed_time;
+  double   bytes_received;
+  int	msg_flags = 0;
+  
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+#ifdef DIRTY
+  int   *message_int_ptr;
+  int   dirty_count;
+  int   clean_count;
+  int   i;
+#endif
+  
+#ifdef DO_SELECT
+  fd_set readfds;
+  struct timeval timeout;
+#endif
+
+  struct	sctp_stream_request_struct	*sctp_stream_request;
+  struct	sctp_stream_response_struct	*sctp_stream_response;
+  struct	sctp_stream_results_struct	*sctp_stream_results;
+  
+#ifdef DO_SELECT
+  FD_ZERO(&readfds);
+  timeout.tv_sec = 1;
+  timeout.tv_usec = 0;
+#endif
+
+  sctp_stream_request	= 
+    (struct sctp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sctp_stream_response	= 
+    (struct sctp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sctp_stream_results	= 
+    (struct sctp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sctp_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_sctp_stream_1toMany: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SCTP_STREAM_MANY_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sctp_stream_1toMany: 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_sctp_stream_1toMany: requested alignment of %d\n",
+	    sctp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = sctp_stream_request->send_buf_size;
+  lsr_size_req = sctp_stream_request->recv_buf_size;
+  loc_nodelay = sctp_stream_request->no_delay;
+  loc_rcvavoid = sctp_stream_request->so_rcvavoid;
+  loc_sndavoid = sctp_stream_request->so_sndavoid;
+  non_block = sctp_stream_request->non_blocking;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sctp_stream_request->ipfamily),
+			sctp_stream_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sctp_stream_request->ipfamily),
+				SOCK_SEQPACKET,
+				IPPROTO_SCTP,
+				0);
+
+  s_recv = create_data_socket(local_res);
+  
+  if (s_recv < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+  /* what sort of sizes did we end-up with? */
+  if (sctp_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = sctp_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,
+				   sctp_stream_request->recv_alignment,
+				   sctp_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_sctp_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* Now, let's set-up the socket to listen for connections */
+  if (listen(s_recv, 5) == -1) {
+    netperf_response.content.serv_errno = errno;
+    close(s_recv);
+    send_response();
+    
+    exit(1);
+  }
+
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_recv, 
+		  (struct sockaddr *)&myaddr_in,
+		  &addrlen) == -1){
+    netperf_response.content.serv_errno = errno;
+    close(s_recv);
+    send_response();
+    
+    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. */
+  
+  sctp_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. */
+  
+  sctp_stream_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (sctp_stream_request->measure_cpu) {
+    sctp_stream_response->measure_cpu = 1;
+    sctp_stream_response->cpu_rate = 
+      calibrate_local_cpu(sctp_stream_request->cpu_rate);
+  }
+  else {
+    sctp_stream_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sctp_stream_response->send_buf_size = lss_size;
+  sctp_stream_response->recv_buf_size = lsr_size;
+  sctp_stream_response->no_delay = loc_nodelay;
+  sctp_stream_response->so_rcvavoid = loc_rcvavoid;
+  sctp_stream_response->so_sndavoid = loc_sndavoid;
+  sctp_stream_response->receive_size = recv_size;
+
+  send_response();
+  
+
+  sctp_enable_events(s_recv, SCTP_ASSOC_CHANGE_EV | SCTP_SHUTDOWN_EV);
+  
+  /* now that we are connected, mark the socket as non-blocking */
+  if (non_block) {
+      if (!set_nonblock(s_recv)) {
+	close(s_recv);
+	exit(1);
+      }
+  }
+
+
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(sctp_stream_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+#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. */
+
+  dirty_count = sctp_stream_request->dirty_count;
+  clean_count = sctp_stream_request->clean_count;
+  message_int_ptr = (int *)recv_ring->buffer_ptr;
+  for (i = 0; i < dirty_count; i++) {
+    *message_int_ptr = rand();
+    message_int_ptr++;
+  }
+  for (i = 0; i < clean_count; i++) {
+    dirty_count = *message_int_ptr;
+    message_int_ptr++;
+  }
+#endif /* DIRTY */
+
+  bytes_received = 0;
+  receive_calls  = 0;
+  
+  while ((len = sctp_recvmsg(s_recv, recv_ring->buffer_ptr, recv_size,
+			     NULL, 0,  /* we don't care who it's from */
+			     NULL, &msg_flags)) != 0) {
+    if (len < 0) {
+      if (non_block && errno == EAGAIN) {
+	Set_errno(0);
+	continue;
+      }
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      close(s_recv);
+      exit(1);
+    }
+
+    if (msg_flags & MSG_NOTIFICATION) {
+	if (sctp_process_event(s_recv, recv_ring->buffer_ptr) == SCTP_CLOSE)
+	    break;
+
+	continue;
+    }
+    
+    bytes_received += len;
+    receive_calls++;
+
+    /* more to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+
+#ifdef PAUSE
+    sleep(1);
+#endif /* PAUSE */
+
+#ifdef DIRTY
+    message_int_ptr = (int *)(recv_ring->buffer_ptr);
+    for (i = 0; i < dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < clean_count; i++) {
+      dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+
+#ifdef DO_SELECT
+	FD_SET(s_recv,&readfds);
+	select(s_recv+1,&readfds,NULL,NULL,&timeout);
+#endif /* DO_SELECT */
+
+  }
+  
+  /* perform a shutdown to signal the sender.  in this case, sctp
+   * will close all associations on this socket
+   */
+  if (close(s_recv) == -1) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+  }
+  
+  cpu_stop(sctp_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_stream: got %g bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_sctp_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  sctp_stream_results->bytes_received	= htond(bytes_received);
+  sctp_stream_results->elapsed_time	= elapsed_time;
+  sctp_stream_results->recv_calls	= receive_calls;
+  
+  if (sctp_stream_request->measure_cpu) {
+    sctp_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_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);
+  }
+  
+  sctp_stream_results->cpu_method = cpu_method;
+  sctp_stream_results->num_cpus   = lib_num_loc_cpus;
+  send_response();
+}
+
+
+ /* this routine implements the sending (netperf) side of the SCTP_RR */
+ /* test. */
+
+void
+send_sctp_rr(remote_host)
+     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;
+  int	send_socket;
+  int	trans_remaining;
+  int   msg_flags = 0;
+  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 sockaddr_storage peer;
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+
+  struct	sctp_rr_request_struct	*sctp_rr_request;
+  struct	sctp_rr_response_struct	*sctp_rr_response;
+  struct	sctp_rr_results_struct	*sctp_rr_result;
+  
+#ifdef WANT_INTERVALS
+  int	interval_count;
+  sigset_t signal_set;
+#endif /* WANT_INTERVALS */
+
+  sctp_rr_request = 
+    (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sctp_rr_response =
+    (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sctp_rr_result =
+    (struct sctp_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. */
+
+  /* complete_addrinfos will either succede or exit the process */
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_SCTP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("SCTP REQUEST/RESPONSE TEST", local_res, remote_res);
+  }
+  
+  /* 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_data_socket(local_res);
+  
+    if (send_socket < 0){
+      perror("netperf: send_sctp_rr: sctp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_sctp_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_SCTP_RR;
+    sctp_rr_request->recv_buf_size	=	rsr_size_req;
+    sctp_rr_request->send_buf_size	=	rss_size_req;
+    sctp_rr_request->recv_alignment     =	remote_recv_align;
+    sctp_rr_request->recv_offset        =	remote_recv_offset;
+    sctp_rr_request->send_alignment     =	remote_send_align;
+    sctp_rr_request->send_offset	=	remote_send_offset;
+    sctp_rr_request->request_size	=	req_size;
+    sctp_rr_request->response_size	=	rsp_size;
+    sctp_rr_request->no_delay	        =	rem_nodelay;
+    sctp_rr_request->measure_cpu	=	remote_cpu_usage;
+    sctp_rr_request->cpu_rate	        =	remote_cpu_rate;
+    sctp_rr_request->so_rcvavoid	        =	rem_rcvavoid;
+    sctp_rr_request->so_sndavoid	        =	rem_sndavoid;
+    if (test_time) {
+      sctp_rr_request->test_length	=	test_time;
+    }
+    else {
+      sctp_rr_request->test_length	=	test_trans * -1;
+    }
+    sctp_rr_request->non_blocking	= 	non_block;
+    sctp_rr_request->ipfamily           = af_to_nf(remote_res->ai_family);
+
+    if (debug > 1) {
+      fprintf(where,"netperf: send_sctp_rr: requesting SCTP 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 sctp tests.					*/
+  
+    recv_response();
+  
+    if (!netperf_response.content.serv_errno) {
+      if (debug)
+	fprintf(where,"remote listen done.\n");
+      rsr_size          = sctp_rr_response->recv_buf_size;
+      rss_size          = sctp_rr_response->send_buf_size;
+      rem_nodelay       = sctp_rr_response->no_delay;
+      remote_cpu_usage  = sctp_rr_response->measure_cpu;
+      remote_cpu_rate   = sctp_rr_response->cpu_rate;
+      /* make sure that port numbers are in network order */
+      set_port_number(remote_res, 
+		      (unsigned short)sctp_rr_response->data_port_number);
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      exit(1);
+    }
+    
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) <0){
+      perror("netperf: send_sctp_rr data socket connect failed");
+      exit(1);
+    }
+
+    /* don't need events for 1-to-1 API with request-response tests */
+    sctp_enable_events(send_socket, 0);
+
+    /* set non-blocking if needed */
+    if (non_block) {
+       if (!set_nonblock(send_socket)) {
+	    close(send_socket);
+	    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_sctp_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. */
+
+#ifdef WANT_FIRST_BURST
+    {
+      int i;
+      for (i = 0; i < first_burst_size; i++) {
+ 	if((len=sctp_sendmsg(send_socket,
+ 			     send_ring->buffer_ptr, req_size,
+ 			     NULL, 0,	/* don't need addrs with 1-to-1 */
+ 			     0, 0, 0, 0, 0)) != req_size) {
+	  /* we should never hit the end of the test in the first burst */
+	  perror("send_sctp_rr: initial burst data send error");
+	  exit(1);
+	}
+      }
+    }
+#endif /* WANT_FIRST_BURST */
+
+    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 */
+      
+      while ((len=sctp_sendmsg(send_socket,
+			       send_ring->buffer_ptr, req_size,
+			       NULL, 0, /* don't need addrs with 1-to-1 */
+			       0, 0, 0, 0, 0)) != req_size) {
+	if (non_block && errno == EAGAIN) {
+	    /* try sending again */
+	    continue;
+	} else if (SOCKET_EINTR(len) || (errno == 0)) {
+	  /* we hit the end of a */
+	  /* timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_sctp_rr: data send error");
+	exit(1);
+      }
+
+      if (timed_out) {
+	/* we timed out while sending. break out another level */
+	break;
+      }
+      send_ring = send_ring->next;
+      
+      /* receive the response */
+      rsp_bytes_left = rsp_size;
+      temp_message_ptr  = recv_ring->buffer_ptr;
+      do {
+	msg_flags = 0;
+	if ((rsp_bytes_recvd=sctp_recvmsg(send_socket,
+					 temp_message_ptr, rsp_bytes_left,
+					 NULL, 0,
+					 NULL, &msg_flags)) < 0) {
+	  if (errno == EINTR) {
+	    /* We hit the end of a timed test. */
+	    timed_out = 1;
+	    break;
+	  } else if (non_block && errno == EAGAIN) {
+	      continue;
+	  }
+	  perror("send_sctp_rr: data recv error");
+	  exit(1);
+	}
+	rsp_bytes_left -= rsp_bytes_recvd;
+	temp_message_ptr  += rsp_bytes_recvd;
+      }	while (!(msg_flags & MSG_EOR));
+      
+      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 > 1) {
+	  fprintf(where,"about to suspend\n");
+	  fflush(where);
+	}
+	if (sigsuspend(&signal_set) == EFAULT) {
+	  fprintf(where,
+		  "send_sctp_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);
+	}
+      }
+    }
+
+    /* At this point we used to call shutdown on the data socket to be */
+    /* sure all the data was delivered, but this was not germane in a */
+    /* request/response test, and it was causing the tests to "hang" when */
+    /* they were being controlled by time. So, I have replaced this */
+    /* shutdown call with a call to close that can be found later in the */
+    /* procedure. */
+    
+    /* 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 CPU utilization. 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);
+      fprintf(where,"netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      exit(1);
+    }
+    
+    /* We now calculate what our throughput 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = sctp_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,
+						    sctp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    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(sctp_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 */
+
+  }
+  
+}
+
+
+ /* this routine implements the receive (netserver) side of a TCP_RR */
+ /* test */
+void
+recv_sctp_rr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+  
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct sockaddr_in        myaddr_in, peeraddr_in;
+  int	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	sctp_rr_request_struct	*sctp_rr_request;
+  struct	sctp_rr_response_struct	*sctp_rr_response;
+  struct	sctp_rr_results_struct	*sctp_rr_results;
+  
+  sctp_rr_request = 
+    (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sctp_rr_response =
+    (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sctp_rr_results =
+    (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sctp_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_sctp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SCTP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sctp_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_sctp_rr: requested recv alignment of %d offset %d\n",
+	    sctp_rr_request->recv_alignment,
+	    sctp_rr_request->recv_offset);
+    fprintf(where,"recv_sctp_rr: requested send alignment of %d offset %d\n",
+	    sctp_rr_request->send_alignment,
+	    sctp_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,
+				   sctp_rr_request->response_size,
+				   sctp_rr_request->send_alignment,
+				   sctp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   sctp_rr_request->request_size,
+				   sctp_rr_request->recv_alignment,
+				   sctp_rr_request->recv_offset);
+
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_sctp_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = sctp_rr_request->send_buf_size;
+  lsr_size_req = sctp_rr_request->recv_buf_size;
+  loc_nodelay = sctp_rr_request->no_delay;
+  loc_rcvavoid = sctp_rr_request->so_rcvavoid;
+  loc_sndavoid = sctp_rr_request->so_sndavoid;
+  non_block = sctp_rr_request->non_blocking;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sctp_rr_request->ipfamily),
+			sctp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sctp_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_SCTP,
+				0);
+
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* Now, let's set-up the socket to listen for connections */
+  if (listen(s_listen, 5) == -1) {
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+  
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_listen,
+		  (struct sockaddr *)&myaddr_in, &addrlen) == -1){
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    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. */
+  
+  sctp_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. */
+  
+  sctp_rr_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  sctp_rr_response->measure_cpu = 0;
+
+  if (sctp_rr_request->measure_cpu) {
+    sctp_rr_response->measure_cpu = 1;
+    sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sctp_rr_response->send_buf_size = lss_size;
+  sctp_rr_response->recv_buf_size = lsr_size;
+  sctp_rr_response->no_delay = loc_nodelay;
+  sctp_rr_response->so_rcvavoid = loc_rcvavoid;
+  sctp_rr_response->so_sndavoid = loc_sndavoid;
+  sctp_rr_response->test_length = sctp_rr_request->test_length;
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+
+  if ((s_data = accept(s_listen,
+		       (struct sockaddr *)&peeraddr_in,
+		       &addrlen)) == -1) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    
+    exit(1);
+  }
+
+  /* we do not need events on a 1-to-1 RR test.  The test will finish
+   * once all transactions are done.
+   */
+
+  /* now that we are connected, mark the socket as non-blocking */
+  if (non_block) {
+    if (!set_nonblock(s_data)) {
+      perror("netperf: set_nonblock");
+	exit(1);
+    }
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+  if (debug) {
+    fprintf(where,"recv_sctp_rr: accept completes on the data connection.\n");
+    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(sctp_rr_request->measure_cpu);
+  
+  /* The loop will exit when we hit the end of the test time, or when */
+  /* we have exchanged the requested number of transactions. */
+  
+  if (sctp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(sctp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = sctp_rr_request->test_length * -1;
+  }
+
+  trans_received = 0;
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    int msg_flags = 0;
+
+    temp_message_ptr = recv_ring->buffer_ptr;
+    request_bytes_remaining = sctp_rr_request->request_size;
+    while(!(msg_flags & MSG_EOR)) {
+      if((request_bytes_recvd=sctp_recvmsg(s_data,
+					temp_message_ptr,
+					request_bytes_remaining,
+					NULL, 0,
+					NULL, &msg_flags)) < 0) {
+	if (errno == EINTR) {
+	  /* the timer popped */
+	  timed_out = 1;
+	  break;
+	} else if (non_block && errno == EAGAIN) {
+	    continue;  /* while request_bytes_remaining */
+	}
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      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,"yo55\n");
+	fflush(where);
+      }						
+      break;
+    }
+    
+
+    /* Now, send the response to the remote
+     * In 1-to-1 API destination addr is not needed.
+     */
+    while ((bytes_sent=sctp_sendmsg(s_data,
+				    send_ring->buffer_ptr,
+				    sctp_rr_request->response_size,
+				    NULL, 0,
+				    0, 0, 0, 0, 0)) == -1) {
+      if (errno == EINTR) {
+	/* the test timer has popped */
+	timed_out = 1;
+	break;
+      } else if (non_block && errno == EAGAIN) {
+	 continue;
+      }
+
+      netperf_response.content.serv_errno = 982;
+      send_response();
+      exit(1);
+    }
+
+    if (timed_out) {
+      /* we hit the end of the test based on time - lets */
+      /* bail out of here now... */
+      if (debug) {
+	fprintf(where,"yo6\n");
+	fflush(where);
+      }						
+      break;
+    }
+    
+    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(sctp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer();
+
+  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_sctp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  sctp_rr_results->bytes_received = (trans_received * 
+				    (sctp_rr_request->request_size + 
+				     sctp_rr_request->response_size));
+  sctp_rr_results->trans_received = trans_received;
+  sctp_rr_results->elapsed_time   = elapsed_time;
+  sctp_rr_results->cpu_method     = cpu_method;
+  sctp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (sctp_rr_request->measure_cpu) {
+    sctp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are now done with the sockets */
+  send_response();
+
+  close(s_data);
+  close(s_listen);
+  
+}
+
+
+
+/* this routine implements the sending (netperf) side of the
+   SCTP_RR_1TOMANY test */
+
+void
+send_sctp_rr_1toMany(remote_host)
+     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, j = 0;
+  char	*temp_message_ptr;
+  int	nummessages;
+  int	*send_socket;
+  int	trans_remaining;
+  double	bytes_xferd;
+  int   msg_flags = 0;
+
+  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 sockaddr_storage peer;
+  struct addrinfo *local_res;
+  struct addrinfo *remote_res;
+
+  struct	sctp_rr_request_struct	*sctp_rr_request;
+  struct	sctp_rr_response_struct	*sctp_rr_response;
+  struct	sctp_rr_results_struct	*sctp_rr_result;
+  
+#ifdef WANT_INTERVALS
+  int	interval_count;
+  sigset_t signal_set;
+#endif /* WANT_INTERVALS */
+
+  sctp_rr_request = 
+    (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sctp_rr_response =
+    (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sctp_rr_result =
+    (struct sctp_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. */
+
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_SEQPACKET,
+		     IPPROTO_SCTP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("SCTP 1-TO-MANY REQUEST/RESPONSE TEST",local_res,remote_res);
+  }
+
+  /* initialize a few counters */
+  
+  send_ring = NULL;
+  recv_ring = NULL;
+  confidence_iteration = 1;
+  init_stat();
+
+  send_socket = malloc(sizeof(int) * num_associations);
+  if (send_socket == NULL) {
+      fprintf(where,
+	      "Could not create the socket array for %d associations",
+	      num_associations);
+      fflush(where);
+      exit(1);
+  }
+
+  /* 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);
+    }
+    
+    /* 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_SCTP_RR_MANY;
+    sctp_rr_request->recv_buf_size     =	rsr_size_req;
+    sctp_rr_request->send_buf_size     =	rss_size_req;
+    sctp_rr_request->recv_alignment    =	remote_recv_align;
+    sctp_rr_request->recv_offset       =	remote_recv_offset;
+    sctp_rr_request->send_alignment    =	remote_send_align;
+    sctp_rr_request->send_offset       =	remote_send_offset;
+    sctp_rr_request->request_size      =	req_size;
+    sctp_rr_request->response_size     =	rsp_size;
+    sctp_rr_request->no_delay	       =	rem_nodelay;
+    sctp_rr_request->measure_cpu       =	remote_cpu_usage;
+    sctp_rr_request->cpu_rate	       =	remote_cpu_rate;
+    sctp_rr_request->so_rcvavoid       =	rem_rcvavoid;
+    sctp_rr_request->so_sndavoid       =	rem_sndavoid;
+    if (test_time) {
+      sctp_rr_request->test_length     =	test_time;
+    }
+    else {
+      sctp_rr_request->test_length     =	test_trans * num_associations
+						* -1;
+    }
+    sctp_rr_request->non_blocking      = 	non_block;
+    sctp_rr_request->port              =       atoi(remote_data_port);
+    sctp_rr_request->ipfamily          =       af_to_nf(remote_res->ai_family);
+    if (debug > 1) {
+      fprintf(where,"netperf: send_sctp_rr_1toMany: requesting SCTP 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 sctp tests.					*/
+  
+    recv_response();
+  
+    if (!netperf_response.content.serv_errno) {
+      rsr_size          = sctp_rr_response->recv_buf_size;
+      rss_size          = sctp_rr_response->send_buf_size;
+      rem_nodelay       = sctp_rr_response->no_delay;
+      remote_cpu_usage  = sctp_rr_response->measure_cpu;
+      remote_cpu_rate   = sctp_rr_response->cpu_rate;
+      /* make sure that port numbers are in network order */
+      set_port_number(remote_res,
+		      (unsigned short)sctp_rr_response->data_port_number);
+    }
+    else {
+      Set_errno(netperf_response.content.serv_errno);
+      fprintf(where,
+	      "netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      
+      exit(1);
+    }
+    
+    /*set up the data socket list  */
+    for (j = 0; j < num_associations; j++) {
+      send_socket[j] = create_data_socket(local_res);
+  
+      if (send_socket < 0){
+	perror("netperf: send_sctp_rr_1toMany: sctp stream data socket");
+	exit(1);
+      }
+      
+      /*Connect up to the remote port on the data socket  */
+      if (connect(send_socket[j], 
+		  remote_res->ai_addr,
+		  remote_res->ai_addrlen) < 0){
+	perror("netperf: data socket connect failed");
+	
+	exit(1);
+      }
+      
+      /* The client end of the 1-to-Many test uses 1-to-1 sockets.
+       * it doesn't need events.
+       */
+      sctp_enable_events(send_socket[j], 0);
+      
+      if (non_block) {
+        if (!set_nonblock(send_socket[j])) {
+	  close(send_socket[j]);
+	  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 * num_associations;
+      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_sctp_rr_1toMany: 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. */
+
+#ifdef WANT_FIRST_BURST
+    {
+      int i;
+      for (j = 0; j < num_associations; j++) {
+	  for (i = 0; i < first_burst_size; i++) {
+	    if((len=sctp_sendmsg(send_socket[j],
+			 send_ring->buffer_ptr, send_size,
+			 remote_res->ai_addr,
+			 remote_res->ai_addrlen,
+			 0, 0, 0, 0, 0)) != req_size) {
+	      /* we should never hit the end of the test in the first burst */
+	      perror("send_sctp_rr_1toMany: initial burst data send error");
+	      exit(1);
+	    }
+	  }
+      }
+    }
+#endif /* WANT_FIRST_BURST */
+
+    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. */
+      
+      /* this is a fairly poor way of testing 1toMany connections.
+       * For each association we measure round trip time to account for
+       * any delay in lookups and delivery.  To stress the server a bit
+       * more we would need a distributed client test, or at least multiple
+       * processes.  I want to force as much paralellism as possible, but
+       * this will do for the fist take. vlad
+       */
+      for (j = 0; j < num_associations; j++) {
+#ifdef WANT_HISTOGRAM
+	/* timestamp just before our call to send, and then again just */
+	/* after the receive raj 8/94 */
+	gettimeofday(&time_one,NULL);
+#endif /* WANT_HISTOGRAM */
+	
+	while ((len=sctp_sendmsg(send_socket[j],
+				 send_ring->buffer_ptr, send_size,
+				 remote_res->ai_addr,
+				 remote_res->ai_addrlen,
+				 0, 0, 0, 0, 0)) != req_size) {
+	  if (non_block && errno == EAGAIN) {
+	    /* try sending again */
+	    continue;
+	  } else if ((errno == EINTR) || (errno == 0)) {
+	    /* we hit the end of a */
+	    /* timed test. */
+	    timed_out = 1;
+	    break;
+	  }
+	  perror("send_sctp_rr_1toMany: data send error");
+	  exit(1);
+	}
+
+	if (timed_out) {
+	  /* we may have been in a nested while loop - we need */
+	  /* another call to break. */
+	  break;
+	}
+	
+	/* setup for the next time */
+	send_ring = send_ring->next;
+	
+	rsp_bytes_left = rsp_size;
+	temp_message_ptr  = recv_ring->buffer_ptr;
+	while (!(msg_flags & MSG_EOR)) {
+	  if((rsp_bytes_recvd = sctp_recvmsg(send_socket[j],
+					     temp_message_ptr,
+					     rsp_bytes_left,
+					     NULL, 0,
+					     NULL, &msg_flags)) < 0) {
+	    if (errno == EINTR) {
+	      /* We hit the end of a timed test. */
+	      timed_out = 1;
+	      break;
+	    } else if (non_block && errno == EAGAIN) {
+	      continue;
+	    }
+	    perror("send_sctp_rr_1toMany: 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;
+	}
+	
+#ifdef WANT_HISTOGRAM
+	gettimeofday(&time_two,NULL);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+#endif /* WANT_HISTOGRAM */
+	
+	nummessages++;          
+	if (trans_remaining) {
+	  trans_remaining--;
+	}
+	
+	if (debug > 3) {
+	  if ((nummessages % 100) == 0) {
+	    fprintf(where,
+		    "Transaction %d completed\n",
+		    nummessages);
+	    fflush(where);
+	  }
+	}
+      }
+    }
+    
+    /* At this point we used to call shutdown on the data socket to be */
+    /* sure all the data was delivered, but this was not germane in a */
+    /* request/response test, and it was causing the tests to "hang" when */
+    /* they were being controlled by time. So, I have replaced this */
+    /* shutdown call with a call to close that can be found later in the */
+    /* procedure. */
+    
+    /* 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 CPU utilization. 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);
+      fprintf(where,"netperf: remote error %d",
+	      netperf_response.content.serv_errno);
+      perror("");
+      fflush(where);
+      exit(1);
+    }
+    
+    /* We now calculate what our throughput 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = sctp_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,
+						    sctp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    for (j = 0; j < num_associations; j++)
+	close(send_socket[j]);
+  }
+
+  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(sctp_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 */
+
+  }
+  
+}
+
+
+ /* this routine implements the receive (netserver) side of a TCP_RR */
+ /* test */
+void
+recv_sctp_rr_1toMany()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+  
+
+  struct sockaddr_in        myaddr_in; 	/* needed to get the port number */
+  struct sockaddr_storage   peeraddr;   /* to communicate with peer */
+  struct addrinfo *local_res;
+  char   local_name[BUFSIZ];
+  char   port_buffer[PORTBUFSIZE];
+  int    msg_flags;
+
+  int	s_rcv;
+  int 	addrlen;
+  char	*temp_message_ptr;
+  int	trans_received;
+  int	trans_remaining;
+  int	bytes_sent;
+  int	bytes_recvd;
+  int	recv_buf_size;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	sctp_rr_request_struct	*sctp_rr_request;
+  struct	sctp_rr_response_struct	*sctp_rr_response;
+  struct	sctp_rr_results_struct	*sctp_rr_results;
+  
+  sctp_rr_request = 
+    (struct sctp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sctp_rr_response =
+    (struct sctp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sctp_rr_results =
+    (struct sctp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sctp_rr_1toMany: 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_sctp_rr_1toMany: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SCTP_RR_MANY_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sctp_rr_1toMany: 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_sctp_rr_1toMany: requested recv alignment of %d offset %d\n",
+	    sctp_rr_request->recv_alignment,
+	    sctp_rr_request->recv_offset);
+    fprintf(where,"recv_sctp_rr_1toMany: requested send alignment of %d offset %d\n",
+	    sctp_rr_request->send_alignment,
+	    sctp_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,
+				   sctp_rr_request->response_size,
+				   sctp_rr_request->send_alignment,
+				   sctp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   sctp_rr_request->request_size,
+				   sctp_rr_request->recv_alignment,
+				   sctp_rr_request->recv_offset);
+
+  
+  /* create_data_socket 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_req = sctp_rr_request->send_buf_size;
+  lsr_size_req = sctp_rr_request->recv_buf_size;
+  loc_nodelay = sctp_rr_request->no_delay;
+  loc_rcvavoid = sctp_rr_request->so_rcvavoid;
+  loc_sndavoid = sctp_rr_request->so_sndavoid;
+  non_block = sctp_rr_request->non_blocking;
+
+  set_hostname_and_port(local_name,
+		        port_buffer,
+			nf_to_af(sctp_rr_request->ipfamily),
+			sctp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sctp_rr_request->ipfamily),
+				SOCK_SEQPACKET,
+				IPPROTO_SCTP,
+				0);
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  if (debug) {
+    fprintf(where,"recv_sctp_rr_1toMany: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  s_rcv = create_data_socket(local_res);
+  
+  if (s_rcv < 0) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* Now, let's set-up the socket to listen for connections */
+  if (listen(s_rcv, 5) == -1) {
+    netperf_response.content.serv_errno = errno;
+    close(s_rcv);
+    send_response();
+    
+    exit(1);
+  }
+  
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_in);
+  if (getsockname(s_rcv,
+		  (struct sockaddr *)&myaddr_in, &addrlen) == -1){
+    netperf_response.content.serv_errno = errno;
+    close(s_rcv);
+    send_response();
+    
+    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. */
+  
+  sctp_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. */
+  
+  sctp_rr_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  sctp_rr_response->measure_cpu = 0;
+
+  if (sctp_rr_request->measure_cpu) {
+    sctp_rr_response->measure_cpu = 1;
+    sctp_rr_response->cpu_rate = calibrate_local_cpu(sctp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sctp_rr_response->send_buf_size = lss_size;
+  sctp_rr_response->recv_buf_size = lsr_size;
+  sctp_rr_response->no_delay = loc_nodelay;
+  sctp_rr_response->so_rcvavoid = loc_rcvavoid;
+  sctp_rr_response->so_sndavoid = loc_sndavoid;
+  sctp_rr_response->test_length = sctp_rr_request->test_length;
+  send_response();
+  
+  /* Don't need events */
+  sctp_enable_events(s_rcv, 0);
+
+  /* now that we are connected, mark the socket as non-blocking */
+  if (non_block) {
+    if (!set_nonblock(s_rcv)) {
+      perror("netperf: set_nonblock");
+	exit(1);
+    }
+  }
+
+  /* FIXME:  The way 1-to-Many test operates right now, we are including
+   * association setup time into our measurements.  The reason for this
+   * is that the client creates multiple endpoints and connects each
+   * endpoint to us using the connect call.  On this end we simply call
+   * recvmsg() to get data becuase there is no equivalen of accept() for
+   * 1-to-Many API.  
+   * I think this is OK, but if it were to be fixed, the server side
+   * would need to know how many associations are being setup and
+   * have a recvmsg() loop with SCTP_ASSOC_CHANGE events waiting for
+   * all the associations to be be established.
+   * I am punting on this for now.
+   */
+
+
+  addrlen = sizeof(peeraddr);
+
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(sctp_rr_request->measure_cpu);
+  
+  /* The loop will exit when we hit the end of the test time, or when */
+  /* we have exchanged the requested number of transactions. */
+  
+  if (sctp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(sctp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = sctp_rr_request->test_length * -1;
+  }
+
+  trans_received = 0;
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+
+    recv_buf_size = sctp_rr_request->request_size;
+ 
+    /* Receive the data.  We don't particularly care which association
+     * the data came in on.  We'll simply be doing a receive untill
+     * we get and MSG_EOR flag (meaning that a single transmission was
+     * received) and a send to the same address, so the RR would be for
+     * the same associations.
+     * We can get away with this because the client will establish all
+     * the associations before transmitting any data.  Any partial data
+     * will not have EOR thus will we will not send a response untill
+     * we get everything.
+     */
+    
+    do {
+      msg_flags = 0;
+      if((bytes_recvd = sctp_recvmsg(s_rcv,
+				     recv_ring->buffer_ptr,
+				     recv_buf_size,
+				     (struct sockaddr *)&peeraddr, &addrlen,
+				     0, &msg_flags)) == SOCKET_ERROR) {
+	if (SOCKET_EINTR(bytes_recvd)) {
+	  /* the timer popped */
+	  timed_out = 1;
+	  break;
+	} else if (non_block & errno == EAGAIN) {
+	    /* do recvmsg again */
+	    continue;
+	}
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+    } while(!(msg_flags & MSG_EOR));
+
+    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 */
+    while ((bytes_sent=sctp_sendmsg(s_rcv,
+			      send_ring->buffer_ptr,
+			      sctp_rr_request->response_size,
+			      (struct sockaddr *)&peeraddr, addrlen,
+			      0, 0, 0, 0, 0)) == SOCKET_ERROR) {
+      if (SOCKET_EINTR(bytes_sent)) {
+	/* the test timer has popped */
+	timed_out = 1;
+	break;
+      } else if (non_block && errno == EAGAIN) {
+	 continue;
+      }
+
+      netperf_response.content.serv_errno = 992;
+      send_response();
+      exit(1);
+    }
+
+    if (timed_out) {
+      if (debug) {
+	fprintf(where,"yo6\n");
+	fflush(where);
+      }						
+      /* we hit the end of the test based on time - lets */
+      /* bail out of here now... */
+      break;
+    }
+    
+    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(sctp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer();
+
+  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_sctp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  sctp_rr_results->bytes_received = (trans_received * 
+				    (sctp_rr_request->request_size + 
+				     sctp_rr_request->response_size));
+  sctp_rr_results->trans_received = trans_received;
+  sctp_rr_results->elapsed_time   = elapsed_time;
+  sctp_rr_results->cpu_method     = cpu_method;
+  sctp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (sctp_rr_request->measure_cpu) {
+    sctp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sctp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are now done with the sockets */
+  close(s_rcv);
+
+  send_response();
+  
+}
+
+
+void
+print_sctp_usage()
+{
+
+  printf("%s",sctp_usage);
+  exit(1);
+
+}
+void
+scan_sctp_args(argc, argv)
+     int	argc;
+     char	*argv[];
+
+{
+
+#define SOCKETS_ARGS "BDhH:I:L:m:M:P:r:s:S:VN:T:46"
+
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	
+    arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+
+  if (no_control) {
+    fprintf(where,
+	    "The SCTP tests do not know how to deal with no control tests\n");
+    exit(-1);
+  }
+
+  strncpy(local_data_port,"0",sizeof(local_data_port));
+  strncpy(remote_data_port,"0",sizeof(remote_data_port));
+  
+  /* 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, SOCKETS_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case '4':
+      remote_data_family = AF_INET;
+      local_data_family = AF_INET;
+      break;
+    case '6':
+#if defined(AF_INET6)
+      remote_data_family = AF_INET6;
+      local_data_family = AF_INET6;
+#else
+      fprintf(stderr,
+	      "This netperf was not compiled on an IPv6 capable host!\n");
+      fflush(stderr);
+      exit(-1);
+#endif
+      break;
+    case 'h':
+      print_sctp_usage();
+      exit(1);
+    case 'b':
+#ifdef WANT_FIRST_BURST
+      first_burst_size = atoi(optarg);
+#else /* WANT_FIRST_BURST */
+      printf("Initial request burst functionality not compiled-in!\n");
+#endif /* WANT_FIRST_BURST */
+      break;
+    case 'D':
+      /* set the nodelay flag */
+      loc_nodelay = 1;
+      rem_nodelay = 1;
+      break;
+    case 'H':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	remote_data_address = malloc(strlen(arg1)+1);
+	strncpy(remote_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	remote_data_family = parse_address_family(arg2);
+      break;
+    case 'L':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	local_data_address = malloc(strlen(arg1)+1);
+	strncpy(local_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	local_data_family = parse_address_family(arg2);
+      break;
+    case 'P':
+      /* set the local and remote data port numbers for the tests to
+	 allow them to run through those blankety blank end-to-end
+	 breaking firewalls. raj 2004-06-15 */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(local_data_port,arg1,sizeof(local_data_port));
+      if (arg2[0])	
+	strncpy(remote_data_port,arg2,sizeof(remote_data_port));
+      break;
+    case 's':
+      /* set local socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lss_size_req = convert(arg1);
+      if (arg2[0])
+	lsr_size_req = convert(arg2);
+      break;
+    case 'S':
+      /* set remote socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rss_size_req = convert(arg1);
+      if (arg2[0])
+	rsr_size_req = 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 size of the buffer for each sent message */
+      send_size = convert(optarg);
+      break;
+    case 'M':
+      /* set the size of the buffer for each received message */
+      recv_size = convert(optarg);
+      break;
+    case 't':
+      /* set the test name */
+      strcpy(test_name,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 'N':
+      /* this opton allows the user to set the number of 
+       * messages to send.  This in effect modifies the test
+       * time.  If we know the message size, then the we can
+       * express the test time as message_size * number_messages
+       */
+      msg_count = convert (optarg);
+      if (msg_count > 0)
+	  test_time = 0;
+      break;
+    case 'B':
+      non_block = 1;
+      break;
+    case 'T':
+      num_associations = atoi(optarg);
+      if (num_associations <= 1) {
+	  printf("Number of SCTP associations must be >= 1\n");
+	  exit(1);
+      }
+      break;
+    };
+  }
+}
+
+#endif  /* WANT_SCTP */
diff --git a/nettest_sctp.h b/nettest_sctp.h
new file mode 100644
index 0000000..5297853
--- /dev/null
+++ b/nettest_sctp.h
@@ -0,0 +1,128 @@
+/*
+        Copyright (C) 1993-2003 Hewlett-Packard Company
+*/
+
+ /* This file contains the test-specific definitions for netperf's BSD */
+ /* sockets tests */
+
+
+struct	sctp_stream_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	receive_size;   /* how many bytes do we want to receive at one */
+			/* time? */ 
+  int	recv_alignment; /* what is the alignment of the receive */
+			/* buffer? */ 
+  int	recv_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   port;		/* the to port to which recv side should bind
+			   to allow netperf to run through firewalls */
+  int   ipfamily;	/* address family of ipaddress */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct	sctp_stream_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	receive_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct sctp_stream_results_struct {
+  double         bytes_received;
+  unsigned int	 recv_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	sctp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;		/* the to port to which recv side should bind
+			   to allow netperf to run through firewalls */
+  int   ipfamily;	/* address family of ipaddress */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct	sctp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct sctp_rr_results_struct {
+  unsigned int  bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+#define SCTP_SNDRCV_INFO_EV		0x01
+#define SCTP_ASSOC_CHANGE_EV		0x02
+#define SCTP_PEERADDR_CHANGE_EV		0x04
+#define SCTP_SND_FAILED_EV		0x08
+#define SCTP_REMOTE_ERROR_EV		0x10
+#define SCTP_SHUTDOWN_EV		0x20
+#define SCTP_PD_EV			0x40
+#define SCTP_ADAPT_EV			0x80
+
+typedef enum sctp_disposition {
+    SCTP_OK = 1,
+    SCTP_CLOSE,
+} sctp_disposition_t;
+
+extern void send_sctp_stream();
+extern void send_sctp_rr();
+
+extern void recv_sctp_stream();
+extern void recv_sctp_rr();
+
+extern void loc_cpu_rate();
+extern void rem_cpu_rate();
diff --git a/nettest_sdp.c b/nettest_sdp.c
new file mode 100644
index 0000000..696fd3e
--- /dev/null
+++ b/nettest_sdp.c
@@ -0,0 +1,3553 @@
+#ifndef lint
+char	nettest_sdp[]="\
+@(#)nettest_sdp.c (c) Copyright 2007 Hewlett-Packard Co. Version 2.4.4";
+#else
+#define DIRTY
+#define WANT_HISTOGRAM
+#define WANT_INTERVALS
+#endif /* lint */
+
+/****************************************************************/
+/*								*/
+/*	nettest_sdp.c						*/
+/*								*/
+/*                                                              */
+/*      scan_sdp_args()        get the sdp command line args  */
+/*                                                              */
+/*	the actual test routines...				*/
+/*								*/
+/*	send_sdp_stream()	perform a sdp stream test	*/
+/*	recv_sdp_stream()					*/
+/*	send_sdp_rr()		perform a sdp request/response	*/
+/*	recv_sdp_rr()						*/
+/*								*/
+/*      relies on create_data_socket in nettest_bsd.c           */
+/****************************************************************/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(WANT_SDP)
+     
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#else /* NOSTDLIBH */
+#include <stdlib.h>
+#endif /* NOSTDLIBH */
+
+#if !defined(__VMS)
+#include <sys/ipc.h>
+#endif /* !defined(__VMS) */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+/* would seem that not all sdp.h files define a MSG_EOF, but that
+   MSG_EOF can be the same as MSG_FIN so lets work with that
+   assumption.  initial find by Jon Pedersen. raj 2006-02-01 */
+#ifndef MSG_EOF
+#ifdef MSG_FIN
+#define MSG_EOF MSG_FIN
+#else
+#error Must have either MSG_EOF or MSG_FIN defined
+#endif
+#endif 
+
+#include "netlib.h"
+#include "netsh.h"
+/* get some of the functions from nettest_bsd.c */
+#include "nettest_bsd.h"
+#include "nettest_sdp.h"
+
+#ifdef WANT_HISTOGRAM
+#ifdef __sgi
+#include <sys/time.h>
+#endif /* __sgi */
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_FIRST_BURST
+extern int first_burst_size;
+#endif /* WANT_FIRST_BURST */
+
+
+
+/* these variables are specific to SDP tests. declare */
+/* them static to make them global only to this file. */
+
+static int	
+  msg_count = 0,	/* number of messages to transmit on association */
+  non_block = 0,	/* default to blocking sockets */
+  num_associations = 1; /* number of associations on the endpoint */
+
+static  int confidence_iteration;
+static  char  local_cpu_method;
+static  char  remote_cpu_method;
+
+#ifdef WANT_HISTOGRAM
+static struct timeval time_one;
+static struct timeval time_two;
+static HIST time_hist;
+#endif /* WANT_HISTOGRAM */
+
+
+char sdp_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+SDP Sockets Test Options:\n\
+    -b number         Send number requests at the start of _RR tests\n\
+    -D [L][,R]        Set SDP_NODELAY locally and/or remotely\n\
+    -h                Display this text\n\
+    -H name,fam       Use name (or IP) and family as target of data connection\n\
+    -L name,fam       Use name (or IP) and family as source of data connextion\n\
+    -m bytes          Set the size of each sent message\n\
+    -M bytes          Set the size of each received messages\n\
+    -P local[,remote] Set the local/remote port for the data socket\n\
+    -r req,[rsp]      Set request/response sizes (_RR tests)\n\
+    -s send[,recv]    Set local socket send/recv buffer sizes\n\
+    -S send[,recv]    Set remote socket send/recv buffer sizes\n\
+    -V 		      Enable copy avoidance if supported\n\
+    -4                Use AF_INET (eg IPv4) on both ends of the data conn\n\
+    -6                Use AF_INET6 (eg IPv6) on both ends of the data conn\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 sdp */
+ /* 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 */
+static
+void
+get_sdp_info(int socket, int * mss)
+{
+
+#ifdef TCP_MAXSEG
+  netperf_socklen_t sock_opt_len;
+
+  sock_opt_len = sizeof(netperf_socklen_t);
+  if (getsockopt(socket,
+		 getprotobyname("tcp")->p_proto,	
+		 TCP_MAXSEG,
+		 (char *)mss,
+		 &sock_opt_len) == SOCKET_ERROR) {
+    fprintf(where,
+	    "netperf: get_sdp_info: getsockopt TCP_MAXSEG: errno %d\n",
+	    errno);
+    fflush(where);
+    *mss = -1;
+  }
+#else
+  *mss = -1;
+#endif /* TCP_MAXSEG */
+
+}
+
+void 
+send_sdp_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 %s\n";
+  
+  char *tput_fmt_1 =
+    "%6d %6d %6d    %-6.2f   %7.2f   %s\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 %s\n";
+
+  char *cpu_fmt_1 =
+    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f %s\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;
+  
+  /* 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. */
+  
+  struct ring_elt *send_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  SOCKET send_socket;
+  int bytes_remaining;
+  int sdp_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 */
+
+  unsigned long long local_bytes_sent = 0;
+  double	bytes_sent = 0.0;
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+  
+  struct	sdp_stream_request_struct	*sdp_stream_request;
+  struct	sdp_stream_response_struct	*sdp_stream_response;
+  struct	sdp_stream_results_struct	*sdp_stream_result;
+  
+  sdp_stream_request  = 
+    (struct sdp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sdp_stream_response =
+    (struct sdp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sdp_stream_result   = 
+    (struct sdp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  /* complete_addrinfos will either succede or exit the process */
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+  
+  if ( print_headers ) {
+    print_top_test_header("SDP STREAM TEST",local_res,remote_res);
+  }
+
+  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                        */
+    /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+    local_res->ai_family = AF_INET_SDP;
+    local_res->ai_protocol = 0;
+    send_socket = create_data_socket(local_res);
+    
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_sdp_stream: sdp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_sdp_stream: send_socket obtained...\n");
+    }
+    
+    /* 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);
+    }
+    
+    if (!no_control) {
+      /* 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_SDP_STREAM;
+      sdp_stream_request->send_buf_size	=	rss_size_req;
+      sdp_stream_request->recv_buf_size	=	rsr_size_req;
+      sdp_stream_request->receive_size	=	recv_size;
+      sdp_stream_request->no_delay	=	rem_nodelay;
+      sdp_stream_request->recv_alignment	=	remote_recv_align;
+      sdp_stream_request->recv_offset	=	remote_recv_offset;
+      sdp_stream_request->measure_cpu	=	remote_cpu_usage;
+      sdp_stream_request->cpu_rate	=	remote_cpu_rate;
+      if (test_time) {
+	sdp_stream_request->test_length	=	test_time;
+      }
+      else {
+	sdp_stream_request->test_length	=	test_bytes;
+      }
+      sdp_stream_request->so_rcvavoid	=	rem_rcvavoid;
+      sdp_stream_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+      sdp_stream_request->dirty_count     =       rem_dirty_count;
+      sdp_stream_request->clean_count     =       rem_clean_count;
+#endif /* DIRTY */
+      sdp_stream_request->port            =    atoi(remote_data_port);
+      sdp_stream_request->ipfamily = af_to_nf(remote_res->ai_family);
+      if (debug > 1) {
+	fprintf(where,
+		"netperf: send_sdp_stream: requesting SDP 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 SDP
+         tests.  */
+    
+      recv_response();
+    
+      if (!netperf_response.content.serv_errno) {
+	if (debug)
+	  fprintf(where,"remote listen done.\n");
+	rsr_size	      =	sdp_stream_response->recv_buf_size;
+	rss_size	      =	sdp_stream_response->send_buf_size;
+	rem_nodelay     =	sdp_stream_response->no_delay;
+	remote_cpu_usage=	sdp_stream_response->measure_cpu;
+	remote_cpu_rate = sdp_stream_response->cpu_rate;
+	
+	/* we have to make sure that the server port number is in
+	   network order */
+	set_port_number(remote_res,
+			(short)sdp_stream_response->data_port_number);
+	
+	rem_rcvavoid	= sdp_stream_response->so_rcvavoid;
+	rem_sndavoid	= sdp_stream_response->so_sndavoid;
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lss_size,rsr_size)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: send_sdp_stream: data socket connect failed");
+      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);
+
+    /* we only start the interval timer if we are using the
+       timer-timed intervals rather than the sit and spin ones. raj
+       2006-02-06 */    
+#if defined(WANT_INTERVALS)
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+    /* before we start, initialize a few variables */
+
+#ifdef WANT_DEMO
+      if (demo_mode) {
+	HIST_timestamp(demo_one_ptr);
+      }
+#endif
+      
+
+    /* 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
+      access_buffer(send_ring->buffer_ptr,
+		    send_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+#endif /* DIRTY */
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp just before we go into send and then again just
+	 after we come out raj 8/94 */
+	/* but lets only do this if there is going to be a histogram
+	   displayed */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+
+      if((len=send(send_socket,
+		   send_ring->buffer_ptr,
+		   send_size,
+		   0)) != send_size) {
+      if ((len >=0) || SOCKET_EINTR(len)) {
+	    /* the test was interrupted, must be the end of test */
+	    break;
+	  }
+	perror("netperf: data send error");
+	printf("len was %d\n",len);
+	exit(1);
+      }
+
+      local_bytes_sent += send_size;
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* 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_DEMO
+      DEMO_STREAM_INTERVAL(send_size)
+#endif 
+
+#if defined(WANT_INTERVALS)
+      INTERVALS_WAIT();
+#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 SDP maximum segment_size was (if possible) */
+    if (verbosity > 1) {
+      sdp_mss = -1;
+      get_sdp_info(send_socket,&sdp_mss);
+    }
+    
+    if (shutdown(send_socket,SHUT_WR) == SOCKET_ERROR) {
+      perror("netperf: cannot shutdown sdp stream socket");
+      exit(1);
+    }
+    
+    /* hang a recv() off the socket to block until the remote has */
+    /* brought all the data up into the application. it will do a */
+    /* shutdown to cause a FIN to be sent our way. We will assume that */
+    /* any exit from the recv() call is good... raj 4/93 */
+    
+    recv(send_socket, send_ring->buffer_ptr, send_size, 0);
+    
+    /* 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+
+    close(send_socket);
+
+    if (!no_control) {
+      /* 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);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	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
+	 SDP 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	= ntohd(sdp_stream_result->bytes_received);
+    }
+    else {
+      bytes_sent = (double)local_bytes_sent;
+    }
+
+    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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= sdp_stream_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      sdp_stream_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(sdp_stream_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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 */
+    /* SDP 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)sdp_stream_result->recv_calls,
+	    sdp_stream_result->recv_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    sdp_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 routine implements the netperf-side SDP unidirectional data
+   transfer test (a.k.a. stream) for the sockets interface where the
+   data flow is from the netserver to the netperf.  It receives its
+   parameters via global variables from the shell and writes its
+   output to the standard output. */
+
+
+void 
+send_sdp_maerts(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 %s\n";
+  
+  char *tput_fmt_1 =
+    "%6d %6d %6d    %-6.2f   %7.2f   \n %s";
+  
+  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 %s\n";
+
+  char *cpu_fmt_1 =
+    "%6d %6d %6d    %-6.2f     %7.2f   %-6.2f   %-6.2f   %-6.3f  %-6.3f %s\n";
+  
+  char *ksink_fmt = "\n\
+Alignment      Offset         %-8.8s %-8.8s    Recvs   %-8.8s Sends\n\
+Local  Remote  Local  Remote  Xfered   Per                 Per\n\
+Recv   Send    Recv   Send             Recv (avg)          Send (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;
+  
+  /* what we want is to have a buffer space that is at least one */
+  /* recv-size greater than our recv 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. */
+  
+  struct ring_elt *recv_ring;
+  
+  int len;
+  unsigned int nummessages = 0;
+  SOCKET recv_socket;
+  int bytes_remaining;
+  int sdp_mss = -1;  /* possibly uninitialized on printf far below */
+
+  /* with links like fddi, one can recv > 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 = 0.0;
+  unsigned long long local_bytes_recvd = 0;
+
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+
+  double	thruput;
+  
+  struct addrinfo *remote_res;
+  struct addrinfo *local_res;
+  
+  struct	sdp_maerts_request_struct	*sdp_maerts_request;
+  struct	sdp_maerts_response_struct	*sdp_maerts_response;
+  struct	sdp_maerts_results_struct	*sdp_maerts_result;
+  
+  sdp_maerts_request  = 
+    (struct sdp_maerts_request_struct *)netperf_request.content.test_specific_data;
+  sdp_maerts_response =
+    (struct sdp_maerts_response_struct *)netperf_response.content.test_specific_data;
+  sdp_maerts_result   = 
+    (struct sdp_maerts_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+  
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+  
+  if ( print_headers ) {
+    print_top_test_header("SDP MAERTS TEST",local_res,remote_res);
+  }
+
+  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_sent     =	0.0;
+    times_up       = 	0;
+    
+    /*set up the data socket                        */
+    /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+    local_res->ai_family = AF_INET_SDP;
+    local_res->ai_protocol = 0;
+    recv_socket = create_data_socket(local_res);
+    
+    if (recv_socket == INVALID_SOCKET){
+      perror("netperf: send_sdp_maerts: sdp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_sdp_maerts: recv_socket obtained...\n");
+    }
+
+    /* 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 recv */
+    /* 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 recv size to 4KB - no */
+    /* particular reason, just arbitrary... */
+    if (recv_size == 0) {
+      if (lsr_size > 0) {
+	recv_size = lsr_size;
+      }
+      else {
+	recv_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 recv-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 */
+    /* recv_size is bigger than the socket size, so we must check... the */
+    /* user may have wanted to explicitly set the "width" of our recv */
+    /* buffers, we should respect that wish... */
+    if (recv_width == 0) {
+      recv_width = (lsr_size/recv_size) + 1;
+      if (recv_width == 1) recv_width++;
+    }
+    
+    if (recv_ring == NULL) {
+      /* only allocate the recv 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 */
+      recv_ring = allocate_buffer_ring(recv_width,
+				       recv_size,
+				       local_recv_align,
+				       local_recv_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);
+    }
+    
+    if (!no_control) {
+      /* 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_SDP_MAERTS;
+      sdp_maerts_request->send_buf_size	=	rss_size_req;
+      sdp_maerts_request->recv_buf_size	=	rsr_size_req;
+      sdp_maerts_request->send_size	=	send_size;
+      sdp_maerts_request->no_delay	=	rem_nodelay;
+      sdp_maerts_request->send_alignment	=	remote_send_align;
+      sdp_maerts_request->send_offset	=	remote_send_offset;
+      sdp_maerts_request->measure_cpu	=	remote_cpu_usage;
+      sdp_maerts_request->cpu_rate	=	remote_cpu_rate;
+      if (test_time) {
+	sdp_maerts_request->test_length	=	test_time;
+      }
+      else {
+	sdp_maerts_request->test_length	=	test_bytes;
+      }
+      sdp_maerts_request->so_rcvavoid	=	rem_rcvavoid;
+      sdp_maerts_request->so_sndavoid	=	rem_sndavoid;
+#ifdef DIRTY
+      sdp_maerts_request->dirty_count       =       rem_dirty_count;
+      sdp_maerts_request->clean_count       =       rem_clean_count;
+#endif /* DIRTY */
+      sdp_maerts_request->port            = atoi(remote_data_port);
+      sdp_maerts_request->ipfamily        = af_to_nf(remote_res->ai_family);
+      if (debug > 1) {
+	fprintf(where,
+		"netperf: send_sdp_maerts: requesting SDP maerts 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 SDP
+	 tests.  */
+      
+      recv_response();
+    
+      if (!netperf_response.content.serv_errno) {
+	if (debug)
+	  fprintf(where,"remote listen done.\n");
+	rsr_size	=	sdp_maerts_response->recv_buf_size;
+	rss_size	=	sdp_maerts_response->send_buf_size;
+	rem_nodelay     =	sdp_maerts_response->no_delay;
+	remote_cpu_usage=	sdp_maerts_response->measure_cpu;
+	remote_cpu_rate = sdp_maerts_response->cpu_rate;
+	send_size       = sdp_maerts_response->send_size;
+	
+	/* we have to make sure that the server port number is in
+	 network order */
+      set_port_number(remote_res,
+		      (short)sdp_maerts_response->data_port_number);
+      rem_rcvavoid	= sdp_maerts_response->so_rcvavoid;
+      rem_sndavoid	= sdp_maerts_response->so_sndavoid;
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_STREAM_SETUP(lsr_size,rss_size)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(recv_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: send_sdp_maerts: data socket connect failed");
+      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 maerts 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 */
+      if (!no_control) {
+	/* this is a netperf to netserver test, netserver will close
+	   to tell us the test is over, so use PAD_TIME to avoid
+	   causing the netserver fits. */
+	start_timer(test_time + PAD_TIME);
+      }
+      else {
+	/* this is a netperf to data source test, no PAD_TIME */
+	start_timer(test_time);
+      }
+    }
+    else {
+      /* The tester wanted to recv a number of bytes. we don't do that 
+	 in a SDP_MAERTS test. sorry. raj 2002-06-21 */
+      printf("netperf: send_sdp_maerts: test must be timed\n");
+      exit(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
+    INTERVALS_INIT();
+#endif /* WANT_INTERVALS */
+
+    /* before we start, initialize a few variables */
+
+#ifdef WANT_DEMO
+    if (demo_mode) {
+      HIST_timestamp(demo_one_ptr);
+    }
+#endif
+
+    /* the test will continue until we either get a zero-byte recv()
+       on the socket or our failsafe timer expires. most of the time
+       we trust that we get a zero-byte recieve from the socket. raj
+       2002-06-21 */
+
+#ifdef WANT_HISTOGRAM
+    if (verbosity > 1) {
+      /* timestamp just before we go into recv and then again just
+	 after we come out raj 8/94 */
+      /* but only if we are actually going to display a histogram. raj
+	 2006-02-07 */
+      HIST_timestamp(&time_one);
+    }
+#endif /* WANT_HISTOGRAM */
+    
+    while ((!times_up) && (len=recv(recv_socket,
+				    recv_ring->buffer_ptr,
+				    recv_size,
+				    0)) > 0 ) {
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp the exit from the recv call and update the histogram */
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */      
+
+#ifdef DIRTY
+      access_buffer(recv_ring->buffer_ptr,
+		    recv_size,
+		    loc_dirty_count,
+		    loc_clean_count);
+#endif /* DIRTY */
+
+#ifdef WANT_DEMO
+      DEMO_STREAM_INTERVAL(len);
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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 recv width, and use that to calculate the offset to add */
+      /* to the base pointer. */
+      nummessages++;          
+      recv_ring = recv_ring->next;
+      if (bytes_remaining) {
+	bytes_remaining -= len;
+      }
+
+      local_bytes_recvd += len;
+
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* make sure we timestamp just before we go into recv  */
+	/* raj 2004-06-15 */
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+    
+    }
+
+    /* an EINTR is to be expected when this is a no_control test */
+    if (((len < 0) || SOCKET_EINTR(len)) && (!no_control)) {
+      perror("send_sdp_maerts: data recv error");
+      printf("len was %d\n",len);
+      exit(1);
+    }
+    
+    /* if we get here, it must mean we had a recv return of 0 before
+       the watchdog timer expired, or the watchdog timer expired and
+       this was a no_control test */
+
+    /* The test is over. Flush the buffers to the remote end. We do a
+       graceful release to tell the  remote we have all the data. */  
+
+    /* but first, if the verbosity is greater than 1, find-out what */
+    /* the SDP maximum segment_size was (if possible) */
+    if (verbosity > 1) {
+      sdp_mss = -1;
+      get_sdp_info(recv_socket,&sdp_mss);
+    }
+    
+    if (shutdown(recv_socket,SHUT_WR) == SOCKET_ERROR) {
+      perror("netperf: cannot shutdown sdp maerts socket");
+      exit(1);
+    }
+
+    stop_timer();
+    
+    /* this call will always give us the local 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? */
+    
+    /* we are finished with the socket, so close it to prevent hitting */
+    /* the limit on maximum open files. */
+
+    close(recv_socket);
+
+    if (!no_control) {
+      /* 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);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	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
+	 SDP maerts 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 recv_size, so we
+	 really didn't recv what he asked for ;-) */
+    
+      bytes_sent	= ntohd(sdp_maerts_result->bytes_sent);
+    }
+    else {
+      bytes_sent = (double)local_bytes_recvd;
+    }
+
+
+    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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	
+	remote_cpu_utilization	= sdp_maerts_result->cpu_util;
+	remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      sdp_maerts_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+    }    
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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(sdp_maerts_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      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 recvs */
+	      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    }
+  }
+  else {
+    /* The tester did not wish to measure service demand. */
+    
+    switch (verbosity) {
+    case 0:
+      fprintf(where,
+	      tput_fmt_0,
+	      thruput,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      break;
+    case 1:
+    case 2:
+      if (print_headers) {
+	fprintf(where,tput_title,format_units());
+      }
+      fprintf(where,
+	      tput_fmt_1,		/* the format string */
+	      lsr_size, 		/* local recvbuf size */
+	      rss_size, 		/* remot sendbuf size */
+	      send_size,		/* how large were the recvs */
+	      elapsed_time, 		/* how long did it take */
+	      thruput,                  /* how fast did it go */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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 */
+    /* SDP 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_recv_align,
+	    remote_recv_align,
+	    local_recv_offset,
+	    remote_recv_offset,
+	    bytes_sent,
+	    bytes_sent / (double)nummessages,
+	    nummessages,
+	    bytes_sent / (double)sdp_maerts_result->send_calls,
+	    sdp_maerts_result->send_calls);
+    fprintf(where,
+	    ksink_fmt2,
+	    sdp_mss);
+    fflush(where);
+#ifdef WANT_HISTOGRAM
+    fprintf(where,"\n\nHistogram of time spent in recv() call.\n");
+    fflush(where);
+    HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+  }
+  
+}
+/* This is the server-side routine for the sdp stream test. It is */
+/* implemented as one routine. I could break things-out somewhat, but */
+/* didn't feel it was necessary. */
+
+void
+recv_sdp_stream()
+{
+  
+  struct sockaddr_in myaddr_in, peeraddr_in;
+  SOCKET s_listen,s_data;
+  netperf_socklen_t addrlen;
+  int	len;
+  unsigned int	receive_calls;
+  float	elapsed_time;
+  double   bytes_received;
+  
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+#ifdef DO_SELECT
+  fd_set readfds;
+  struct timeval timeout;
+#endif /* DO_SELECT */
+
+  struct	sdp_stream_request_struct	*sdp_stream_request;
+  struct	sdp_stream_response_struct	*sdp_stream_response;
+  struct	sdp_stream_results_struct	*sdp_stream_results;
+  
+#ifdef DO_SELECT
+  FD_ZERO(&readfds);
+  timeout.tv_sec = 1;
+  timeout.tv_usec = 0;
+#endif /* DO_SELECT */
+
+  sdp_stream_request	= 
+    (struct sdp_stream_request_struct *)netperf_request.content.test_specific_data;
+  sdp_stream_response	= 
+    (struct sdp_stream_response_struct *)netperf_response.content.test_specific_data;
+  sdp_stream_results	= 
+    (struct sdp_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sdp_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_sdp_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SDP_STREAM_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sdp_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_sdp_stream: requested alignment of %d\n",
+	    sdp_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = sdp_stream_request->send_buf_size;
+  lsr_size_req = sdp_stream_request->recv_buf_size;
+  loc_nodelay  = sdp_stream_request->no_delay;
+  loc_rcvavoid = sdp_stream_request->so_rcvavoid;
+  loc_sndavoid = sdp_stream_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sdp_stream_request->ipfamily),
+			sdp_stream_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sdp_stream_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+  local_res->ai_family = AF_INET_SDP;
+  local_res->ai_protocol = 0;
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+  
+  /* what sort of sizes did we end-up with? */
+  if (sdp_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = sdp_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,
+				   sdp_stream_request->recv_alignment,
+				   sdp_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_sdp_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  sdp_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. */
+  
+  sdp_stream_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (sdp_stream_request->measure_cpu) {
+    sdp_stream_response->measure_cpu = 1;
+    sdp_stream_response->cpu_rate = 
+      calibrate_local_cpu(sdp_stream_request->cpu_rate);
+  }
+  else {
+    sdp_stream_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sdp_stream_response->send_buf_size = lss_size;
+  sdp_stream_response->recv_buf_size = lsr_size;
+  sdp_stream_response->no_delay = loc_nodelay;
+  sdp_stream_response->so_rcvavoid = loc_rcvavoid;
+  sdp_stream_response->so_sndavoid = loc_sndavoid;
+  sdp_stream_response->receive_size = recv_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  if ((s_data=accept(s_listen,
+		     (struct sockaddr *)&peeraddr_in,
+		     &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(sdp_stream_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  /* there used to be an #ifdef DIRTY call to access_buffer() here,
+     but we have switched from accessing the buffer before the recv()
+     call to accessing the buffer after the recv() call.  The
+     accessing before was, IIRC, related to having dirty data when
+     doing page-flipping copy avoidance. */
+
+  bytes_received = 0;
+  receive_calls  = 0;
+
+  while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
+    if (len == SOCKET_ERROR )
+	{
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    bytes_received += len;
+    receive_calls++;
+
+#ifdef DIRTY
+    /* we access the buffer after the recv() call now, rather than before */
+    access_buffer(recv_ring->buffer_ptr,
+		  recv_size,
+		  sdp_stream_request->dirty_count,
+		  sdp_stream_request->clean_count);
+#endif /* DIRTY */
+
+
+    /* move to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+
+#ifdef PAUSE
+    sleep(1);
+#endif /* PAUSE */
+
+#ifdef DO_SELECT
+	FD_SET(s_data,&readfds);
+	select(s_data+1,&readfds,NULL,NULL,&timeout);
+#endif /* DO_SELECT */
+
+  }
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+  
+  cpu_stop(sdp_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sdp_stream: got %g bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_sdp_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  sdp_stream_results->bytes_received	= htond(bytes_received);
+  sdp_stream_results->elapsed_time	= elapsed_time;
+  sdp_stream_results->recv_calls	= receive_calls;
+  
+  sdp_stream_results->cpu_method = cpu_method;
+  sdp_stream_results->num_cpus   = lib_num_loc_cpus;
+  
+  if (sdp_stream_request->measure_cpu) {
+    sdp_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sdp_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);
+  }
+
+  send_response();
+
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  }
+
+/* This is the server-side routine for the sdp maerts test. It is
+   implemented as one routine. I could break things-out somewhat, but
+   didn't feel it was necessary. */ 
+
+void
+recv_sdp_maerts()
+{
+  
+  struct sockaddr_in myaddr_in, peeraddr_in;
+  struct addrinfo *local_res;
+  char  local_name[BUFSIZ];
+  char  port_buffer[PORTBUFSIZE];
+
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	addrlen;
+  int	len;
+  unsigned int	send_calls;
+  float	elapsed_time;
+  double   bytes_sent = 0.0 ;
+  
+  struct ring_elt *send_ring;
+
+  struct	sdp_maerts_request_struct	*sdp_maerts_request;
+  struct	sdp_maerts_response_struct	*sdp_maerts_response;
+  struct	sdp_maerts_results_struct	*sdp_maerts_results;
+  
+  sdp_maerts_request	= 
+    (struct sdp_maerts_request_struct *)netperf_request.content.test_specific_data;
+  sdp_maerts_response	= 
+    (struct sdp_maerts_response_struct *)netperf_response.content.test_specific_data;
+  sdp_maerts_results	= 
+    (struct sdp_maerts_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sdp_maerts: 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_sdp_maerts: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SDP_MAERTS_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sdp_maerts: 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_sdp_maerts: requested alignment of %d\n",
+	    sdp_maerts_request->send_alignment);
+    fflush(where);
+  }
+
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_sdp_maerts: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  /* create_data_socket 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_req = sdp_maerts_request->send_buf_size;
+  lsr_size_req = sdp_maerts_request->recv_buf_size;
+  loc_nodelay = sdp_maerts_request->no_delay;
+  loc_rcvavoid = sdp_maerts_request->so_rcvavoid;
+  loc_sndavoid = sdp_maerts_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sdp_maerts_request->ipfamily),
+			sdp_maerts_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sdp_maerts_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+  local_res->ai_family = AF_INET_SDP;
+  local_res->ai_protocol = 0;
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+  
+  /* what sort of sizes did we end-up with? */
+  if (sdp_maerts_request->send_size == 0) {
+    if (lss_size > 0) {
+      send_size = lss_size;
+    }
+    else {
+      send_size = 4096;
+    }
+  }
+  else {
+    send_size = sdp_maerts_request->send_size;
+  }
+  
+  /* we want to set-up our recv_ring in a manner analagous to what we */
+  /* do on the recving 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 (send_width == 0) {
+    send_width = (lsr_size/send_size) + 1;
+    if (send_width == 1) send_width++;
+  }
+
+  send_ring = allocate_buffer_ring(send_width,
+				   send_size,
+				   sdp_maerts_request->send_alignment,
+				   sdp_maerts_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_sdp_maerts: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  sdp_maerts_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. */
+  
+  sdp_maerts_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  if (sdp_maerts_request->measure_cpu) {
+    sdp_maerts_response->measure_cpu = 1;
+    sdp_maerts_response->cpu_rate = 
+      calibrate_local_cpu(sdp_maerts_request->cpu_rate);
+  }
+  else {
+    sdp_maerts_response->measure_cpu = 0;
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sdp_maerts_response->send_buf_size = lss_size;
+  sdp_maerts_response->recv_buf_size = lsr_size;
+  sdp_maerts_response->no_delay = loc_nodelay;
+  sdp_maerts_response->so_rcvavoid = loc_rcvavoid;
+  sdp_maerts_response->so_sndavoid = loc_sndavoid;
+  sdp_maerts_response->send_size = send_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+
+  /* we will start the timer before the accept() to be somewhat
+     analagous to the starting of the timer before the connect() call
+     in the SDP_STREAM test. raj 2002-06-21 */
+
+  start_timer(sdp_maerts_request->test_length);
+
+  /* Now it's time to start receiving data on the connection. We will
+     first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(sdp_maerts_request->measure_cpu);
+  
+
+  if ((s_data=accept(s_listen,
+		     (struct sockaddr *)&peeraddr_in,
+		     &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+  
+  /* this is for those systems which *INCORRECTLY* fail to pass
+     attributes across an accept() call. Including this goes against
+     my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  bytes_sent = 0.0;
+  send_calls  = 0;
+
+  len = 0;   /* nt-lint; len is not initialized (printf far below) if
+		times_up initially true.*/
+  times_up = 0; /* must remember to initialize this little beauty */
+  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,
+		sdp_maerts_request->dirty_count,
+		sdp_maerts_request->clean_count);
+
+#endif /* DIRTY */
+
+    if((len=send(s_data,
+		 send_ring->buffer_ptr,
+		 send_size,
+		 0)) != send_size) {
+		if ((len >=0) || SOCKET_EINTR(len)) {
+	      /* the test was interrupted, must be the end of test */
+	      break;
+		}
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+
+    bytes_sent += len;
+    send_calls++;
+
+    /* more to the next buffer in the send_ring */
+    send_ring = send_ring->next;
+
+  }
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (shutdown(s_data,SHUT_WR) == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+
+  /* hang a recv() off the socket to block until the remote has
+     brought all the data up into the application. it will do a
+     shutdown to cause a FIN to be sent our way. We will assume that
+     any exit from the recv() call is good... raj 4/93 */
+    
+  recv(s_data, send_ring->buffer_ptr, send_size, 0);
+    
+  
+  cpu_stop(sdp_maerts_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sdp_maerts: got %g bytes\n",
+	    bytes_sent);
+    fprintf(where,
+	    "recv_sdp_maerts: got %d sends\n",
+	    send_calls);
+    fflush(where);
+  }
+  
+  sdp_maerts_results->bytes_sent	= htond(bytes_sent);
+  sdp_maerts_results->elapsed_time	= elapsed_time;
+  sdp_maerts_results->send_calls	= send_calls;
+  
+  if (sdp_maerts_request->measure_cpu) {
+    sdp_maerts_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sdp_maerts: test complete, sending results.\n");
+    fprintf(where,
+	    "                 bytes_sent %g send_calls %d\n",
+	    bytes_sent,
+	    send_calls);
+    fprintf(where,
+	    "                 len %d\n",
+	    len);
+    fflush(where);
+  }
+  
+  sdp_maerts_results->cpu_method = cpu_method;
+  sdp_maerts_results->num_cpus   = lib_num_loc_cpus;
+  send_response();
+
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  }
+
+
+ /* this routine implements the sending (netperf) side of the SDP_RR */
+ /* test. */
+
+void
+send_sdp_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 %s\n";
+  
+  char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d   %-6d  %-6.2f   %7.2f   %s\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 %s\n";
+  
+  char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d  %-6d %-6.2f  %-6.2f  %-6.2f %-6.2f %-6.3f  %-6.3f %s\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 addrinfo *local_res;
+  struct addrinfo *remote_res;
+
+  struct	sdp_rr_request_struct	*sdp_rr_request;
+  struct	sdp_rr_response_struct	*sdp_rr_response;
+  struct	sdp_rr_results_struct	*sdp_rr_result;
+
+#ifdef WANT_FIRST_BURST
+#define REQUEST_CWND_INITIAL 2
+  /* "in the beginning..." the WANT_FIRST_BURST stuff was like both
+     Unix and the state of New Jersey - both were simple an unspoiled.
+     then it was realized that some stacks are quite picky about
+     initial congestion windows and a non-trivial initial burst of
+     requests would not be individual segments even with TCP_NODELAY
+     set. so, we have to start tracking a poor-man's congestion window
+     up here in window space because we want to try to make something
+     happen that frankly, we cannot guarantee with the specification
+     of SDP.  ain't that grand?-)  raj 2006-01-30 */
+  int requests_outstanding = 0;
+  int request_cwnd = REQUEST_CWND_INITIAL;  /* we ass-u-me that having
+					       three requests
+					       outstanding at the
+					       beginning of the test
+					       is ok with SDP stacks
+					       of interest. the first
+					       two will come from our
+					       first_burst loop, and
+					       the third from our
+					       regularly scheduled
+					       send */
+#endif
+
+  sdp_rr_request = 
+    (struct sdp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sdp_rr_response=
+    (struct sdp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sdp_rr_result	=
+    (struct sdp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+#ifdef WANT_HISTOGRAM
+  if (verbosity > 1) {
+    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. */
+
+  complete_addrinfos(&remote_res,
+		     &local_res,
+		     remote_host,
+		     SOCK_STREAM,
+		     IPPROTO_TCP,
+		     0);
+
+  if ( print_headers ) {
+    print_top_test_header("SDP REQUEST/RESPONSE TEST",local_res,remote_res);
+  }
+  
+  /* 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;
+
+#ifdef WANT_FIRST_BURST
+    /* we have to remember to reset the number of transactions
+       outstanding and the "congestion window for each new
+       iteration. raj 2006-01-31 */
+    requests_outstanding = 0;
+    request_cwnd = REQUEST_CWND_INITIAL;
+#endif
+
+
+    /* 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                        */
+    /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+    local_res->ai_family = AF_INET_SDP;
+    local_res->ai_protocol = 0;
+    send_socket = create_data_socket(local_res);
+  
+    if (send_socket == INVALID_SOCKET){
+      perror("netperf: send_sdp_rr: sdp stream data socket");
+      exit(1);
+    }
+    
+    if (debug) {
+      fprintf(where,"send_sdp_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);
+    }
+    
+    if (!no_control) {
+      /* 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_SDP_RR;
+      sdp_rr_request->recv_buf_size	=	rsr_size_req;
+      sdp_rr_request->send_buf_size	=	rss_size_req;
+      sdp_rr_request->recv_alignment    =	remote_recv_align;
+      sdp_rr_request->recv_offset	=	remote_recv_offset;
+      sdp_rr_request->send_alignment    =	remote_send_align;
+      sdp_rr_request->send_offset	=	remote_send_offset;
+      sdp_rr_request->request_size	=	req_size;
+      sdp_rr_request->response_size	=	rsp_size;
+      sdp_rr_request->no_delay	        =	rem_nodelay;
+      sdp_rr_request->measure_cpu	=	remote_cpu_usage;
+      sdp_rr_request->cpu_rate	        =	remote_cpu_rate;
+      sdp_rr_request->so_rcvavoid	=	rem_rcvavoid;
+      sdp_rr_request->so_sndavoid	=	rem_sndavoid;
+      if (test_time) {
+	sdp_rr_request->test_length	=	test_time;
+      }
+      else {
+	sdp_rr_request->test_length	=	test_trans * -1;
+      }
+      sdp_rr_request->port              =      atoi(remote_data_port);
+      sdp_rr_request->ipfamily = af_to_nf(remote_res->ai_family);
+      
+      if (debug > 1) {
+	fprintf(where,"netperf: send_sdp_rr: requesting SDP 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 SDP
+	 tests.  */
+  
+      recv_response();
+  
+      if (!netperf_response.content.serv_errno) {
+	if (debug)
+	  fprintf(where,"remote listen done.\n");
+	rsr_size          = sdp_rr_response->recv_buf_size;
+	rss_size          = sdp_rr_response->send_buf_size;
+	rem_nodelay       = sdp_rr_response->no_delay;
+	remote_cpu_usage  = sdp_rr_response->measure_cpu;
+	remote_cpu_rate   = sdp_rr_response->cpu_rate;
+	/* make sure that port numbers are in network order */
+	set_port_number(remote_res,(short)sdp_rr_response->data_port_number);
+      }
+      else {
+	Set_errno(netperf_response.content.serv_errno);
+	fprintf(where,
+		"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	
+	exit(1);
+      }
+    }
+
+#ifdef WANT_DEMO
+    DEMO_RR_SETUP(1000)
+#endif
+
+    /*Connect up to the remote port on the data socket  */
+    if (connect(send_socket, 
+		remote_res->ai_addr,
+		remote_res->ai_addrlen) == INVALID_SOCKET){
+      perror("netperf: data socket connect failed");
+      
+      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
+    INTERVALS_INIT();
+#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. */
+
+#ifdef WANT_DEMO
+      if (demo_mode) {
+	HIST_timestamp(demo_one_ptr);
+      }
+#endif
+
+    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_FIRST_BURST
+      /* we can inject no more than request_cwnd, which will grow with
+	 time, and no more than first_burst_size.  we don't use <= to
+	 account for the "regularly scheduled" send call.  of course
+	 that makes it more a "max_outstanding_ than a
+	 "first_burst_size" but for now we won't fix the names. also,
+	 I suspect the extra check against < first_burst_size is
+	 redundant since later I expect to make sure that request_cwnd
+	 can never get larger than first_burst_size, but just at the
+	 moment I'm feeling like a belt and suspenders kind of
+	 programmer. raj 2006-01-30 */
+      while ((first_burst_size > 0) &&
+	     (requests_outstanding < request_cwnd) &&
+	     (requests_outstanding < first_burst_size)) {
+	if (debug) {
+	  fprintf(where,
+		  "injecting, req_outstndng %d req_cwnd %d burst %d\n",
+		  requests_outstanding,
+		  request_cwnd,
+		  first_burst_size);
+	}
+	if ((len = send(send_socket,
+			send_ring->buffer_ptr,
+			req_size,
+			0)) != req_size) {
+	  /* we should never hit the end of the test in the first burst */
+	  perror("send_sdp_rr: initial burst data send error");
+	  exit(-1);
+	}
+	requests_outstanding += 1;
+      }
+
+#endif /* WANT_FIRST_BURST */
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	/* timestamp just before our call to send, and then again just
+	   after the receive raj 8/94 */
+	/* but only if we are actually going to display one. raj
+	   2007-02-07 */
+
+	HIST_timestamp(&time_one);
+      }
+#endif /* WANT_HISTOGRAM */
+      
+      if ((len = send(send_socket,
+		      send_ring->buffer_ptr,
+		      req_size,
+		      0)) != req_size) {
+	if (SOCKET_EINTR(len) || (errno == 0)) {
+	  /* we hit the end of a */
+	  /* timed test. */
+	  timed_out = 1;
+	  break;
+	}
+	perror("send_sdp_rr: data send error");
+	exit(1);
+      }
+      send_ring = send_ring->next;
+
+#ifdef WANT_FIRST_BURST
+      requests_outstanding += 1;
+#endif
+
+      /* 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 ( SOCKET_EINTR(rsp_bytes_recvd) ) {
+		    /* We hit the end of a timed test. */
+			timed_out = 1;
+			break;
+		}
+	  perror("send_sdp_rr: data recv error");
+	  exit(1);
+	}
+	rsp_bytes_left -= rsp_bytes_recvd;
+	temp_message_ptr  += rsp_bytes_recvd;
+      }	
+      recv_ring = recv_ring->next;
+      
+#ifdef WANT_FIRST_BURST
+      /* so, since we've gotten a response back, update the
+	 bookkeeping accordingly.  there is one less request
+	 outstanding and we can put one more out there than before. */
+      requests_outstanding -= 1;
+      if (request_cwnd < first_burst_size) {
+	request_cwnd += 1;
+	if (debug) {
+	  fprintf(where,
+		  "incr req_cwnd to %d first_burst %d reqs_outstndng %d\n",
+		  request_cwnd,
+		  first_burst_size,
+		  requests_outstanding);
+	}
+      }
+#endif
+      if (timed_out) {
+	/* we may have been in a nested while loop - we need */
+	/* another call to break. */
+	break;
+      }
+      
+#ifdef WANT_HISTOGRAM
+      if (verbosity > 1) {
+	HIST_timestamp(&time_two);
+	HIST_add(time_hist,delta_micro(&time_one,&time_two));
+      }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+      DEMO_RR_INTERVAL(1);
+#endif
+
+#ifdef WANT_INTERVALS      
+      INTERVALS_WAIT();
+#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);
+	}
+      }
+    }
+
+    /* At this point we used to call shutdown on the data socket to be
+       sure all the data was delivered, but this was not germane in a
+       request/response test, and it was causing the tests to "hang"
+       when they were being controlled by time. So, I have replaced
+       this shutdown call with a call to close that can be found later
+       in the procedure. */
+    
+    /* 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? */
+    
+    if (!no_control) {
+      /* Get the statistics from the remote end. The remote will have
+	 calculated CPU utilization. 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);
+	fprintf(where,"netperf: remote error %d",
+		netperf_response.content.serv_errno);
+	perror("");
+	fflush(where);
+	exit(1);
+      }
+    }
+    
+    /* We now calculate what our throughput 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	= (float) -1.0;
+	local_service_demand	= (float) -1.0;
+      }
+      
+      if (remote_cpu_usage) {
+	remote_cpu_utilization = sdp_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,
+						    sdp_rr_result->num_cpus);
+      }
+      else {
+	remote_cpu_utilization = (float) -1.0;
+	remote_service_demand  = (float) -1.0;
+      }
+      
+    }
+    else {
+      /* we were not measuring cpu, for the confidence stuff, we */
+      /* should make it -1.0 */
+      local_cpu_utilization	= (float) -1.0;
+      local_service_demand	= (float) -1.0;
+      remote_cpu_utilization = (float) -1.0;
+      remote_service_demand  = (float) -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 */
+    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(sdp_rr_result->cpu_method);
+    
+    switch (verbosity) {
+    case 0:
+      if (local_cpu_usage) {
+	fprintf(where,
+		cpu_fmt_0,
+		local_service_demand,
+		local_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      else {
+	fprintf(where,
+		cpu_fmt_0,
+		remote_service_demand,
+		remote_cpu_method,
+		((print_headers) || 
+		 (result_brand == NULL)) ? "" : result_brand);
+      }
+      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 */
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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,
+	      ((print_headers) || 
+	       (result_brand == NULL)) ? "" : result_brand);
+      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 */
+    /* SDP 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 */
+
+  }
+  
+}
+ /* this routine implements the receive (netserver) side of a SDP_RR */
+ /* test */
+void
+recv_sdp_rr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct addrinfo *local_res;
+  char local_name[BUFSIZ];
+  char port_buffer[PORTBUFSIZE];
+
+  struct	sockaddr_in        myaddr_in,
+  peeraddr_in;
+  SOCKET	s_listen,s_data;
+  netperf_socklen_t 	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;
+  int   sock_closed = 0;
+  float	elapsed_time;
+  
+  struct	sdp_rr_request_struct	*sdp_rr_request;
+  struct	sdp_rr_response_struct	*sdp_rr_response;
+  struct	sdp_rr_results_struct	*sdp_rr_results;
+  
+  sdp_rr_request = 
+    (struct sdp_rr_request_struct *)netperf_request.content.test_specific_data;
+  sdp_rr_response =
+    (struct sdp_rr_response_struct *)netperf_response.content.test_specific_data;
+  sdp_rr_results =
+    (struct sdp_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_sdp_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_sdp_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = SDP_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_sdp_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_sdp_rr: requested recv alignment of %d offset %d\n",
+	    sdp_rr_request->recv_alignment,
+	    sdp_rr_request->recv_offset);
+    fprintf(where,"recv_sdp_rr: requested send alignment of %d offset %d\n",
+	    sdp_rr_request->send_alignment,
+	    sdp_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,
+				   sdp_rr_request->response_size,
+				   sdp_rr_request->send_alignment,
+				   sdp_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   sdp_rr_request->request_size,
+				   sdp_rr_request->recv_alignment,
+				   sdp_rr_request->recv_offset);
+
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_sdp_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_data_socket 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_req = sdp_rr_request->send_buf_size;
+  lsr_size_req = sdp_rr_request->recv_buf_size;
+  loc_nodelay = sdp_rr_request->no_delay;
+  loc_rcvavoid = sdp_rr_request->so_rcvavoid;
+  loc_sndavoid = sdp_rr_request->so_sndavoid;
+
+  set_hostname_and_port(local_name,
+			port_buffer,
+			nf_to_af(sdp_rr_request->ipfamily),
+			sdp_rr_request->port);
+
+  local_res = complete_addrinfo(local_name,
+				local_name,
+				port_buffer,
+				nf_to_af(sdp_rr_request->ipfamily),
+				SOCK_STREAM,
+				IPPROTO_TCP,
+				0);
+
+  /* fake things out by changing local_res->ai_family to AF_INET_SDP */
+  local_res->ai_family = AF_INET_SDP;
+  local_res->ai_protocol = 0;
+  s_listen = create_data_socket(local_res);
+  
+  if (s_listen == INVALID_SOCKET) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    
+    exit(1);
+  }
+  
+  
+#ifdef WIN32
+  /* The test timer can fire during operations on the listening socket,
+     so to make the start_timer below work we have to move
+     it to close s_listen while we are blocked on accept. */
+  win_kludge_socket2 = s_listen;
+#endif
+
+  
+  /* 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();
+    
+    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();
+    
+    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. */
+  
+  sdp_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. */
+  
+  sdp_rr_response->cpu_rate = (float)0.0; 	/* assume no cpu */
+  sdp_rr_response->measure_cpu = 0;
+
+  if (sdp_rr_request->measure_cpu) {
+    sdp_rr_response->measure_cpu = 1;
+    sdp_rr_response->cpu_rate = calibrate_local_cpu(sdp_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  sdp_rr_response->send_buf_size = lss_size;
+  sdp_rr_response->recv_buf_size = lsr_size;
+  sdp_rr_response->no_delay = loc_nodelay;
+  sdp_rr_response->so_rcvavoid = loc_rcvavoid;
+  sdp_rr_response->so_sndavoid = loc_sndavoid;
+  sdp_rr_response->test_length = sdp_rr_request->test_length;
+  send_response();
+  
+  addrlen = sizeof(peeraddr_in);
+  
+  if ((s_data = accept(s_listen,
+		       (struct sockaddr *)&peeraddr_in,
+		       &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    
+    exit(1);
+  }
+  
+#ifdef KLUDGE_SOCKET_OPTIONS
+  /* this is for those systems which *INCORRECTLY* fail to pass */
+  /* attributes across an accept() call. Including this goes against */
+  /* my better judgement :( raj 11/95 */
+
+  kludge_socket_options(s_data);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+#ifdef WIN32
+  /* this is used so the timer thread can close the socket out from */
+  /* under us, which to date is the easiest/cleanest/least */
+  /* Windows-specific way I can find to force the winsock calls to */
+  /* return WSAEINTR with the test is over. anything that will run on */
+  /* 95 and NT and is closer to what netperf expects from Unix signals */
+  /* and such would be appreciated raj 1/96 */
+  win_kludge_socket = s_data;
+#endif /* WIN32 */
+
+  if (debug) {
+    fprintf(where,"recv_sdp_rr: accept completes on the data connection.\n");
+    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(sdp_rr_request->measure_cpu);
+  
+  /* The loop will exit when we hit the end of the test time, or when */
+  /* we have exchanged the requested number of transactions. */
+  
+  if (sdp_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(sdp_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = sdp_rr_request->test_length * -1;
+  }
+
+  trans_received = 0;
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    temp_message_ptr = recv_ring->buffer_ptr;
+    request_bytes_remaining	= sdp_rr_request->request_size;
+    while(request_bytes_remaining > 0) {
+      if((request_bytes_recvd=recv(s_data,
+				   temp_message_ptr,
+				   request_bytes_remaining,
+				   0)) == SOCKET_ERROR) {
+	if (SOCKET_EINTR(request_bytes_recvd))
+	{
+	  timed_out = 1;
+	  break;
+	}
+
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      else if( request_bytes_recvd == 0 ) {
+	if (debug) {
+	  fprintf(where,"zero is my hero\n");
+	  fflush(where);
+	}
+	sock_closed = 1;
+	break;
+      }
+      else {
+	request_bytes_remaining -= request_bytes_recvd;
+	temp_message_ptr  += request_bytes_recvd;
+      }
+    }
+
+    recv_ring = recv_ring->next;
+
+    if ((timed_out) || (sock_closed)) {
+      /* we hit the end of the test based on time - or the socket
+	 closed on us along the way.  bail out of here now... */
+      if (debug) {
+	fprintf(where,"yo5\n");
+	fflush(where);
+      }						
+      break;
+    }
+    
+    /* Now, send the response to the remote */
+    if((bytes_sent=send(s_data,
+			send_ring->buffer_ptr,
+			sdp_rr_request->response_size,
+			0)) == SOCKET_ERROR) {
+      if (SOCKET_EINTR(bytes_sent)) {
+	/* the test timer has popped */
+	timed_out = 1;
+	fprintf(where,"yo6\n");
+	fflush(where);						
+	break;
+      }
+      netperf_response.content.serv_errno = 992;
+      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(sdp_rr_request->measure_cpu,&elapsed_time);
+  
+  stop_timer();
+
+  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_sdp_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  sdp_rr_results->bytes_received = (trans_received * 
+				    (sdp_rr_request->request_size + 
+				     sdp_rr_request->response_size));
+  sdp_rr_results->trans_received = trans_received;
+  sdp_rr_results->elapsed_time   = elapsed_time;
+  sdp_rr_results->cpu_method     = cpu_method;
+  sdp_rr_results->num_cpus       = lib_num_loc_cpus;
+  if (sdp_rr_request->measure_cpu) {
+    sdp_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_sdp_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  /* we are now done with the sockets */
+  close(s_data);
+  close(s_listen);
+
+  send_response();
+  
+}
+
+
+
+void
+print_sdp_usage()
+{
+
+  printf("%s",sdp_usage);
+  exit(1);
+
+}
+void
+scan_sdp_args(argc, argv)
+     int	argc;
+     char	*argv[];
+
+{
+
+#define SOCKETS_ARGS "b:DhH:I:L:m:M:P:r:s:S:V46"
+
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	
+    arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+
+  if (no_control) {
+    fprintf(where,
+	    "The SDP tests do not know how to deal with no control tests\n");
+    exit(-1);
+  }
+
+  strncpy(local_data_port,"0",sizeof(local_data_port));
+  strncpy(remote_data_port,"0",sizeof(remote_data_port));
+  
+  /* 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, SOCKETS_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case '4':
+      remote_data_family = AF_INET;
+      local_data_family = AF_INET;
+      break;
+    case '6':
+#if defined(AF_INET6)
+      remote_data_family = AF_INET6;
+      local_data_family = AF_INET6;
+#else
+      fprintf(stderr,
+	      "This netperf was not compiled on an IPv6 capable host!\n");
+      fflush(stderr);
+      exit(-1);
+#endif
+      break;
+    case 'h':
+      print_sdp_usage();
+      exit(1);
+    case 'b':
+#ifdef WANT_FIRST_BURST
+      first_burst_size = atoi(optarg);
+#else /* WANT_FIRST_BURST */
+      printf("Initial request burst functionality not compiled-in!\n");
+#endif /* WANT_FIRST_BURST */
+      break;
+    case 'D':
+      /* set the nodelay flag */
+      loc_nodelay = 1;
+      rem_nodelay = 1;
+      break;
+    case 'H':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	remote_data_address = malloc(strlen(arg1)+1);
+	strncpy(remote_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	remote_data_family = parse_address_family(arg2);
+      break;
+    case 'L':
+      break_args_explicit(optarg,arg1,arg2);
+      if (arg1[0]) {
+	/* make sure we leave room for the NULL termination boys and
+	   girls. raj 2005-02-82 */ 
+	local_data_address = malloc(strlen(arg1)+1);
+	strncpy(local_data_address,arg1,strlen(arg1));
+      }
+      if (arg2[0])
+	local_data_family = parse_address_family(arg2);
+      break;
+    case 'P':
+      /* set the local and remote data port numbers for the tests to
+	 allow them to run through those blankety blank end-to-end
+	 breaking firewalls. raj 2004-06-15 */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	strncpy(local_data_port,arg1,sizeof(local_data_port));
+      if (arg2[0])	
+	strncpy(remote_data_port,arg2,sizeof(remote_data_port));
+      break;
+    case 's':
+      /* set local socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lss_size_req = convert(arg1);
+      if (arg2[0])
+	lsr_size_req = convert(arg2);
+      break;
+    case 'S':
+      /* set remote socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rss_size_req = convert(arg1);
+      if (arg2[0])
+	rsr_size_req = 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 size of the buffer for each sent message */
+      send_size = convert(optarg);
+      break;
+    case 'M':
+      /* set the size of the buffer for each received message */
+      recv_size = convert(optarg);
+      break;
+    case 't':
+      /* set the test name */
+      strcpy(test_name,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 'N':
+      /* this opton allows the user to set the number of 
+       * messages to send.  This in effect modifies the test
+       * time.  If we know the message size, then the we can
+       * express the test time as message_size * number_messages
+       */
+      msg_count = convert (optarg);
+      if (msg_count > 0)
+	  test_time = 0;
+      break;
+    case 'B':
+      non_block = 1;
+      break;
+    case 'T':
+      num_associations = atoi(optarg);
+      if (num_associations <= 1) {
+	  printf("Number of SDP associations must be >= 1\n");
+	  exit(1);
+      }
+      break;
+    };
+  }
+}
+
+#endif  /* WANT_SDP */
diff --git a/nettest_sdp.h b/nettest_sdp.h
new file mode 100644
index 0000000..31d76bc
--- /dev/null
+++ b/nettest_sdp.h
@@ -0,0 +1,170 @@
+/*
+        Copyright (C) 2007 Hewlett-Packard Company
+*/
+
+ /* This file contains the test-specific definitions for netperf's SDP */
+ /* sockets tests */
+
+/* one of these days, this should not be required */
+#ifndef AF_INET_SDP
+#define AF_INET_SDP 27
+#define PF_INET_SDP AF_INET_SDP
+#endif 
+
+struct	sdp_stream_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	receive_size;   /* how many bytes do we want to receive at one */
+			/* time? */ 
+  int	recv_alignment; /* what is the alignment of the receive */
+			/* buffer? */ 
+  int	recv_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   port;		/* the to port to which recv side should bind
+			   to allow netperf to run through firewalls */
+  int   ipfamily;	/* address family of ipaddress */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct	sdp_stream_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	receive_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct sdp_stream_results_struct {
+  double         bytes_received;
+  unsigned int	 recv_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	sdp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   port;		/* the to port to which recv side should bind
+			   to allow netperf to run through firewalls */
+  int   ipfamily;	/* address family of ipaddress */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct	sdp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   non_blocking;   /* run the test in non-blocking mode */
+};
+
+struct sdp_rr_results_struct {
+  unsigned int  bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs had the remote? */
+};
+
+struct	sdp_maerts_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	send_size;      /* how many bytes do we want netserver to send
+			   at one time? */
+  int	send_alignment; /* what is the alignment of the send */
+			/* buffer? */ 
+  int	send_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the send buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   port;           /* the port to which the recv side should bind
+			   to allow netperf to run through those evil
+			   firewall things */
+  int   ipfamily;
+};
+
+struct	sdp_maerts_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct sdp_maerts_results_struct {
+  double         bytes_sent;
+  unsigned int	 send_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs had the remote? */
+};
+
+extern void send_sdp_stream();
+extern void send_sdp_rr();
+
+extern void recv_sdp_stream();
+extern void recv_sdp_rr();
+
+extern void loc_cpu_rate();
+extern void rem_cpu_rate();
diff --git a/nettest_unix.c b/nettest_unix.c
new file mode 100644
index 0000000..e4716a4
--- /dev/null
+++ b/nettest_unix.c
@@ -0,0 +1,3431 @@
+#ifdef lint
+#define WANT_UNIX
+#define DIRTY
+#define WANT_INTERVALS
+#endif /* lint */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WANT_UNIX
+char	nettest_unix_id[]="\
+@(#)nettest_unix.c (c) Copyright 1994-2007 Hewlett-Packard Co. Version 2.4.3";
+     
+/****************************************************************/
+/*								*/
+/*	nettest_bsd.c						*/
+/*								*/
+/*      the BSD sockets parsing routine...                      */
+/*                                                              */
+/*      scan_unix_args()                                        */
+/*                                                              */
+/*	the actual test routines...				*/
+/*								*/
+/*	send_stream_stream()  perform a stream stream test	*/
+/*	recv_stream_stream()					*/
+/*	send_stream_rr()      perform a stream request/response	*/
+/*	recv_stream_rr()					*/
+/*	send_dg_stream()      perform a dg stream test	        */
+/*	recv_dg_stream()					*/
+/*	send_dg_rr()	      perform a dg request/response	*/
+/*	recv_dg_rr()						*/
+/*	loc_cpu_rate()	      determine the local cpu maxrate   */
+/*	rem_cpu_rate()	      find the remote cpu maxrate	*/
+/*								*/
+/****************************************************************/
+     
+ /* at some point, I might want to go-in and see if I really need all */
+ /* these includes, but for the moment, we'll let them all just sit */
+ /* there. raj 8/94 */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <sys/ipc.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/un.h>
+#include <unistd.h>
+#else /* WIN32 */
+#include <process.h>
+#include <winsock2.h>
+#include <windows.h>
+#endif /* WIN32 */
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#else /* NOSTDLIBH */
+#include <stdlib.h>
+#endif /* NOSTDLIBH */
+
+#include <sys/stat.h>
+
+   
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_unix.h"
+
+
+
+ /* these variables are specific to the UNIX sockets tests. declare */
+ /* them static to make them global only to this file. */
+
+#define UNIX_PRFX "netperf."
+#define UNIX_LENGTH_MAX 0xFFFF - 28
+
+static char
+  path_prefix[32]; 
+
+static int	
+  rss_size,		/* remote socket send buffer size	*/
+  rsr_size,		/* remote socket recv buffer size	*/
+  lss_size_req,		/* requested local socket send buffer size */
+  lsr_size_req,		/* requested local 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	*/
+
+ /* different options for the sockets				*/
+
+
+char unix_usage[] = "\n\
+Usage: netperf [global options] -- [test options] \n\
+\n\
+STREAM/DG UNIX Sockets Test Options:\n\
+    -h                Display this text\n\
+    -m bytes          Set the send size (STREAM_STREAM, DG_STREAM)\n\
+    -M bytes          Set the recv size (STREAM_STREAM, DG_STREAM)\n\
+    -p dir            Set the directory where pipes are created\n\
+    -r req,res        Set request,response size (STREAM_RR, DG_RR)\n\
+    -s send[,recv]    Set local socket send/recv buffer sizes\n\
+    -S send[,recv]    Set remote socket send/recv buffer sizes\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 routing initializes all the test specific variables */
+
+static void
+init_test_vars()
+{
+  rss_size  = 0;
+  rsr_size  = 0;
+  lss_size_req = 0;
+  lsr_size_req = 0;
+  lss_size  = 0;
+  lsr_size  = 0;
+  req_size  = 1;
+  rsp_size  = 1;
+  send_size = 0;
+  recv_size = 0;
+
+  strcpy(path_prefix,"/tmp");
+
+}     
+
+ /* 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_UNIX, */
+ /* and type will be either SOCK_STREAM or SOCK_DGRAM */
+SOCKET
+create_unix_socket(int family, int type)
+{
+
+  SOCKET temp_socket;
+  int sock_opt_len;
+
+  /*set up the data socket                        */
+  temp_socket = socket(family, 
+		       type,
+		       0);
+  
+  if (temp_socket == INVALID_SOCKET){
+    fprintf(where,
+	    "netperf: create_unix_socket: socket: %d\n",
+	    errno);
+    fflush(where);
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"create_unix_socket: socket %d obtained...\n",temp_socket);
+    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 STREAM no-no. Also, by setting the */
+  /* buffer (window) size before the connection is established, we can */
+  /* control the STREAM 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.  */
+  
+  set_sock_buffer(temp_socket, SEND_BUFFER, lss_size_req, &lss_size);
+  set_sock_buffer(temp_socket, RECV_BUFFER, lsr_size_req, &lsr_size);
+
+  return(temp_socket);
+
+}
+
+
+/* This routine implements the STREAM unidirectional data transfer test */
+/* (a.k.a. stream) for the sockets interface. It receives its */
+/* parameters via global variables from the shell and writes its */
+/* output to the standard output. */
+
+
+void 
+send_stream_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 =
+    "%5d  %5d  %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  %%      %%       us/KB   us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.3f\n";
+  
+  char *cpu_fmt_1 =
+    "%5d  %5d  %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";
+  
+  
+  float			elapsed_time;
+  
+#ifdef WANT_INTERVALS
+  int interval_count;
+#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. */
+  
+#ifdef DIRTY
+  int	*message_int_ptr;
+#endif
+#include <sys/stat.h>
+
+  struct ring_elt *send_ring;
+  
+  int	len = 0;
+  int	nummessages;
+  SOCKET send_socket;
+  int	bytes_remaining;
+  /* with links like fddi, one can send > 32 bits worth of bytes */
+  /* during a test... ;-) */
+  double	bytes_sent;
+  
+#ifdef DIRTY
+  int	i;
+#endif /* DIRTY */
+  
+  float	local_cpu_utilization;
+  float	local_service_demand;
+  float	remote_cpu_utilization;
+  float	remote_service_demand;
+  double	thruput;
+  
+  struct	sockaddr_un	server;
+  
+  struct	stream_stream_request_struct	*stream_stream_request;
+  struct	stream_stream_response_struct	*stream_stream_response;
+  struct	stream_stream_results_struct	*stream_stream_result;
+  
+  stream_stream_request  = 
+    (struct stream_stream_request_struct *)netperf_request.content.test_specific_data;
+  stream_stream_response =
+    (struct stream_stream_response_struct *)netperf_response.content.test_specific_data;
+  stream_stream_result   = 
+    (struct stream_stream_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. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  server.sun_family = AF_UNIX;
+  
+  
+  if ( print_headers ) {
+    fprintf(where,"STREAM STREAM 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_sent	=	0.0;
+  times_up 	= 	0;
+  
+  /*set up the data socket                        */
+  send_socket = create_unix_socket(AF_UNIX, 
+				   SOCK_STREAM);
+  
+  if (send_socket == INVALID_SOCKET){
+    perror("netperf: send_stream_stream: stream stream data socket");
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_stream_stream: send_socket obtained...\n");
+  }
+  
+  /* 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++;
+  }
+  
+  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_STREAM_STREAM;
+  stream_stream_request->send_buf_size	=	rss_size;
+  stream_stream_request->recv_buf_size	=	rsr_size;
+  stream_stream_request->receive_size	=	recv_size;
+  stream_stream_request->recv_alignment	=	remote_recv_align;
+  stream_stream_request->recv_offset	=	remote_recv_offset;
+  stream_stream_request->measure_cpu	=	remote_cpu_usage;
+  stream_stream_request->cpu_rate	=	remote_cpu_rate;
+  if (test_time) {
+    stream_stream_request->test_length	=	test_time;
+  }
+  else {
+    stream_stream_request->test_length	=	test_bytes;
+  }
+#ifdef DIRTY
+  stream_stream_request->dirty_count    =       rem_dirty_count;
+  stream_stream_request->clean_count    =       rem_clean_count;
+#endif /* DIRTY */
+  
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "netperf: send_stream_stream: requesting STREAM 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 STREAM tests.					*/
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"remote listen done.\n");
+    rsr_size	        =	stream_stream_response->recv_buf_size;
+    rss_size	        =	stream_stream_response->send_buf_size;
+    remote_cpu_usage    =	stream_stream_response->measure_cpu;
+    remote_cpu_rate     = 	stream_stream_response->cpu_rate;
+    strcpy(server.sun_path,stream_stream_response->unix_path);
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: send_stream_stream: remote error");
+    exit(1);
+  }
+  
+  /*Connect up to the remote port on the data socket  */
+  if (connect(send_socket, 
+	      (struct sockaddr *)&server,
+	      sizeof(server)) == INVALID_SOCKET){
+    perror("netperf: send_stream_stream: data socket connect failed");
+    printf(" path: %s\n",server.sun_path);
+    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;
+    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);
+  
+  /* 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. */
+  
+#ifdef DIRTY
+  /* initialize the random number generator for putting dirty stuff */
+  /* into the send buffer. raj */
+  srand((int) getpid());
+#endif
+  
+  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. */
+    message_int_ptr = (int *)(send_ring->buffer_ptr);
+    for (i = 0; i < loc_dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < loc_clean_count; i++) {
+      loc_dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+    
+    if((len=send(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;
+      }
+      perror("netperf: data send error");
+      printf("len was %d\n",len);
+      exit(1);
+    }
+#ifdef WANT_INTERVALS
+    for (interval_count = 0;
+	 interval_count < interval_wate;
+	 interval_count++);
+#endif
+    
+    /* 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. */ 
+  
+  if (close(send_socket) == -1) {
+    perror("netperf: send_stream_stream: cannot close socket");
+    exit(1);
+  }
+  
+  /* 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 STREAM 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	= ((double) send_size * (double) nummessages) + len;
+  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) {
+      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);
+      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) {
+      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	= stream_stream_result->cpu_util;
+      remote_service_demand	= calc_service_demand(bytes_sent,
+						      0.0,
+						      remote_cpu_utilization,
+						      stream_stream_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:
+    case 2:
+      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:
+      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 */
+    /* STREAM statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+    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)stream_stream_result->recv_calls,
+	    stream_stream_result->recv_calls);
+  }
+  
+}
+
+
+/* This is the server-side routine for the stream stream test. It is */
+/* implemented as one routine. I could break things-out somewhat, but */
+/* didn't feel it was necessary. */
+
+void
+recv_stream_stream()
+{
+  
+  struct sockaddr_un myaddr_un, peeraddr_un;
+  SOCKET s_listen,s_data;
+  int 	addrlen;
+  int	len;
+  int	receive_calls = 0;
+  float	elapsed_time;
+  int   bytes_received;
+  
+  struct ring_elt *recv_ring;
+
+#ifdef DIRTY
+  char	*message_ptr;
+  int   *message_int_ptr;
+  int   dirty_count;
+  int   clean_count;
+  int   i;
+#endif
+  
+  struct	stream_stream_request_struct	*stream_stream_request;
+  struct	stream_stream_response_struct	*stream_stream_response;
+  struct	stream_stream_results_struct	*stream_stream_results;
+  
+  stream_stream_request	= 
+    (struct stream_stream_request_struct *)netperf_request.content.test_specific_data;
+  stream_stream_response	= 
+    (struct stream_stream_response_struct *)netperf_response.content.test_specific_data;
+  stream_stream_results	= 
+    (struct stream_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_stream_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_stream_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = STREAM_STREAM_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_stream_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_stream_stream: requested alignment of %d\n",
+	    stream_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_un,
+	sizeof(myaddr_un));
+  myaddr_un.sun_family      = AF_UNIX;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_stream_stream: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+  /* create_unix_socket 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_req = stream_stream_request->send_buf_size;
+  lsr_size_req = stream_stream_request->recv_buf_size;
+
+  s_listen = create_unix_socket(AF_UNIX,
+				SOCK_STREAM);
+  
+  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. */
+  
+  strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
+  if (debug) {
+    fprintf(where,"selected a path of %s\n",myaddr_un.sun_path);
+    fflush(where);
+  }
+  if (bind(s_listen,
+	   (struct sockaddr *)&myaddr_un,
+	   sizeof(myaddr_un)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    fprintf(where,"could not bind to path\n");
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+  
+  chmod(myaddr_un.sun_path, 0666);
+
+  /* what sort of sizes did we end-up with? */
+  if (stream_stream_request->receive_size == 0) {
+    if (lsr_size > 0) {
+      recv_size = lsr_size;
+    }
+    else {
+      recv_size = 4096;
+    }
+  }
+  else {
+    recv_size = stream_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,
+				   stream_stream_request->recv_alignment,
+				   stream_stream_request->recv_offset);
+
+  if (debug) {
+    fprintf(where,"recv_stream_stream: receive alignment and offset set...\n");
+    fflush(where);
+  }
+  
+  /* 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();
+    
+    exit(1);
+  }
+  
+  /* now get the port number assigned by the system  */
+  addrlen = sizeof(myaddr_un);
+  if (getsockname(s_listen, 
+		  (struct sockaddr *)&myaddr_un,
+		  &addrlen) == SOCKET_ERROR){
+    netperf_response.content.serv_errno = errno;
+    close(s_listen);
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* Now myaddr_un contains the path */
+  /* returned to the sender also implicitly telling the sender that the */
+  /* socket buffer sizing has been done. */
+  strcpy(stream_stream_response->unix_path,myaddr_un.sun_path);
+  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. */
+  
+  stream_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (stream_stream_request->measure_cpu) {
+    stream_stream_response->measure_cpu = 1;
+    stream_stream_response->cpu_rate = 
+      calibrate_local_cpu(stream_stream_request->cpu_rate);
+  }
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  stream_stream_response->send_buf_size = lss_size;
+  stream_stream_response->recv_buf_size = lsr_size;
+  stream_stream_response->receive_size = recv_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_un);
+  
+  if ((s_data=accept(s_listen,
+		     (struct sockaddr *)&peeraddr_un,
+		     &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    exit(1);
+  }
+  
+  /* Now it's time to start receiving data on the connection. We will */
+  /* first grab the apropriate counters and then start grabbing. */
+  
+  cpu_start(stream_stream_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+#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. */
+
+  dirty_count = stream_stream_request->dirty_count;
+  clean_count = stream_stream_request->clean_count;
+  message_int_ptr = (int *)recv_ring->buffer_ptr;
+  for (i = 0; i < dirty_count; i++) {
+    *message_int_ptr = rand();
+    message_int_ptr++;
+  }
+  for (i = 0; i < clean_count; i++) {
+    dirty_count = *message_int_ptr;
+    message_int_ptr++;
+  }
+#endif /* DIRTY */
+  bytes_received = 0;
+
+  while ((len = recv(s_data, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
+    if (len == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+    bytes_received += len;
+    receive_calls++;
+
+    /* more to the next buffer in the recv_ring */
+    recv_ring = recv_ring->next;
+
+#ifdef DIRTY
+    message_int_ptr = (int *)(recv_ring->buffer_ptr);
+    for (i = 0; i < dirty_count; i++) {
+      *message_int_ptr = rand();
+      message_int_ptr++;
+    }
+    for (i = 0; i < clean_count; i++) {
+      dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+  }
+  
+  /* The loop now exits due to zero bytes received. we will have */
+  /* counted one too many messages received, so decrement the */
+  /* receive_calls counter by one. raj 7/94 */
+  receive_calls--;
+  
+  /* perform a shutdown to signal the sender that */
+  /* we have received all the data sent. raj 4/93 */
+
+  if (shutdown(s_data,1) == SOCKET_ERROR) {
+      netperf_response.content.serv_errno = errno;
+      send_response();
+      exit(1);
+    }
+  
+  cpu_stop(stream_stream_request->measure_cpu,&elapsed_time);
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_stream_stream: got %d bytes\n",
+	    bytes_received);
+    fprintf(where,
+	    "recv_stream_stream: got %d recvs\n",
+	    receive_calls);
+    fflush(where);
+  }
+  
+  stream_stream_results->bytes_received	= bytes_received;
+  stream_stream_results->elapsed_time	= elapsed_time;
+  stream_stream_results->recv_calls	= receive_calls;
+  
+  if (stream_stream_request->measure_cpu) {
+    stream_stream_results->cpu_util	= calc_cpu_util(0.0);
+  };
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_stream_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  unlink(myaddr_un.sun_path);
+}
+
+
+ /* this routine implements the sending (netperf) side of the STREAM_RR */
+ /* test. */
+
+void
+send_stream_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			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	sockaddr_un	server;
+  
+  struct	stream_rr_request_struct	*stream_rr_request;
+  struct	stream_rr_response_struct	*stream_rr_response;
+  struct	stream_rr_results_struct	*stream_rr_result;
+  
+  stream_rr_request = 
+    (struct stream_rr_request_struct *)netperf_request.content.test_specific_data;
+  stream_rr_response=
+    (struct stream_rr_response_struct *)netperf_response.content.test_specific_data;
+  stream_rr_result	=
+    (struct stream_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. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  
+  server.sun_family = AF_UNIX;
+  
+  
+  if ( print_headers ) {
+    fprintf(where,"STREAM 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. */
+  /* 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;
+  
+  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);
+				   
+  /*set up the data socket                        */
+  send_socket = create_unix_socket(AF_UNIX, 
+				   SOCK_STREAM);
+  
+  if (send_socket == INVALID_SOCKET){
+    perror("netperf: send_stream_rr: stream stream data socket");
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_stream_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_STREAM_RR;
+  stream_rr_request->recv_buf_size	=	rsr_size;
+  stream_rr_request->send_buf_size	=	rss_size;
+  stream_rr_request->recv_alignment=	remote_recv_align;
+  stream_rr_request->recv_offset	=	remote_recv_offset;
+  stream_rr_request->send_alignment=	remote_send_align;
+  stream_rr_request->send_offset	=	remote_send_offset;
+  stream_rr_request->request_size	=	req_size;
+  stream_rr_request->response_size	=	rsp_size;
+  stream_rr_request->measure_cpu	=	remote_cpu_usage;
+  stream_rr_request->cpu_rate	=	remote_cpu_rate;
+  if (test_time) {
+    stream_rr_request->test_length	=	test_time;
+  }
+  else {
+    stream_rr_request->test_length	=	test_trans * -1;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"netperf: send_stream_rr: requesting STREAM 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 STREAM tests.					*/
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"remote listen done.\n");
+    rsr_size	=	stream_rr_response->recv_buf_size;
+    rss_size	=	stream_rr_response->send_buf_size;
+    remote_cpu_usage=	stream_rr_response->measure_cpu;
+    remote_cpu_rate = 	stream_rr_response->cpu_rate;
+    /* make sure that port numbers are in network order */
+    strcpy(server.sun_path,stream_rr_response->unix_path);
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    
+    exit(1);
+  }
+  
+  /*Connect up to the remote port on the data socket  */
+  if (connect(send_socket, 
+	      (struct sockaddr *)&server,
+	      sizeof(server)) == INVALID_SOCKET){
+    perror("netperf: data socket connect failed");
+    
+    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);
+  
+  /* 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. */
+    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_stream_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_stream_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;
+    }
+    
+    nummessages++;          
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug > 3) {
+      fprintf(where,
+	      "Transaction %d completed\n",
+	      nummessages);
+      fflush(where);
+    }
+  }
+  
+  /* At this point we used to call shutdown on the data socket to be */
+  /* sure all the data was delivered, but this was not germane in a */
+  /* request/response test, and it was causing the tests to "hang" when */
+  /* they were being controlled by time. So, I have replaced this */
+  /* shutdown call with a call to close that can be found later in the */
+  /* procedure. */
+  
+  /* 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 STREAM 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 STREAM 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 = stream_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,
+						  stream_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 */
+    /* STREAM statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+    fprintf(where,
+	    ksink_fmt);
+  }
+  /* The test is over. Kill the data socket */
+  
+  if (close(send_socket) == -1) {
+    perror("send_stream_rr: cannot shutdown stream stream socket");
+  }
+  
+}
+
+void
+send_dg_stream(char remote_host[])
+{
+  /************************************************************************/
+  /*									*/
+  /*               	DG 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 =
+    "%5d   %5d    %-7.2f   %7d %6d    %7.2f\n\
+%5d            %-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   %%       us/KB\n\n";
+  
+  char *cpu_fmt_0 =
+    "%6.2f\n";
+  
+  char *cpu_fmt_1 =
+    "%5d   %5d    %-7.2f   %7d %6d    %7.1f      %-6.2f  %-6.3f\n\
+%5d            %-7.2f   %7d           %7.1f      %-6.2f  %-6.3f\n\n";
+  
+  int	messages_recvd;
+  float	elapsed_time, 
+  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;
+  struct ring_elt *send_ring;
+  int	failed_sends;
+  int	failed_cows;
+  int 	messages_sent;
+  SOCKET data_socket;
+  
+  
+#ifdef WANT_INTERVALS
+  int	interval_count;
+#endif /* WANT_INTERVALS */
+#ifdef DIRTY
+  int	*message_int_ptr;
+  int	i;
+#endif /* DIRTY */
+  
+  struct	sockaddr_un	server;
+  
+  struct	dg_stream_request_struct	*dg_stream_request;
+  struct	dg_stream_response_struct	*dg_stream_response;
+  struct	dg_stream_results_struct	*dg_stream_results;
+  
+  dg_stream_request	= (struct dg_stream_request_struct *)netperf_request.content.test_specific_data;
+  dg_stream_response	= (struct dg_stream_response_struct *)netperf_response.content.test_specific_data;
+  dg_stream_results	= (struct dg_stream_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. */
+  
+  bzero((char *)&server,
+	sizeof(server));
+  
+  server.sun_family = AF_UNIX;
+  
+  if ( print_headers ) {
+    printf("DG UNIDIRECTIONAL SEND TEST\n");
+    if (local_cpu_usage || remote_cpu_usage)
+      printf(cpu_title,format_units());
+    else
+      printf(tput_title,format_units());
+  }	
+  
+  failed_sends	= 0;
+  failed_cows	= 0;
+  messages_sent	= 0;
+  times_up	= 0;
+  
+  /*set up the data socket			*/
+  data_socket = create_unix_socket(AF_UNIX,
+				   SOCK_DGRAM);
+  
+  if (data_socket == INVALID_SOCKET){
+    perror("dg_send: data socket");
+    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 < UNIX_LENGTH_MAX ? lss_size : UNIX_LENGTH_MAX);
+    }
+    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;
+
+  send_ring = allocate_buffer_ring(send_width,
+				   send_size,
+				   local_send_align,
+				   local_send_offset);
+
+  /* At this point, we want to do things like disable DG checksumming */
+  /* and measure the cpu rate and all that so we are ready to go */
+  /* immediately after the test response message is delivered. */
+  
+  /* 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_DG_STREAM;
+  dg_stream_request->recv_buf_size	= rsr_size;
+  dg_stream_request->message_size	= send_size;
+  dg_stream_request->recv_alignment	= remote_recv_align;
+  dg_stream_request->recv_offset	= remote_recv_offset;
+  dg_stream_request->measure_cpu	= remote_cpu_usage;
+  dg_stream_request->cpu_rate		= remote_cpu_rate;
+  dg_stream_request->test_length	= test_time;
+  
+  send_request();
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"send_dg_stream: remote data connection done.\n");
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("send_dg_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 */
+  strcpy(server.sun_path,dg_stream_response->unix_path);
+  rsr_size	= dg_stream_response->recv_buf_size;
+  rss_size	= dg_stream_response->send_buf_size;
+  remote_cpu_rate	= dg_stream_response->cpu_rate;
+  
+  /* We "connect" up to the remote post to allow is to use the send */
+  /* call instead of the sendto call. Presumeably, this is a little */
+  /* simpler, and a little more efficient. I think that it also means */
+  /* that we can be informed of certain things, but am not sure yet... */
+  
+  if (connect(data_socket,
+	      (struct sockaddr *)&server,
+	      sizeof(server)) == INVALID_SOCKET){
+    perror("send_dg_stream: data socket connect failed");
+    exit(1);
+  }
+  
+  /* set up the timer to call us after test_time	*/
+  start_timer(test_time);
+  
+  /* Get the start count for the idle counter and the start time */
+  
+  cpu_start(local_cpu_usage);
+  
+#ifdef WANT_INTERVALS
+  interval_count = interval_burst;
+#endif
+  
+  /* 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. */
+    message_int_ptr = (int *)(send_ring->buffer_ptr);
+    for (i = 0; i < loc_dirty_count; i++) {
+      *message_int_ptr = 4;
+      message_int_ptr++;
+    }
+    for (i = 0; i < loc_clean_count; i++) {
+      loc_dirty_count = *message_int_ptr;
+      message_int_ptr++;
+    }
+#endif /* DIRTY */
+
+    if ((len=send(data_socket,
+		  send_ring->buffer_ptr,
+		  send_size,
+		  0))  != send_size) {
+      if ((len >= 0) || (errno == EINTR))
+	break;
+      if (errno == ENOBUFS) {
+	failed_sends++;
+	continue;
+      }
+      perror("dg_send: data send error");
+      exit(1);
+    }
+    messages_sent++;          
+    
+    /* now we want to move our pointer to the next position in the */
+    /* data buffer... */
+
+    send_ring = send_ring->next;
+    
+    
+#ifdef WANT_INTERVALS
+    /* 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 the sleep routine for some milliseconds, if our */
+      /* timer popped while we were in there, we want to */
+      /* break out of the loop. */
+      if (msec_sleep(interval_wate)) {
+	break;
+      }
+      interval_count = interval_burst;
+    }
+    
+#endif
+    
+  }
+  
+  /* 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_dg_stream: remote results obtained\n");
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("send_dg_stream: error on remote");
+    exit(1);
+  }
+  
+  bytes_sent	= send_size * messages_sent;
+  local_thruput	= calc_thruput(bytes_sent);
+  
+  messages_recvd	= dg_stream_results->messages_recvd;
+  bytes_recvd	= send_size * 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) {
+      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);
+      local_service_demand	= calc_service_demand(bytes_sent,
+						      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) {
+      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	= dg_stream_results->cpu_util;
+      remote_service_demand	= calc_service_demand(bytes_recvd,
+						      0.0,
+						      remote_cpu_utilization,
+						      dg_stream_results->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,		/* 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:
+      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;
+    }
+  }
+}
+
+
+ /* this routine implements the receive side (netserver) of the */
+ /* DG_STREAM performance test. */
+
+void
+recv_dg_stream()
+{
+  struct ring_elt *recv_ring;
+
+  struct sockaddr_un myaddr_un;
+  SOCKET s_data;
+  int	len = 0;
+  int	bytes_received = 0;
+  float	elapsed_time;
+  
+  int	message_size;
+  int	messages_recvd = 0;
+  
+  struct	dg_stream_request_struct	*dg_stream_request;
+  struct	dg_stream_response_struct	*dg_stream_response;
+  struct	dg_stream_results_struct	*dg_stream_results;
+  
+  dg_stream_request  = 
+    (struct dg_stream_request_struct *)netperf_request.content.test_specific_data;
+  dg_stream_response = 
+    (struct dg_stream_response_struct *)netperf_response.content.test_specific_data;
+  dg_stream_results  = 
+    (struct dg_stream_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dg_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_dg_stream: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = DG_STREAM_RESPONSE;
+  
+  if (debug > 2) {
+    fprintf(where,"recv_dg_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_dg_stream: requested alignment of %d\n",
+	    dg_stream_request->recv_alignment);
+    fflush(where);
+  }
+
+  if (recv_width == 0) recv_width = 1;
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   dg_stream_request->message_size,
+				   dg_stream_request->recv_alignment,
+				   dg_stream_request->recv_offset);
+
+  if (debug > 1) {
+    fprintf(where,"recv_dg_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_un,
+	sizeof(myaddr_un));
+  myaddr_un.sun_family      = AF_UNIX;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug > 1) {
+    fprintf(where,"recv_dg_stream: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_unix_socket 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 = dg_stream_request->recv_buf_size;
+    
+  s_data = create_unix_socket(AF_UNIX,
+			      SOCK_DGRAM);
+  
+  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. */
+  
+  strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
+  if (bind(s_data,
+	   (struct sockaddr *)&myaddr_un,
+	   sizeof(myaddr_un)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    send_response();
+    exit(1);
+  }
+
+  chmod(myaddr_un.sun_path, 0666);
+
+  dg_stream_response->test_length = dg_stream_request->test_length;
+  
+  /* Now myaddr_un 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. */
+  
+  strcpy(dg_stream_response->unix_path,myaddr_un.sun_path);
+  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. */
+  
+  dg_stream_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dg_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... */
+    dg_stream_response->measure_cpu = 1;
+    dg_stream_response->cpu_rate = 
+      calibrate_local_cpu(dg_stream_request->cpu_rate);
+  }
+  
+  message_size	= dg_stream_request->message_size;
+  test_time	= dg_stream_request->test_length;
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  dg_stream_response->send_buf_size = lss_size;
+  dg_stream_response->recv_buf_size = lsr_size;
+
+  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(dg_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_dg_stream: about to enter inner sanctum.\n");
+    fflush(where);
+  }
+  
+  while (!times_up) {
+    if ((len = recv(s_data, 
+		    recv_ring->buffer_ptr,
+		    message_size, 
+		    0)) != message_size) {
+      if ((len == SOCKET_ERROR) && (errno != EINTR)) {
+	netperf_response.content.serv_errno = errno;
+	send_response();
+	exit(1);
+      }
+      break;
+    }
+    messages_recvd++;
+    recv_ring = recv_ring->next;
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_dg_stream: got %d messages.\n",messages_recvd);
+    fflush(where);
+  }
+  
+  
+  /* The loop now exits due timer or < send_size bytes received. */
+  
+  cpu_stop(dg_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_dg_stream: test ended in %f seconds.\n",elapsed_time);
+    fflush(where);
+  }
+  
+  
+  /* We will count the "off" message that got us out of the loop */
+  bytes_received = (messages_recvd * message_size) + len;
+  
+  /* send the results to the sender			*/
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dg_stream: got %d bytes\n",
+	    bytes_received);
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type		= DG_STREAM_RESULTS;
+  dg_stream_results->bytes_received	= bytes_received;
+  dg_stream_results->messages_recvd	= messages_recvd;
+  dg_stream_results->elapsed_time	= elapsed_time;
+  if (dg_stream_request->measure_cpu) {
+    dg_stream_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  else {
+    dg_stream_results->cpu_util	= -1.0;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,
+	    "recv_dg_stream: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  
+}
+
+void
+send_dg_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";
+  
+  float			elapsed_time;
+  
+  /* we add MAXALIGNMENT and MAXOFFSET to insure that there is enough */
+  /* space for a maximally aligned, maximally sized message. At some */
+  /* point, we may want to actually make this even larger and cycle */
+  /* through the thing one piece at a time.*/
+  
+  int	len;
+  char	*send_message_ptr;
+  char	*recv_message_ptr;
+  char	*temp_message_ptr;
+  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;
+  
+#ifdef WANT_INTERVALS
+  /* timing stuff */
+#define	MAX_KEPT_TIMES	1024
+  int	time_index = 0;
+  int	unused_buckets;
+  int	kept_times[MAX_KEPT_TIMES];
+  int	sleep_usecs;
+  unsigned	int	total_times=0;
+  struct	timezone	dummy_zone;
+  struct	timeval		send_time;
+  struct	timeval		recv_time;
+  struct	timeval		sleep_timeval;
+#endif
+  
+  struct	sockaddr_un	server, myaddr_un;
+  
+  struct	dg_rr_request_struct	*dg_rr_request;
+  struct	dg_rr_response_struct	*dg_rr_response;
+  struct	dg_rr_results_struct	*dg_rr_result;
+  
+  dg_rr_request	= 
+    (struct dg_rr_request_struct *)netperf_request.content.test_specific_data;
+  dg_rr_response=
+    (struct dg_rr_response_struct *)netperf_response.content.test_specific_data;
+  dg_rr_result	=
+    (struct dg_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  /* we want to zero out the times, so we can detect unused entries. */
+#ifdef WANT_INTERVALS
+  time_index = 0;
+  while (time_index < MAX_KEPT_TIMES) {
+    kept_times[time_index] = 0;
+    time_index += 1;
+  }
+  time_index = 0;
+#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));
+  server.sun_family = AF_UNIX;
+
+  bzero((char *)&myaddr_un,
+	sizeof(myaddr_un));
+  myaddr_un.sun_family = AF_UNIX;
+
+  strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
+  
+  if ( print_headers ) {
+    fprintf(where,"DG 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;
+  times_up 	= 	0;
+  
+  /* set-up the data buffer with the requested alignment and offset */
+  temp_message_ptr = (char *)malloc(DATABUFFERLEN);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", DATABUFFERLEN);
+    exit(1);
+  }
+  send_message_ptr = (char *)(( (long)temp_message_ptr + 
+			(long) local_send_align - 1) &	
+			~((long) local_send_align - 1));
+  send_message_ptr = send_message_ptr + local_send_offset;
+  temp_message_ptr = (char *)malloc(DATABUFFERLEN);
+  if (temp_message_ptr == NULL) {
+    printf("malloc(%d) failed!\n", DATABUFFERLEN);
+    exit(1);
+  }
+  recv_message_ptr = (char *)(( (long)temp_message_ptr + 
+			(long) local_recv_align - 1) &	
+			~((long) local_recv_align - 1));
+  recv_message_ptr = recv_message_ptr + local_recv_offset;
+  
+  /*set up the data socket                        */
+  send_socket = create_unix_socket(AF_UNIX, 
+				   SOCK_DGRAM);
+  
+  if (send_socket == INVALID_SOCKET){
+    perror("netperf: send_dg_rr: dg rr data socket");
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"send_dg_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 */
+  /* 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_DG_RR;
+  dg_rr_request->recv_buf_size	=	rsr_size;
+  dg_rr_request->send_buf_size	=	rss_size;
+  dg_rr_request->recv_alignment	=	remote_recv_align;
+  dg_rr_request->recv_offset	=	remote_recv_offset;
+  dg_rr_request->send_alignment	=	remote_send_align;
+  dg_rr_request->send_offset	=	remote_send_offset;
+  dg_rr_request->request_size	=	req_size;
+  dg_rr_request->response_size	=	rsp_size;
+  dg_rr_request->measure_cpu	=	remote_cpu_usage;
+  dg_rr_request->cpu_rate	=	remote_cpu_rate;
+  if (test_time) {
+    dg_rr_request->test_length	=	test_time;
+  }
+  else {
+    dg_rr_request->test_length	=	test_trans * -1;
+  }
+  
+  if (debug > 1) {
+    fprintf(where,"netperf: send_dg_rr: requesting DG request/response 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 DG tests.					*/
+  
+  recv_response();
+  
+  if (!netperf_response.content.serv_errno) {
+    if (debug)
+      fprintf(where,"remote listen done.\n");
+    rsr_size	=	dg_rr_response->recv_buf_size;
+    rss_size	=	dg_rr_response->send_buf_size;
+    remote_cpu_usage=	dg_rr_response->measure_cpu;
+    remote_cpu_rate = 	dg_rr_response->cpu_rate;
+    /* port numbers in proper order */
+    strcpy(server.sun_path,dg_rr_response->unix_path);
+  }
+  else {
+    Set_errno(netperf_response.content.serv_errno);
+    perror("netperf: remote error");
+    
+    exit(1);
+  }
+  
+  /* Connect up to the remote port on the data socket. This will set */
+  /* the default destination address on this socket. we need to bind */
+  /* out socket so that the remote gets something from a recvfrom  */
+  if (bind(send_socket,
+	   (struct sockaddr *)&myaddr_un,
+	   sizeof(myaddr_un)) == SOCKET_ERROR) {
+    perror("netperf: send_dg_rr");
+    unlink(myaddr_un.sun_path);
+    close(send_socket);
+    exit(1);
+  }
+  
+  if (connect(send_socket, 
+	      (struct sockaddr *)&server,
+	      sizeof(server)) == INVALID_SOCKET ) {
+    perror("netperf: data socket connect failed");
+    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);
+  
+  /* 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_INTERVALS
+    gettimeofday(&send_time,&dummy_zone);
+#endif
+    if((len=send(send_socket,
+		 send_message_ptr,
+		 req_size,
+		 0)) != req_size) {
+      if (errno == EINTR) {
+	/* We likely hit */
+	/* test-end time. */
+	break;
+      }
+      perror("send_dg_rr: data send error");
+      exit(1);
+    }
+    
+    /* receive the response. with DG we will get it all, or nothing */
+    
+    if((rsp_bytes_recvd=recv(send_socket,
+			     recv_message_ptr,
+			     rsp_size,
+			     0)) != rsp_size) {
+      if (errno == EINTR) {
+	/* Again, we have likely hit test-end time */
+	break;
+      }
+      perror("send_dg_rr: data recv error");
+      exit(1);
+    }
+#ifdef WANT_INTERVALS
+    gettimeofday(&recv_time,&dummy_zone);
+    
+    /* now we do some arithmatic on the two timevals */
+    if (recv_time.tv_usec < send_time.tv_usec) {
+      /* we wrapped around a second */
+      recv_time.tv_usec += 1000000;
+      recv_time.tv_sec  -= 1;
+    }
+    
+    /* and store it away */
+    kept_times[time_index] = (recv_time.tv_sec - send_time.tv_sec) * 1000000;
+    kept_times[time_index] += (recv_time.tv_usec - send_time.tv_usec);
+    
+    /* 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.  */
+    if (interval_usecs > 0) {
+      sleep_usecs = interval_usecs - kept_times[time_index];
+      if (sleep_usecs > 1000) {
+	/* we sleep */
+	sleep_timeval.tv_sec = sleep_usecs / 1000000;
+	sleep_timeval.tv_usec = sleep_usecs % 1000000;
+	select(0,
+	       0,
+	       0,
+	       0,
+	       &sleep_timeval);
+      }
+    }
+    
+    /* now up the time index */
+    time_index = (time_index +1)%MAX_KEPT_TIMES;
+#endif
+    nummessages++;          
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug > 3) {
+      fprintf(where,"Transaction %d completed\n",nummessages);
+      fflush(where);
+    }
+    
+  }
+  
+  /* 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. Of course, since this was a request/response test, there */
+  /* should be no data outstanding on the socket ;-) */ 
+  
+  if (shutdown(send_socket,1) == SOCKET_ERROR) {
+    perror("netperf: cannot shutdown dg stream socket");
+    
+    exit(1);
+  }
+  
+  /* 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 DG 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 */
+  
+  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 = dg_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,
+						   dg_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:
+    case 2:
+      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:
+      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 */
+    /* DG statistics, the alignments of the sends and receives */
+    /* and all that sort of rot... */
+    
+#ifdef WANT_INTERVALS
+    kept_times[MAX_KEPT_TIMES] = 0;
+    time_index = 0;
+    while (time_index < MAX_KEPT_TIMES) {
+      if (kept_times[time_index] > 0) {
+	total_times += kept_times[time_index];
+      }
+      else
+	unused_buckets++;
+      time_index += 1;
+    }
+    total_times /= (MAX_KEPT_TIMES-unused_buckets);
+    fprintf(where,
+	    "Average response time %d usecs\n",
+	    total_times);
+#endif
+  }
+  unlink(myaddr_un.sun_path);
+}
+
+ /* this routine implements the receive side (netserver) of a DG_RR */
+ /* test. */
+void
+recv_dg_rr()
+{
+  
+  struct ring_elt *recv_ring;
+  struct ring_elt *send_ring;
+
+  struct	sockaddr_un        myaddr_un,
+  peeraddr_un;
+  SOCKET s_data;
+  int 	addrlen;
+  int	trans_received = 0;
+  int	trans_remaining;
+  float	elapsed_time;
+  
+  struct	dg_rr_request_struct	*dg_rr_request;
+  struct	dg_rr_response_struct	*dg_rr_response;
+  struct	dg_rr_results_struct	*dg_rr_results;
+  
+  dg_rr_request  = 
+    (struct dg_rr_request_struct *)netperf_request.content.test_specific_data;
+  dg_rr_response = 
+    (struct dg_rr_response_struct *)netperf_response.content.test_specific_data;
+  dg_rr_results  = 
+    (struct dg_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_dg_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_dg_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = DG_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_dg_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_dg_rr: requested recv alignment of %d offset %d\n",
+	    dg_rr_request->recv_alignment,
+	    dg_rr_request->recv_offset);
+    fprintf(where,"recv_dg_rr: requested send alignment of %d offset %d\n",
+	    dg_rr_request->send_alignment,
+	    dg_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,
+				   dg_rr_request->request_size,
+				   dg_rr_request->recv_alignment,
+				   dg_rr_request->recv_offset);
+
+  send_ring = allocate_buffer_ring(send_width,
+				   dg_rr_request->response_size,
+				   dg_rr_request->send_alignment,
+				   dg_rr_request->send_offset);
+
+  if (debug) {
+    fprintf(where,"recv_dg_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_un,
+	sizeof(myaddr_un));
+  myaddr_un.sun_family      = AF_UNIX;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_dg_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+  
+
+  /* create_unix_socket 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_req = dg_rr_request->send_buf_size;
+  lsr_size_req = dg_rr_request->recv_buf_size;
+
+  s_data = create_unix_socket(AF_UNIX,
+			      SOCK_DGRAM);
+  
+  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. */
+  
+  strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
+  if (bind(s_data,
+	   (struct sockaddr *)&myaddr_un,
+	   sizeof(myaddr_un)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    unlink(myaddr_un.sun_path);
+    close(s_data);
+    send_response();
+    
+    exit(1);
+  }
+  
+  /* Now myaddr_un 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. */
+  
+  strcpy(dg_rr_response->unix_path,myaddr_un.sun_path);
+  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. */
+  
+  dg_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (dg_rr_request->measure_cpu) {
+    dg_rr_response->measure_cpu = 1;
+    dg_rr_response->cpu_rate = calibrate_local_cpu(dg_rr_request->cpu_rate);
+  }
+   
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  dg_rr_response->send_buf_size = lss_size;
+  dg_rr_response->recv_buf_size = lsr_size;
+ 
+  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(dg_rr_request->measure_cpu);
+  
+  if (dg_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(dg_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = dg_rr_request->test_length * -1;
+  }
+  
+  addrlen = sizeof(peeraddr_un);
+  bzero((char *)&peeraddr_un, addrlen);
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    
+    /* receive the request from the other side */
+    fprintf(where,"socket %d ptr %p size %d\n",
+	    s_data,
+	    recv_ring->buffer_ptr,
+	    dg_rr_request->request_size);
+    fflush(where);
+    if (recvfrom(s_data,
+		 recv_ring->buffer_ptr,
+		 dg_rr_request->request_size,
+		 0,
+		 (struct sockaddr *)&peeraddr_un,
+		 &addrlen) != dg_rr_request->request_size) {
+      if (errno == EINTR) {
+	/* we must have hit the end of test time. */
+	break;
+      }
+      netperf_response.content.serv_errno = errno;
+      fprintf(where,"error on recvfrom errno %d\n",errno);
+      fflush(where);
+      send_response();
+      unlink(myaddr_un.sun_path);
+      exit(1);
+    }
+    recv_ring = recv_ring->next;
+
+    /* Now, send the response to the remote */
+    if (sendto(s_data,
+	       send_ring->buffer_ptr,
+	       dg_rr_request->response_size,
+	       0,
+	       (struct sockaddr *)&peeraddr_un,
+	       addrlen) != dg_rr_request->response_size) {
+      if (errno == EINTR) {
+	/* we have hit end of test time. */
+	break;
+      }
+      netperf_response.content.serv_errno = errno;
+      fprintf(where,"error on recvfrom errno %d\n",errno);
+      fflush(where);
+      unlink(myaddr_un.sun_path);
+      send_response();
+      exit(1);
+    }
+    send_ring = send_ring->next;
+    
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_dg_rr: Transaction %d complete.\n",
+	      trans_received);
+      fflush(where);
+    }
+    
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(dg_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_dg_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  dg_rr_results->bytes_received	= (trans_received * 
+					   (dg_rr_request->request_size + 
+					    dg_rr_request->response_size));
+  dg_rr_results->trans_received	= trans_received;
+  dg_rr_results->elapsed_time	= elapsed_time;
+  if (dg_rr_request->measure_cpu) {
+    dg_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_dg_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  unlink(myaddr_un.sun_path);
+  
+}
+ /* this routine implements the receive (netserver) side of a STREAM_RR */
+ /* test */
+
+void
+recv_stream_rr()
+{
+  
+  struct ring_elt *send_ring;
+  struct ring_elt *recv_ring;
+
+  struct	sockaddr_un        myaddr_un,
+  peeraddr_un;
+  SOCKET s_listen,s_data;
+  int 	addrlen;
+  char	*temp_message_ptr;
+  int	trans_received = 0;
+  int	trans_remaining;
+  int	bytes_sent;
+  int	request_bytes_recvd;
+  int	request_bytes_remaining;
+  int	timed_out = 0;
+  float	elapsed_time;
+  
+  struct	stream_rr_request_struct	*stream_rr_request;
+  struct	stream_rr_response_struct	*stream_rr_response;
+  struct	stream_rr_results_struct	*stream_rr_results;
+  
+  stream_rr_request = 
+    (struct stream_rr_request_struct *)netperf_request.content.test_specific_data;
+  stream_rr_response =
+    (struct stream_rr_response_struct *)netperf_response.content.test_specific_data;
+  stream_rr_results =
+    (struct stream_rr_results_struct *)netperf_response.content.test_specific_data;
+  
+  if (debug) {
+    fprintf(where,"netserver: recv_stream_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_stream_rr: setting the response type...\n");
+    fflush(where);
+  }
+  
+  netperf_response.content.response_type = STREAM_RR_RESPONSE;
+  
+  if (debug) {
+    fprintf(where,"recv_stream_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_stream_rr: requested recv alignment of %d offset %d\n",
+	    stream_rr_request->recv_alignment,
+	    stream_rr_request->recv_offset);
+    fprintf(where,"recv_stream_rr: requested send alignment of %d offset %d\n",
+	    stream_rr_request->send_alignment,
+	    stream_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,
+				   stream_rr_request->response_size,
+				   stream_rr_request->send_alignment,
+				   stream_rr_request->send_offset);
+
+  recv_ring = allocate_buffer_ring(recv_width,
+				   stream_rr_request->request_size,
+				   stream_rr_request->recv_alignment,
+				   stream_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_un,
+	sizeof(myaddr_un));
+  myaddr_un.sun_family      = AF_UNIX;
+  
+  /* Grab a socket to listen on, and then listen on it. */
+  
+  if (debug) {
+    fprintf(where,"recv_stream_rr: grabbing a socket...\n");
+    fflush(where);
+  }
+
+  /* create_unix_socket 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_req = stream_rr_request->send_buf_size;
+  lsr_size_req = stream_rr_request->recv_buf_size;
+  
+  s_listen = create_unix_socket(AF_UNIX,
+				SOCK_STREAM);
+  
+  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. */
+  
+  strcpy(myaddr_un.sun_path,tempnam(path_prefix,"netperf."));
+  if (bind(s_listen,
+	   (struct sockaddr *)&myaddr_un,
+	   sizeof(myaddr_un)) == SOCKET_ERROR) {
+    netperf_response.content.serv_errno = errno;
+    unlink(myaddr_un.sun_path);
+    close(s_listen);
+    send_response();
+    
+    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();
+    
+    exit(1);
+  }
+  
+  /* Now myaddr_un 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. */
+  
+  strcpy(stream_rr_response->unix_path,myaddr_un.sun_path);
+  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. */
+  
+  stream_rr_response->cpu_rate = 0.0; 	/* assume no cpu */
+  if (stream_rr_request->measure_cpu) {
+    stream_rr_response->measure_cpu = 1;
+    stream_rr_response->cpu_rate = calibrate_local_cpu(stream_rr_request->cpu_rate);
+  }
+  
+  
+  /* before we send the response back to the initiator, pull some of */
+  /* the socket parms from the globals */
+  stream_rr_response->send_buf_size = lss_size;
+  stream_rr_response->recv_buf_size = lsr_size;
+
+  send_response();
+  
+  addrlen = sizeof(peeraddr_un);
+  
+  if ((s_data = accept(s_listen,
+		       (struct sockaddr *)&peeraddr_un,
+		       &addrlen)) == INVALID_SOCKET) {
+    /* Let's just punt. The remote will be given some information */
+    close(s_listen);
+    
+    exit(1);
+  }
+  
+  if (debug) {
+    fprintf(where,"recv_stream_rr: accept completes on the data connection.\n");
+    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(stream_rr_request->measure_cpu);
+  
+  /* The loop will exit when the sender does a shutdown, which will */
+  /* return a length of zero   */
+  
+  if (stream_rr_request->test_length > 0) {
+    times_up = 0;
+    trans_remaining = 0;
+    start_timer(stream_rr_request->test_length + PAD_TIME);
+  }
+  else {
+    times_up = 1;
+    trans_remaining = stream_rr_request->test_length * -1;
+  }
+  
+  while ((!times_up) || (trans_remaining > 0)) {
+    temp_message_ptr = recv_ring->buffer_ptr;
+    request_bytes_remaining	= stream_rr_request->request_size;
+    
+    /* receive the request from the other side */
+    if (debug) {
+      fprintf(where,"about to receive for trans %d\n",trans_received);
+      fprintf(where,"temp_message_ptr is %p\n",temp_message_ptr);
+      fflush(where);
+    }
+    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 (debug) {
+	fprintf(where,"just received for trans %d\n",trans_received);
+	fflush(where);
+      }
+    }
+
+    recv_ring = recv_ring->next;
+
+    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 (debug) {
+      fprintf(where,"about to send for trans %d\n",trans_received);
+      fflush(where);
+    }
+    if((bytes_sent=send(s_data,
+			send_ring->buffer_ptr,
+			stream_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 = 997;
+      send_response();
+      exit(1);
+    }
+    
+    send_ring = send_ring->next;
+
+    trans_received++;
+    if (trans_remaining) {
+      trans_remaining--;
+    }
+    
+    if (debug) {
+      fprintf(where,
+	      "recv_stream_rr: Transaction %d complete\n",
+	      trans_received);
+      fflush(where);
+    }
+  }
+  
+  
+  /* The loop now exits due to timeout or transaction count being */
+  /* reached */
+  
+  cpu_stop(stream_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_stream_rr: got %d transactions\n",
+	    trans_received);
+    fflush(where);
+  }
+  
+  stream_rr_results->bytes_received	= (trans_received * 
+					   (stream_rr_request->request_size + 
+					    stream_rr_request->response_size));
+  stream_rr_results->trans_received	= trans_received;
+  stream_rr_results->elapsed_time	= elapsed_time;
+  if (stream_rr_request->measure_cpu) {
+    stream_rr_results->cpu_util	= calc_cpu_util(elapsed_time);
+  }
+  
+  if (debug) {
+    fprintf(where,
+	    "recv_stream_rr: test complete, sending results.\n");
+    fflush(where);
+  }
+  
+  send_response();
+  unlink(myaddr_un.sun_path);
+}
+
+void
+print_unix_usage()
+{
+
+  fwrite(unix_usage, sizeof(char), strlen(unix_usage), stdout);
+  exit(1);
+
+}
+void
+scan_unix_args(int argc, char *argv[])
+{
+#define UNIX_ARGS "hm:M:p:r:s:S:"
+  extern char	*optarg;	  /* pointer to option string	*/
+  
+  int		c;
+  
+  char	
+    arg1[BUFSIZ],  /* argument holders		*/
+    arg2[BUFSIZ];
+  
+  init_test_vars();
+
+  if (no_control) {
+    fprintf(where,
+	    "The UNIX 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, UNIX_ARGS)) != EOF) {
+    switch (c) {
+    case '?':	
+    case 'h':
+      print_unix_usage();
+      exit(1);
+    case 'p':
+      /* set the path prefix (directory) that should be used for the */
+      /* pipes. at some point, there should be some error checking. */
+      strcpy(path_prefix,optarg);
+      break;
+    case 's':
+      /* set local socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	lss_size_req = atoi(arg1);
+      if (arg2[0])
+	lsr_size_req = atoi(arg2);
+      break;
+    case 'S':
+      /* set remote socket sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	rss_size = atoi(arg1);
+      if (arg2[0])
+	rsr_size = atoi(arg2);
+      break;
+    case 'r':
+      /* set the request/response sizes */
+      break_args(optarg,arg1,arg2);
+      if (arg1[0])
+	req_size = atoi(arg1);
+      if (arg2[0])	
+	rsp_size = atoi(arg2);
+      break;
+    case 'm':
+      /* set the send size */
+      send_size = atoi(optarg);
+      break;
+    case 'M':
+      /* set the recv size */
+      recv_size = atoi(optarg);
+      break;
+    };
+  }
+}
+#endif /* WANT_UNIX */ 
diff --git a/nettest_unix.h b/nettest_unix.h
new file mode 100644
index 0000000..8eb393b
--- /dev/null
+++ b/nettest_unix.h
@@ -0,0 +1,198 @@
+/*
+        Copyright (C) 1993-2004 Hewlett-Packard Company
+*/
+
+ /* This file contains the test-specific definitions for netperf's */
+ /* DLPI tests */
+
+struct	stream_stream_request_struct {
+  int	recv_buf_size;
+  int	send_buf_size;
+  int	receive_size;   /* how many bytes do we want to */
+                        /* receive at one time? */
+  int	recv_alignment; /* what is the alignment of the */
+                        /* receive buffer? */
+  int	recv_offset;    /* and at what offset from that */
+                        /* alignment? */
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int	measure_cpu;	/* does the client want server cpu */
+                        /* utilization measured? */
+  float	cpu_rate;	/* do we know how fast the cpu is */
+                        /* already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct	stream_stream_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	receive_size;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct stream_stream_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   num_cpus;
+};
+
+struct	stream_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct	stream_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  float	cpu_rate;		/* could we measure	*/
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path to the dlpi device */
+};
+
+struct stream_rr_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  int	trans_received;	/* not ignored  */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   num_cpus;
+};
+
+struct	dg_stream_request_struct {
+  int	recv_buf_size;
+  int	message_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	measure_cpu;
+  float	cpu_rate;
+  int	test_length;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive copies? */
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct	dg_stream_response_struct {
+  int	recv_buf_size;
+  int	send_buf_size;
+  int	measure_cpu;
+  int	test_length;
+  float	cpu_rate;
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct	dg_stream_results_struct {
+  int	messages_recvd;
+  int	bytes_received;
+  float	elapsed_time;
+  float	cpu_util;
+  int   num_cpus;
+};
+
+
+struct	dg_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct	dg_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+  int   path_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  unix_path[32]; /* the path */
+};
+
+struct dg_rr_results_struct {
+  int	bytes_received;	/* ignored initially */
+  int	recv_calls;	/* ignored initially */
+  int	trans_received;	/* not ignored  */
+  float	elapsed_time;	/* how long the test ran */
+  float	cpu_util;	/* -1 if not measured */
+  float	serv_dem;	/* -1 if not measured */
+  int   num_cpus;
+};
+
+extern void scan_unix_args(int argc, char *argv[]);
+
+extern void send_stream_stream(char remote_host[]);
+extern void send_stream_rr(char remote_host[]);
+extern void send_dg_stream(char remote_host[]);
+extern void send_dg_rr(char remote_host[]);
+
+extern void recv_stream_stream();
+extern void recv_stream_rr();
+extern void recv_dg_stream();
+extern void recv_dg_rr();
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 */
diff --git a/nettest_xti.h b/nettest_xti.h
new file mode 100644
index 0000000..3bf9968
--- /dev/null
+++ b/nettest_xti.h
@@ -0,0 +1,264 @@
+/*
+ *       Copyright (C) 1995,2004 Hewlett-Packard Company
+ */
+
+ /* This file contains the test-specific definitions for netperf's BSD */
+ /* sockets tests */
+
+struct	xti_tcp_stream_request_struct {
+  int	send_buf_size;
+  int	recv_buf_size;	/* how big does the client want it - the */
+			/* receive socket buffer that is */ 
+  int	receive_size;   /* how many bytes do we want to receive at one */
+			/* time? */ 
+  int	recv_alignment; /* what is the alignment of the receive */
+			/* buffer? */ 
+  int	recv_offset;    /* and at what offset from that alignment? */ 
+  int	no_delay;       /* do we disable the nagle algorithm for send */
+			/* coalescing? */ 
+  int	measure_cpu;	/* does the client want server cpu utilization */
+			/* measured? */ 
+  float	cpu_rate;	/* do we know how fast the cpu is already? */ 
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid copies on */
+			/* receives? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dirty_count;    /* how many integers in the receive buffer */
+			/* should be made dirty before calling recv? */  
+  int   clean_count;    /* how many integers should be read from the */
+			/* recv buffer before calling recv? */ 
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  xti_device[32]; /* the path to the dlpi device */
+};
+
+struct	xti_tcp_stream_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	receive_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */ 
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct xti_tcp_stream_results_struct {
+  double         bytes_received;
+  unsigned int	 recv_calls;	
+  float	         elapsed_time;	/* how long the test ran */
+  float	         cpu_util;	/* -1 if not measured */
+  float	         serv_dem;	/* -1 if not measured */
+  int            cpu_method;    /* how was cpu util measured? */
+  int            num_cpus;      /* how many CPUs were there */
+};
+
+struct	xti_tcp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  xti_device[32]; /* the path to the dlpi device */
+};
+
+struct	xti_tcp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct xti_tcp_rr_results_struct {
+  unsigned int  bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs were there */
+};
+
+struct	xti_tcp_conn_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  xti_device[32]; /* the path to the dlpi device */
+};
+
+
+struct	xti_tcp_conn_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct xti_tcp_conn_rr_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs were there */
+};
+
+struct	xti_udp_stream_request_struct {
+  int	recv_buf_size;
+  int	message_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	checksum_off;   /* not used. left in for compatibility */
+  int	measure_cpu;
+  float	cpu_rate;
+  int	test_length;
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  xti_device[32]; /* the path to the dlpi device */
+};
+
+struct	xti_udp_stream_response_struct {
+  int	recv_buf_size;
+  int	send_buf_size;
+  int	measure_cpu;
+  int	test_length;
+  int	data_port_number;
+  float	cpu_rate;
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct	xti_udp_stream_results_struct {
+  unsigned int	messages_recvd;
+  unsigned int	bytes_received;
+  float	        elapsed_time;
+  float	        cpu_util;
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs were there */
+};
+
+
+struct	xti_udp_rr_request_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	send_buf_size;
+  int	recv_alignment;
+  int	recv_offset;
+  int	send_alignment;
+  int	send_offset;
+  int	request_size;
+  int	response_size;
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  float	cpu_rate;	/* do we know how fast the cpu is?	*/
+  int	test_length;	/* how long is the test?		*/
+  int	so_rcvavoid;    /* do we want the remote to avoid receive */
+			/* copies? */ 
+  int	so_sndavoid;    /* do we want the remote to avoid send copies? */
+  int   dev_name_len;   /* the length of the device name string. this */
+			/* is used to put it into the proper order on */
+			/* @#$% byte-swapped boxes... */
+  char  xti_device[32]; /* the path to the dlpi device */
+};
+
+struct	xti_udp_rr_response_struct {
+  int	recv_buf_size;	/* how big does the client want it	*/
+  int	no_delay;
+  int	measure_cpu;	/* does the client want server cpu	*/
+  int	test_length;	/* how long is the test?		*/
+  int	send_buf_size;
+  int	data_port_number;	/* connect to me here	*/
+  float	cpu_rate;		/* could we measure	*/
+  int	so_rcvavoid;	/* could the remote avoid receive copies? */
+  int	so_sndavoid;	/* could the remote avoid send copies? */
+};
+
+struct xti_udp_rr_results_struct {
+  unsigned int	bytes_received;	/* ignored initially */
+  unsigned int	recv_calls;	/* ignored initially */
+  unsigned int	trans_received;	/* not ignored  */
+  float	        elapsed_time;	/* how long the test ran */
+  float	        cpu_util;	/* -1 if not measured */
+  float	        serv_dem;	/* -1 if not measured */
+  int           cpu_method;    /* how was cpu util measured? */
+  int           num_cpus;      /* how many CPUs were there */
+};
+
+extern void send_xti_tcp_stream(char remote_host[]);
+
+extern void recv_xti_tcp_stream();
+
+extern void send_xti_tcp_rr(char remote_host[]);
+
+extern void send_xti_udp_stream(char remote_host[]);
+
+extern void recv_xti_udp_stream();
+
+extern void send_xti_udp_rr(char remote_host[]);
+
+extern void recv_xti_udp_rr();
+
+extern void recv_xti_tcp_rr();
+
+extern void send_xti_tcp_conn_rr(char remote_host[]);
+
+extern void recv_xti_tcp_conn_rr();
+
+extern void scan_xti_args(int argc, char *argv[]);
+
+
+
+
+
+
+
+
+
+