[netperf-dev] netperf2 commit notice r107 - in trunk: . src

raj at netperf.org raj at netperf.org
Wed Apr 25 12:34:25 PDT 2007


Author: raj
Date: 2007-04-25 12:34:20 -0700 (Wed, 25 Apr 2007)
New Revision: 107

Added:
   trunk/src/nettest_sdp.c
   trunk/src/nettest_sdp.h
Modified:
   trunk/config.h.in
   trunk/configure
   trunk/configure.ac
   trunk/src/Makefile.am
   trunk/src/Makefile.in
   trunk/src/netlib.h
   trunk/src/netperf.c
   trunk/src/netserver.c
Log:
initial  explicit SDP test coding 

Modified: trunk/config.h.in
===================================================================
--- trunk/config.h.in	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/config.h.in	2007-04-25 19:34:20 UTC (rev 107)
@@ -81,15 +81,15 @@
 /* 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 `xti' library (-lxti). */
-#undef HAVE_LIBXTI
-
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
@@ -306,6 +306,9 @@
 /* Define to one to include SCTP tests. */
 #undef WANT_SCTP
 
+/* 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

Modified: trunk/configure
===================================================================
--- trunk/configure	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/configure	2007-04-25 19:34:20 UTC (rev 107)
@@ -1304,6 +1304,7 @@
   --enable-unixdomain     include Unix Domain socket tests
   --enable-dlpi           include DLPI (link-layer) tests
   --enable-xti            include XTI socket tests
+  --enable-sdp            include SDP socket tests
   --enable-exs            include ICSC async sockets tests
   --enable-sctp           include tests to measure SCTP performance
   --enable-intervals      include ability to pace operations, may affect
@@ -7768,15 +7769,61 @@
 
 case "$enable_xti" in
      yes)
+		use_xti=true
+		;;
+     no)
+		use_xti=false
+		;;
+     '')
+		use_xti=false
+		;;
+     *)
+		{ { echo "$as_me:$LINENO: error: --enable-xti takes yes or no" >&5
+echo "$as_me: error: --enable-xti takes yes or no" >&2;}
+   { (exit 1); exit 1; }; }
+		;;
+esac
+
+if $use_xti
+then
+	{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+	{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+if $use_xti
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define WANT_XTI
+_ACEOF
+
+fi
+
+# see if we should be including the SDP tests
+
+{ echo "$as_me:$LINENO: checking whether to include SDP tests" >&5
+echo $ECHO_N "checking whether to include SDP tests... $ECHO_C" >&6; }
+
+# Check whether --enable-sdp was given.
+if test "${enable_sdp+set}" = set; then
+  enableval=$enable_sdp;
+fi
+
+
+case "$enable_sdp" in
+     yes)
 		# probably need to be a bit more sophisticated here
 
-{ echo "$as_me:$LINENO: checking for t_open in -lxti" >&5
-echo $ECHO_N "checking for t_open in -lxti... $ECHO_C" >&6; }
-if test "${ac_cv_lib_xti_t_open+set}" = set; then
+{ echo "$as_me:$LINENO: checking for t_open in -lsdp" >&5
+echo $ECHO_N "checking for t_open in -lsdp... $ECHO_C" >&6; }
+if test "${ac_cv_lib_sdp_t_open+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lxti  $LIBS"
+LIBS="-lsdp  $LIBS"
 cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
@@ -7817,45 +7864,45 @@
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext &&
        $as_test_x conftest$ac_exeext; then
-  ac_cv_lib_xti_t_open=yes
+  ac_cv_lib_sdp_t_open=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-	ac_cv_lib_xti_t_open=no
+	ac_cv_lib_sdp_t_open=no
 fi
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ echo "$as_me:$LINENO: result: $ac_cv_lib_xti_t_open" >&5
-echo "${ECHO_T}$ac_cv_lib_xti_t_open" >&6; }
-if test $ac_cv_lib_xti_t_open = yes; then
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_sdp_t_open" >&5
+echo "${ECHO_T}$ac_cv_lib_sdp_t_open" >&6; }
+if test $ac_cv_lib_sdp_t_open = yes; then
   cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBXTI 1
+#define HAVE_LIBSDP 1
 _ACEOF
 
-  LIBS="-lxti $LIBS"
+  LIBS="-lsdp $LIBS"
 
 fi
 
-		use_xti=true
+		use_sdp=true
 		;;
      no)
-		use_xti=false
+		use_sdp=false
 		;;
      '')
-		use_xti=false
+		use_sdp=false
 		;;
      *)
-		{ { echo "$as_me:$LINENO: error: --enable-xti takes yes or no" >&5
-echo "$as_me: error: --enable-xti takes yes or no" >&2;}
+		{ { echo "$as_me:$LINENO: error: --enable-sdp takes yes or no" >&5
+echo "$as_me: error: --enable-sdp takes yes or no" >&2;}
    { (exit 1); exit 1; }; }
 		;;
 esac
 
-if $use_xti
+if $use_sdp
 then
 	{ echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6; }
@@ -7864,11 +7911,11 @@
 echo "${ECHO_T}no" >&6; }
 fi
 
-if $use_xti
+if $use_sdp
 then
 
 cat >>confdefs.h <<\_ACEOF
-#define WANT_XTI
+#define WANT_SDP
 _ACEOF
 
 fi

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/configure.ac	2007-04-25 19:34:20 UTC (rev 107)
@@ -274,8 +274,6 @@
 
 case "$enable_xti" in
      yes)
-		# probably need to be a bit more sophisticated here
-		AC_CHECK_LIB(xti,t_open)
 		use_xti=true
 		;;
      no)	
@@ -301,6 +299,42 @@
 	AC_DEFINE([WANT_XTI],,[Define to one to include XTI tests.])
 fi
 
+# see if we should be including the SDP tests
+
+AC_MSG_CHECKING(whether to include SDP tests)
+
+AC_ARG_ENABLE(sdp,
+	[AS_HELP_STRING([--enable-sdp],[include SDP socket tests])])
+
+case "$enable_sdp" in
+     yes)
+		# probably need to be a bit more sophisticated here
+		AC_CHECK_LIB(sdp,t_open)
+		use_sdp=true
+		;;
+     no)	
+		use_sdp=false
+		;;
+     '')
+		use_sdp=false
+		;;
+     *)
+		AC_MSG_ERROR([--enable-sdp takes yes or no])
+		;;
+esac
+
+if $use_sdp
+then
+	AC_MSG_RESULT(yes)
+else
+	AC_MSG_RESULT(no)
+fi
+
+if $use_sdp
+then
+	AC_DEFINE([WANT_SDP],,[Define to one to include SDP tests.])
+fi
+
 # see if we should be including the ICSC-EXS tests
 
 AC_MSG_CHECKING(whether to include ICSC-EXS tests)

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/Makefile.am	2007-04-25 19:34:20 UTC (rev 107)
@@ -8,7 +8,7 @@
 
 EXTRA_DIST = netcpu_none.c netcpu_looper.c netcpu_pstat.c netcpu_pstatnew.c netcpu_perfstat.c netcpu_procstat.c netcpu_kstat.c netcpu_kstat10.c netcpu_sysctl.c netcpu_ntperf.c netcpu_osx.c missing/* dirs NetPerfDir/* NetServerDir/* netperf_version.h.in
 
-COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h
+COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h
 
 netperf_SOURCES = netperf.c $(COMMON_SRC) $(USE_CPU_SOURCE)
 netserver_SOURCES = netserver.c $(COMMON_SRC) $(USE_CPU_SOURCE)

Modified: trunk/src/Makefile.in
===================================================================
--- trunk/src/Makefile.in	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/Makefile.in	2007-04-25 19:34:20 UTC (rev 107)
@@ -136,7 +136,7 @@
 
 EXTRA_DIST = netcpu_none.c netcpu_looper.c netcpu_pstat.c netcpu_pstatnew.c netcpu_perfstat.c netcpu_procstat.c netcpu_kstat.c netcpu_kstat10.c netcpu_sysctl.c netcpu_ntperf.c netcpu_osx.c missing/* dirs NetPerfDir/* NetServerDir/* netperf_version.h.in
 
-COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h
+COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h
 
 netperf_SOURCES = netperf.c $(COMMON_SRC) $(USE_CPU_SOURCE)
 netserver_SOURCES = netserver.c $(COMMON_SRC) $(USE_CPU_SOURCE)
@@ -154,7 +154,8 @@
 
 am__objects_1 = netlib.$(OBJEXT) netsh.$(OBJEXT) nettest_bsd.$(OBJEXT) \
 	nettest_dlpi.$(OBJEXT) nettest_unix.$(OBJEXT) \
-	nettest_xti.$(OBJEXT) nettest_sctp.$(OBJEXT)
+	nettest_xti.$(OBJEXT) nettest_sctp.$(OBJEXT) \
+	nettest_sdp.$(OBJEXT)
 am__objects_2 = netcpu_ at NETCPU_SOURCE@.$(OBJEXT)
 am_netperf_OBJECTS = netperf.$(OBJEXT) $(am__objects_1) $(am__objects_2)
 netperf_OBJECTS = $(am_netperf_OBJECTS)
@@ -177,6 +178,7 @@
 @AMDEP_TRUE@	./$(DEPDIR)/nettest_bsd.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/nettest_dlpi.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/nettest_sctp.Po \
+ at AMDEP_TRUE@	./$(DEPDIR)/nettest_sdp.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/nettest_unix.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/nettest_xti.Po
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -244,6 +246,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_bsd.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_dlpi.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_sctp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_sdp.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_unix.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_xti.Po at am__quote@
 

Modified: trunk/src/netlib.h
===================================================================
--- trunk/src/netlib.h	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/netlib.h	2007-04-25 19:34:20 UTC (rev 107)
@@ -201,6 +201,26 @@
 #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

Modified: trunk/src/netperf.c
===================================================================
--- trunk/src/netperf.c	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/netperf.c	2007-04-25 19:34:20 UTC (rev 107)
@@ -85,6 +85,10 @@
 #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. */
 
@@ -241,9 +245,17 @@
   
 #ifdef DO_DNS
   else if (strcasecmp(test_name,"DNS_RR") == 0) {
-    send_dns_rr(host_name);
+    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);
+  }
+#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");

Modified: trunk/src/netserver.c
===================================================================
--- trunk/src/netserver.c	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/netserver.c	2007-04-25 19:34:20 UTC (rev 107)
@@ -386,6 +386,12 @@
       break;
 #endif
 
+#ifdef WANT_SDP
+    case DO_SDP_STREAM:
+      recv_sdp_stream();
+      break;
+#endif 
+
     default:
       fprintf(where,"unknown test number %d\n",
 	      netperf_request.content.request_type);

Added: trunk/src/nettest_sdp.c
===================================================================
--- trunk/src/nettest_sdp.c	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/nettest_sdp.c	2007-04-25 19:34:20 UTC (rev 107)
@@ -0,0 +1,3535 @@
+#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
+int first_burst_size=0;
+#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\
+    -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 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(socket, mss)
+     int socket;
+     int *mss;
+{
+
+  int sock_opt_len;
+
+}
+
+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;
+    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;
+    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;
+  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;
+  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;
+    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;
+  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 "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 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 */

Added: trunk/src/nettest_sdp.h
===================================================================
--- trunk/src/nettest_sdp.h	2007-04-03 23:25:27 UTC (rev 106)
+++ trunk/src/nettest_sdp.h	2007-04-25 19:34:20 UTC (rev 107)
@@ -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();



More information about the netperf-dev mailing list