[netperf-dev] netperf4 commit notice r20 - in trunk: . src

raj at netperf.org raj at netperf.org
Fri Nov 18 11:45:05 PST 2005


Author: raj
Date: 2005-11-18 11:45:00 -0800 (Fri, 18 Nov 2005)
New Revision: 20

Added:
   trunk/src/nettest_dns.c
   trunk/src/nettest_dns.h
Modified:
   trunk/config.h.in
   trunk/configure
   trunk/configure.ac
   trunk/src/Makefile.am
   trunk/src/Makefile.in
   trunk/src/generic_test.c
   trunk/src/netmsg.c
   trunk/src/nettest_bsd.c
Log:
Initial checkin of DNS tests - compiles but not complete and functional.


Modified: trunk/config.h.in
===================================================================
--- trunk/config.h.in	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/config.h.in	2005-11-18 19:45:00 UTC (rev 20)
@@ -6,6 +6,9 @@
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #undef HAVE_ARPA_INET_H
 
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
 /* Define to 1 if you have the `bind_to_cpu_id' function. */
 #undef HAVE_BIND_TO_CPU_ID
 
@@ -123,9 +126,15 @@
 /* Define to 1 if you have the <netinet/sctp.h> header file. */
 #undef HAVE_NETINET_SCTP_H
 
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
 /* Define to 1 if you have the `processor_bind' function. */
 #undef HAVE_PROCESSOR_BIND
 
+/* Define to 1 if you have the <resolv.h> header file. */
+#undef HAVE_RESOLV_H
+
 /* Define to 1 if you have the `sched_setaffinity' function. */
 #undef HAVE_SCHED_SETAFFINITY
 

Modified: trunk/configure
===================================================================
--- trunk/configure	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/configure	2005-11-18 19:45:00 UTC (rev 20)
@@ -20922,7 +20922,10 @@
 
 
 
-for ac_header in arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h math.h
+
+
+
+for ac_header in arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h math.h arpa/nameser.h resolv.h poll.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/configure.ac	2005-11-18 19:45:00 UTC (rev 20)
@@ -1,3 +1,4 @@
+# $Id$
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 
@@ -31,7 +32,7 @@
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h math.h])
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h math.h arpa/nameser.h resolv.h poll.h])
 
 # Some platforms require these.  There may be a better way.
 AC_HAVE_LIBRARY(socket)


Property changes on: trunk/configure.ac
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/Makefile.am	2005-11-18 19:45:00 UTC (rev 20)
@@ -22,11 +22,14 @@
 include_HEADERS = netperf.h netconfidence.h
 
 # in theory, the stuff below should deal with creating the requisite libs
-lib_LTLIBRARIES = nettest_bsd.la netsysstats.la
+lib_LTLIBRARIES = nettest_bsd.la netsysstats.la nettest_dns.la
 
 nettest_bsd_la_SOURCES = nettest_bsd.c nettest_bsd.h
 nettest_bsd_la_LDFLAGS = -module
 
+nettest_dns_la_SOURCES = nettest_dns.c nettest_dns.h
+nettest_dns_la_LDFLAGS = -module
+
 # the USE_CPU_SOURCE will pick the apropriate file based on the platform
 netsysstats_la_SOURCES = netsysstats_common.c netsysstats.h $(USE_CPU_SOURCE)
 netsysstats_la_LDFLAGS = -module

Modified: trunk/src/Makefile.in
===================================================================
--- trunk/src/Makefile.in	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/Makefile.in	2005-11-18 19:45:00 UTC (rev 20)
@@ -161,11 +161,14 @@
 include_HEADERS = netperf.h netconfidence.h
 
 # in theory, the stuff below should deal with creating the requisite libs
-lib_LTLIBRARIES = nettest_bsd.la netsysstats.la
+lib_LTLIBRARIES = nettest_bsd.la netsysstats.la nettest_dns.la
 
 nettest_bsd_la_SOURCES = nettest_bsd.c nettest_bsd.h
 nettest_bsd_la_LDFLAGS = -module
 
+nettest_dns_la_SOURCES = nettest_dns.c nettest_dns.h
+nettest_dns_la_LDFLAGS = -module
+
 # the USE_CPU_SOURCE will pick the apropriate file based on the platform
 netsysstats_la_SOURCES = netsysstats_common.c netsysstats.h $(USE_CPU_SOURCE)
 netsysstats_la_LDFLAGS = -module
@@ -190,6 +193,9 @@
 nettest_bsd_la_LIBADD =
 am_nettest_bsd_la_OBJECTS = nettest_bsd.lo
 nettest_bsd_la_OBJECTS = $(am_nettest_bsd_la_OBJECTS)
+nettest_dns_la_LIBADD =
+am_nettest_dns_la_OBJECTS = nettest_dns.lo
+nettest_dns_la_OBJECTS = $(am_nettest_dns_la_OBJECTS)
 bin_PROGRAMS = netperf$(EXEEXT) netserver$(EXEEXT)
 PROGRAMS = $(bin_PROGRAMS)
 
@@ -216,7 +222,8 @@
 @AMDEP_TRUE@	./$(DEPDIR)/netserver.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/netsysstats_ at NETSYS_SOURCE@.Plo \
 @AMDEP_TRUE@	./$(DEPDIR)/netsysstats_common.Plo \
- at AMDEP_TRUE@	./$(DEPDIR)/nettest_bsd.Plo
+ at AMDEP_TRUE@	./$(DEPDIR)/nettest_bsd.Plo \
+ at AMDEP_TRUE@	./$(DEPDIR)/nettest_dns.Plo
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
@@ -225,13 +232,14 @@
 LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
 DIST_SOURCES = $(netsysstats_la_SOURCES) $(nettest_bsd_la_SOURCES) \
-	$(netperf_SOURCES) $(netserver_SOURCES)
+	$(nettest_dns_la_SOURCES) $(netperf_SOURCES) \
+	$(netserver_SOURCES)
 HEADERS = $(include_HEADERS)
 
 DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.in Makefile.am \
 	missing/get_expiration_time.c missing/getaddrinfo.c \
 	missing/getopt.c missing/getopt1.c missing/inet_ntop.c
-SOURCES = $(netsysstats_la_SOURCES) $(nettest_bsd_la_SOURCES) $(netperf_SOURCES) $(netserver_SOURCES)
+SOURCES = $(netsysstats_la_SOURCES) $(nettest_bsd_la_SOURCES) $(nettest_dns_la_SOURCES) $(netperf_SOURCES) $(netserver_SOURCES)
 
 all: all-am
 
@@ -274,6 +282,8 @@
 	$(LINK) -rpath $(libdir) $(netsysstats_la_LDFLAGS) $(netsysstats_la_OBJECTS) $(netsysstats_la_LIBADD) $(LIBS)
 nettest_bsd.la: $(nettest_bsd_la_OBJECTS) $(nettest_bsd_la_DEPENDENCIES) 
 	$(LINK) -rpath $(libdir) $(nettest_bsd_la_LDFLAGS) $(nettest_bsd_la_OBJECTS) $(nettest_bsd_la_LIBADD) $(LIBS)
+nettest_dns.la: $(nettest_dns_la_OBJECTS) $(nettest_dns_la_DEPENDENCIES) 
+	$(LINK) -rpath $(libdir) $(nettest_dns_la_LDFLAGS) $(nettest_dns_la_OBJECTS) $(nettest_dns_la_LIBADD) $(LIBS)
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 install-binPROGRAMS: $(bin_PROGRAMS)
 	@$(NORMAL_INSTALL)
@@ -329,6 +339,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/netsysstats_ at NETSYS_SOURCE@.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/netsysstats_common.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_bsd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_dns.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \

Modified: trunk/src/generic_test.c
===================================================================
--- trunk/src/generic_test.c	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/generic_test.c	2005-11-18 19:45:00 UTC (rev 20)
@@ -1,4 +1,37 @@
+/*
 
+This file is part of netperf4.
+
+Netperf4 is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+Netperf4 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of netperf4 with the OpenSSL project's
+"OpenSSL" library (or with modified versions of it that use the same
+license as the "OpenSSL" library), and distribute the linked
+executables.  You must obey the GNU General Public License in all
+respects for all of the code used other than "OpenSSL".  If you modify
+this file, you may extend this exception to your version of the file,
+but you are not obligated to do so.  If you do not wish to do so,
+delete this exception statement from your version.
+
+*/
+
+char    generic_test_id[]="\
+@(#)generic_test.c (c) Copyright 2005 Hewlett-Packard Co. $Id$";
+
 /* Macros for accessing fields in the global netperf structures. */
 #define CHECKREQ_STATE                   test->state_req
 #define GET_TEST_DATA(test)              test->test_specific_data


Property changes on: trunk/src/generic_test.c
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/src/netmsg.c
===================================================================
--- trunk/src/netmsg.c	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/netmsg.c	2005-11-18 19:45:00 UTC (rev 20)
@@ -132,10 +132,7 @@
   xmlNodePtr cur;
   struct msgs *which_msg;
 
-  if (debug) {
-    fprintf(where,"process_message: entered\n");
-    fflush(where);
-  }
+  NETPERF_DEBUG_ENTRY(debug,where);
 
   msg = xmlDocGetRootElement(doc);
   if (msg == NULL) {
@@ -189,10 +186,9 @@
     }
   }
   xmlFreeDoc(doc);
-  if (debug) {
-    fprintf(where,"process_message: exiting\n");
-    fflush(where);
-  }
+
+  NETPERF_DEBUG_EXIT(debug,where);
+
   return(rc);
 }
 
@@ -752,10 +748,8 @@
   xmlChar   *testid;
 
 
-  if (debug) {
-    fprintf(where,"entering test_message\n");
-    fflush(where);
-  }
+  NETPERF_DEBUG_ENTRY(debug,where);
+
   if (server->state != server->state_req) {
     /* set netserver state to NSRV_WORK because receiving a test message
        shows that netperf accepted our version message */
@@ -845,10 +839,8 @@
     test_node = test_node->next;
   }
 
-  if (debug) {
-    fprintf(where,"exiting test_message\n");
-    fflush(where);
-  }
+  NETPERF_DEBUG_EXIT(debug,where);
+
   return(rc);
 }
 

Modified: trunk/src/nettest_bsd.c
===================================================================
--- trunk/src/nettest_bsd.c	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/nettest_bsd.c	2005-11-18 19:45:00 UTC (rev 20)
@@ -34,7 +34,6 @@
 #else
 #define DIRTY
 #define HISTOGRAM
-#define INTERVALS
 #endif /* lint */
 
 #ifdef DIRTY
@@ -57,12 +56,6 @@
 /*                                                              */
 /*      nettest_bsd.c                                           */
 /*                                                              */
-/*      the BSD sockets parsing routine...                      */
-/*       ...with the addition of Windows NT, this is now also   */
-/*          a Winsock test... sigh :)                           */
-/*                                                              */
-/*      scan_sockets_args()                                     */
-/*                                                              */
 /*      the actual test routines...                             */
 /*                                                              */
 /*      send_tcp_stream()       perform a tcp stream test       */

Added: trunk/src/nettest_dns.c
===================================================================
--- trunk/src/nettest_dns.c	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/nettest_dns.c	2005-11-18 19:45:00 UTC (rev 20)
@@ -0,0 +1,2032 @@
+/*
+
+This file is part of netperf4.
+
+Netperf4 is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+Netperf4 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of netperf4 with the OpenSSL project's
+"OpenSSL" library (or with modified versions of it that use the same
+license as the "OpenSSL" library), and distribute the linked
+executables.  You must obey the GNU General Public License in all
+respects for all of the code used other than "OpenSSL".  If you modify
+this file, you may extend this exception to your version of the file,
+but you are not obligated to do so.  If you do not wish to do so,
+delete this exception statement from your version.
+
+*/
+char    nettest_dns_id[]="\
+@(#)nettest_dns.c (c) Copyright 2005 Hewlett-Packard Co. $Id$";
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HISTOGRAM
+#define HISTOGRAM_VARS        struct timeval time_one,time_two
+#define HIST_TIMESTAMP(time)  gettimeofday(time,NULL)
+#define HIST_ADD(h,delta)     HIST_add(h,delta)
+#else
+#define HISTOGRAM_VARS       /* variable declarations for histogram go here */
+#define HIST_TIMESTAMP(time) /* time stamp call for histogram goes here */
+#define HIST_ADD(h,delta)    /* call to add data to histogram goes here */
+#endif
+
+/****************************************************************/
+/*                                                              */
+/*      nettest_dns.c                                           */
+/*                                                              */
+/*      the actual test routines...                             */
+/*                                                              */
+/*      send_dns_rr()           perform a DNS req/rsp test      */
+/*                                                              */
+/****************************************************************/
+
+
+
+#include <stdio.h>
+#include <values.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <errno.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#include "netperf.h"
+
+#ifdef HISTOGRAM
+#include "hist.h"
+#else
+#define HIST  void*
+#endif /* HISTOGRAM */
+
+#include "nettest_dns.h"
+
+#ifdef WIN32
+#define CHECK_FOR_INVALID_SOCKET (temp_socket == INVALID_SOCKET)
+#define CHECK_FOR_RECV_ERROR(len) (len == SOCKET_ERROR)
+#define CHECK_FOR_SEND_ERROR(len) (len >=0) || (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR) 
+#define GET_ERRNO WSAGetLastError()
+#else
+#define CHECK_FOR_INVALID_SOCKET (temp_socket < 0)
+#define CHECK_FOR_RECV_ERROR(len) (len < 0)
+#define CHECK_FOR_SEND_ERROR(len) (len >=0) || (errno == EINTR)
+#define GET_ERRNO errno
+#endif
+
+/* Macros for accessing fields in the global netperf structures. */
+#define SET_TEST_STATE(state)             test->new_state = state
+#define GET_TEST_STATE                    test->new_state
+#define CHECK_REQ_STATE                   test->state_req 
+#define GET_TEST_DATA(test)               test->test_specific_data
+
+
+static void
+report_test_failure(test, function, err_code, err_string)
+  test_t *test;
+  char   *function;
+  int     err_code;
+  char   *err_string;
+{
+  if (test->debug) {
+    fprintf(test->where,"%s: called report_test_failure:",function);
+    fprintf(test->where,"reporting  %s  errno = %d\n",err_string,GET_ERRNO);
+    fflush(test->where);
+  }
+  test->err_rc    = err_code;
+  test->err_fn    = function;
+  test->err_str   = err_string;
+  test->new_state = TEST_ERROR;
+  test->err_no    = GET_ERRNO;
+}
+
+static void
+set_test_state(test_t *test, uint32_t new_state)
+{
+  int   curr_state;
+  int   state;
+  int   valid = 0;
+  char *state_name;
+  char  error_msg[1024];
+  
+  curr_state = GET_TEST_STATE;
+
+  if (curr_state != TEST_ERROR) {
+    if (curr_state != new_state) {
+      switch (curr_state) {
+      case TEST_PREINIT:
+        state = TEST_INIT;
+        valid = 1;
+        break;
+      case TEST_INIT:
+        state_name = "TEST_INIT";
+        if (new_state == TEST_IDLE) {
+          state = TEST_IDLE;
+          valid = 1;
+        }
+        break;
+      case TEST_IDLE:
+        state_name = "TEST_IDLE";
+        if (new_state == TEST_LOADED) {
+          state = TEST_LOADED;
+          valid = 1;
+        }
+        if (new_state == TEST_DEAD) {
+          state = TEST_DEAD;
+          valid = 1;
+        }
+        break;
+      case TEST_LOADED:
+        state_name = "TEST_LOADED";
+        if (new_state == TEST_MEASURE) {
+          state = TEST_MEASURE;
+          valid = 1;
+        }
+        if (new_state == TEST_IDLE) {
+          state = TEST_IDLE;
+          valid = 1;
+        }
+        break;
+      case TEST_MEASURE:
+        state_name = "TEST_MEASURE";
+        if (new_state == TEST_LOADED) {
+          state = TEST_LOADED;
+          valid = 1;
+        }
+        break;
+      case TEST_ERROR:
+        /* an error occured while processing in the current state 
+           return and we should drop into wait_to_die so that
+           netperf4 can retrieve the error information before killing
+           the test */
+        state_name = "TEST_ERROR";
+        break;
+      default:
+        state_name = "ILLEGAL";
+      }
+      if (valid) {
+        test->new_state = state;
+      } else {
+        sprintf(error_msg,"bad state transition from %s state",state_name);
+        report_test_failure( test,
+                             "set_test_state",
+                             DNSE_REQUESTED_STATE_INVALID,
+                             strdup(error_msg));
+      }
+    }
+  }
+}
+
+void
+wait_to_die(test_t *test)
+{
+  while (GET_TEST_STATE != TEST_DEAD) {
+    if (CHECK_REQ_STATE == TEST_DEAD) {
+      free(test->test_specific_data);
+      test->test_specific_data = NULL;
+      test->new_state = TEST_DEAD;
+    }
+  }
+}
+
+
+
+static void
+get_dependency_data(test_t *test, int type, int protocol)
+{
+  dns_data_t *my_data = test->test_specific_data;
+
+  xmlChar *string;
+  xmlChar *remotehost;
+  xmlChar *remoteport;
+  int      remotefam;
+
+  int      count;
+  int      error;
+
+  struct addrinfo  hints;
+  struct addrinfo *remote_ai;
+  
+  /* still need to finish */
+  /* now get and initialize the remote addressing info */
+  string      =  xmlGetProp(test->dependency_data,(const xmlChar *)"family");
+  remotefam   = strtofam(string);
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family   = remotefam;
+  hints.ai_socktype = type;
+  hints.ai_protocol = protocol;
+  hints.ai_flags    = 0;
+
+  remoteport = xmlGetProp(test->dependency_data,(const xmlChar *)"remote_port");
+  remotehost = xmlGetProp(test->dependency_data,(const xmlChar *)"remote_host");
+  count = 0;
+  error = EAI_AGAIN;
+  do {
+    error = getaddrinfo( (char *)remotehost, (char *)remoteport,
+                            &hints, &remote_ai);
+    count += 1;
+    if (error == EAI_AGAIN) {
+      if (test->debug) {
+        fprintf(test->where,"Sleeping on getaddrinfo EAI_AGAIN\n");
+        fflush(test->where);
+      }
+      sleep(1);
+    }
+  } while ((error == EAI_AGAIN) && (count <= 5));
+    
+  if (test->debug) {
+    dump_addrinfo(test->where, remote_ai, remotehost, remoteport, remotefam);
+  }
+
+  if (!error) {
+    my_data->remaddr = remote_ai;
+  } else {
+    if (test->debug) {
+      fprintf(test->where,"get_dependency_data: getaddrinfo returned %d %s\n",
+              error, gai_strerror(error));
+      fflush(test->where);
+    }
+    report_test_failure(test,
+                        "get_dependency_data",
+                        DNSE_GETADDRINFO_ERROR,
+                        gai_strerror(error));
+  }
+}
+
+
+static void
+set_dependent_data(test)
+  test_t *test;
+{
+  
+  dns_data_t  *my_data = test->test_specific_data;
+  xmlChar *family;
+  char port[8];
+  char host[32];
+
+  xmlNodePtr dep_data;
+
+  switch (my_data->locaddr->ai_addr->sa_family) {
+#ifdef AF_INET6
+  case AF_INET6:
+    family = (xmlChar *)"AF_INET6";
+    break;
+#endif
+  case AF_INET:
+    family = (xmlChar *)"AF_INET";
+    break;
+  default:
+    family = (xmlChar *)"AF_UNSPEC";
+    break;
+  }
+
+  getnameinfo(my_data->locaddr->ai_addr, my_data->locaddr->ai_addrlen,
+                 host, sizeof(host), port, sizeof(port),
+                 NI_NUMERICHOST | NI_NUMERICSERV);
+
+  if ((dep_data = xmlNewNode(NULL,(xmlChar *)"dependency_data")) != NULL) {
+   /* set the properties of the dependency data sbg 2004-06-08 */
+    if ((xmlSetProp(dep_data,(const xmlChar *)"family",family)    != NULL) &&
+        (xmlSetProp(dep_data,(const xmlChar *)"remote_port",
+                    (xmlChar *)port) != NULL) &&
+        (xmlSetProp(dep_data,(const xmlChar *)"remote_host",
+                    (xmlChar *)host) != NULL))  {
+    test->dependent_data = dep_data;
+    } else {
+      report_test_failure(test,
+                          "set_dependent_data",
+                          DNSE_XMLSETPROP_ERROR,
+                          "error setting properties for dependency data");
+    }
+  } else {
+    report_test_failure(test,
+                        "set_dependent_data",
+                        DNSE_XMLNEWNODE_ERROR,
+                        "error getting new node for dependency data");
+  }
+}
+
+
+unsigned int
+convert(string,units)
+     unsigned char *string;
+     unsigned char *units;
+{
+  unsigned int base;
+  base = atoi((char *)string);
+  if (strstr((char *)units,"B")) {
+    base *= 1;
+  }
+  if (strstr((char *)units,"KB")) {
+    base *= 1024;
+  }
+  if (strstr((char *)units,"MB")) {
+    base *= (1024 * 1024);
+  }
+  if (strstr((char *)units,"GB")) {
+    base *= (1024 * 1024 * 1024);
+  }
+  if (strstr((char *)units,"kB")) {
+    base *= (1000);
+  }
+  if (strstr((char *)units,"mB")) {
+    base *= (1000 * 1000);
+  }
+  if (strstr((char *)units,"gB")) {
+    base *= (1000 * 1000 * 1000);
+  }
+  return(base);
+}
+
+
+
+ /* This routine will create a data (listen) socket with the apropriate */
+ /* options set and return it to the caller. this replaces all the */
+ /* duplicate code in each of the test routines and should help make */
+ /* things a little easier to understand. since this routine can be */
+ /* called by either the netperf or netserver programs, all output */
+ /* should be directed towards "where." family is generally AF_INET, */
+ /* and type will be either SOCK_STREAM or SOCK_DGRAM */
+static int
+create_data_socket(test)
+  test_t *test;
+{
+  dns_data_t  *my_data = test->test_specific_data;
+
+  int family           = my_data->locaddr->ai_family;
+  int type             = my_data->locaddr->ai_socktype;
+  int lss_size         = my_data->send_buf_size;
+  int lsr_size         = my_data->recv_buf_size;
+
+  int temp_socket;
+  int one;
+  int sock_opt_len;
+
+  if (test->debug) {
+    fprintf(test->where,
+            "create_data_socket: calling socket family = %d type = %d\n",
+            family, type);
+    fflush(test->where);
+  }
+  /*set up the data socket                        */
+  temp_socket = socket(family,
+                       type,
+                       0);
+
+  if (CHECK_FOR_INVALID_SOCKET) {
+    report_test_failure(test,
+                        "create_data_socket",
+                        DNSE_SOCKET_ERROR,
+                        "error creating socket");
+    return(temp_socket);
+  }
+
+  if (test->debug) {
+    fprintf(test->where,
+            "create_data_socket: socket %d obtained...\n",
+            temp_socket);
+    fflush(test->where);
+  }
+
+  /* Modify the local socket size. The reason we alter the send buffer */
+  /* size here rather than when the connection is made is to take care */
+  /* of decreases in buffer size. Decreasing the window size after */
+  /* connection establishment is a TCP no-no. Also, by setting the */
+  /* buffer (window) size before the connection is established, we can */
+  /* control the TCP MSS (segment size). The MSS is never more that 1/2 */
+  /* the minimum receive buffer size at each half of the connection. */
+  /* This is why we are altering the receive buffer size on the sending */
+  /* size of a unidirectional transfer. If the user has not requested */
+  /* that the socket buffers be altered, we will try to find-out what */
+  /* their values are. If we cannot touch the socket buffer in any way, */
+  /* we will set the values to -1 to indicate that.  */
+
+#ifdef SO_SNDBUF
+  if (lss_size > 0) {
+    if(setsockopt(temp_socket, SOL_SOCKET, SO_SNDBUF,
+                  &lss_size, sizeof(int)) < 0) {
+      report_test_failure(test,
+                          "create_data_socket",
+                          DNSE_SETSOCKOPT_ERROR,
+                          "error setting local send socket buffer size");
+      return(temp_socket);
+    }
+    if (test->debug > 1) {
+      fprintf(test->where,
+              "nettest_dns: create_data_socket: SO_SNDBUF of %d requested.\n",
+              lss_size);
+      fflush(test->where);
+    }
+  }
+
+  if (lsr_size > 0) {
+    if(setsockopt(temp_socket, SOL_SOCKET, SO_RCVBUF,
+                  &lsr_size, sizeof(int)) < 0) {
+      report_test_failure(test,
+                          "create_data_socket",
+                          DNSE_SETSOCKOPT_ERROR,
+                          "error setting local recv socket buffer size");
+      return(temp_socket);
+    }
+    if (test->debug > 1) {
+      fprintf(test->where,
+              "nettest_dns: create_data_socket: SO_RCVBUF of %d requested.\n",
+              lsr_size);
+      fflush(test->where);
+    }
+  }
+
+  /* Now, we will find-out what the size actually became, and report */
+  /* that back to the test. If the call fails, we will just report a -1 */
+  /* back to the initiator for the recv buffer size. */
+
+  sock_opt_len = sizeof(int);
+  if (getsockopt(temp_socket,
+                 SOL_SOCKET,
+                 SO_SNDBUF,
+                 (char *)&lss_size,
+                 &sock_opt_len) < 0) {
+    fprintf(test->where,
+        "nettest_dns: create_data_socket: getsockopt SO_SNDBUF: errno %d\n",
+        errno);
+    fflush(test->where);
+    lss_size = -1;
+  }
+  if (getsockopt(temp_socket,
+                 SOL_SOCKET,
+                 SO_RCVBUF,
+                 (char *)&lsr_size,
+                 &sock_opt_len) < 0) {
+    fprintf(test->where,
+        "nettest_dns: create_data_socket: getsockopt SO_RCVBUF: errno %d\n",
+        errno);
+    fflush(test->where);
+    lsr_size = -1;
+  }
+  if (test->debug) {
+    fprintf(test->where,
+            "nettest_dns: create_data_socket: socket sizes determined...\n");
+    fprintf(test->where,
+            "                       send: %d recv: %d\n",
+            lss_size,lsr_size);
+    fflush(test->where);
+  }
+
+#else /* SO_SNDBUF */
+
+  lss_size = -1;
+  lsr_size = -1;
+
+#endif /* SO_SNDBUF */
+
+  my_data->sbuf_size_ret = lss_size;
+  my_data->rbuf_size_ret = lsr_size;
+  /* now, we may wish to enable the copy avoidance features on the */
+  /* local system. of course, this may not be possible... */
+
+
+  /* Now, we will see about setting the TCP_NO_DELAY flag on the local */
+  /* socket. We will only do this for those systems that actually */
+  /* support the option. If it fails, note the fact, but keep going. */
+  /* If the user tries to enable TCP_NODELAY on a UDP socket, this */
+  /* will cause an error to be displayed */
+
+#ifdef TCP_NODELAY
+  if (my_data->no_delay) {
+    one = 1;
+    if(setsockopt(temp_socket,
+                  getprotobyname("tcp")->p_proto,
+                  TCP_NODELAY,
+                  (char *)&one,
+                  sizeof(one)) < 0) {
+      fprintf(test->where,
+              "netperf: create_data_socket: nodelay: errno %d\n",
+              errno);
+      fflush(test->where);
+    }
+
+    if (test->debug > 1) {
+      fprintf(test->where,
+              "netperf: create_data_socket: TCP_NODELAY requested...\n");
+      fflush(test->where);
+    }
+  }
+#else /* TCP_NODELAY */
+
+  my_data->no_delay = 0;
+
+#endif /* TCP_NODELAY */
+
+  return(temp_socket);
+
+}
+
+
+static void
+test_specific_data_init(dns_data_t *new) {
+
+  struct timeval foo;
+
+  /* first, zero the thing entirely */
+  memset(new,0,sizeof(dns_data_t));
+
+  /* now, set some specific fields.  some of these may be redundant */
+  new->request_source = NULL;
+
+  new->query_socket = -1;
+
+  /* might be good to randomize the initial request_id.  in the
+     overall scheme of things it may not really matter, but if we are
+     staring at a tcpdump trace of many threads sending
+     requests... and knuth only knows what the DNS server might do
+     with the request_id if we have all the threads starting with the
+     same one...  raj 2005-11-17 */
+  gettimeofday(&foo,NULL);
+  srandom(foo.tv_usec);
+  new->request_id = random() % UINT16_MAX;
+
+}
+
+/* at present we only support Internet class */
+static int
+strtoclass(char class_string[]){
+  if (!strcasecmp(class_string,"C_IN")) return(C_IN);
+  else return(C_NONE);
+}
+
+static int
+strtotype(char type_string[]){
+  if (!stracasecmp(type_string,"T_A")) return(T_A);
+  else if (!strcasecmp(type_string,"T_NS")) return(T_NS);
+  else if (!strcasecmp(type_string,"T_MD")) return(T_MD);
+  else if (!strcasecmp(type_string,"T_MF")) return(T_MF);
+  else if (!strcasecmp(type_string,"T_CNAME")) return(T_CNAME);
+  else if (!strcasecmp(type_string,"T_SOA")) return(T_SOA);
+  else if (!strcasecmp(type_string,"T_MB")) return(T_MB);
+  else if (!strcasecmp(type_string,"T_MG")) return(T_MG);
+  else if (!strcasecmp(type_string,"T_MR")) return(T_MR);
+  else if (!strcasecmp(type_string,"T_NULL")) return(T_NULL);
+  else if (!strcasecmp(type_string,"T_WKS")) return(T_WKS);
+  else if (!strcasecmp(type_string,"T_PTR")) return(T_PTR);
+  else if (!strcasecmp(type_string,"T_HINFO")) return(T_HINFO);
+  else if (!strcasecmp(type_string,"T_MINFO")) return(T_MINFO);
+  else if (!strcasecmp(type_string,"T_MX")) return(T_MX);
+  else if (!strcasecmp(type_string,"T_TXT")) return(T_TXT);
+  else if (!strcasecmp(type_string,"T_AFSDB")) return(T_AFSDB);
+  else if (!strcasecmp(type_string,"T_X25")) return(T_X25);
+  else if (!strcasecmp(type_string,"T_ISDN")) return(T_ISDN);
+  else if (!strcasecmp(type_string,"T_RT")) return(T_RT);
+  else if (!strcasecmp(type_string,"T_NSAP")) return(T_NSAP);
+  else if (!strcasecmp(type_string,"T_NSAP_PTR")) return(T_NSAP_PTR);
+  else if (!strcasecmp(type_string,"T_ATMA")) return(T_ATMA);
+  else if (!strcasecmp(type_string,"T_NAPTR")) return(T_NAPTR);
+#ifdef T_A6
+  else if (!strcasecmp(type_string,"T_A6")) return(T_A6);
+#endif
+#ifdef T_AAAA
+  else if (!strcasecmp(type_string,"T_AAAA")) return(T_AAAA);
+#endif
+#ifdef T_DNAME
+  else if (!strcasecmp(type_string,"T_DNAME")) return(T_DNAME);
+#endif
+  else if (!strcasecmp(type_string,"T_AXFR")) return(T_AXFR);
+  else if (!strcasecmp(type_string,"T_MAILB")) return(T_MAILB);
+  else if (!strcasecmp(type_string,"T_MAILA")) return(T_MAILA);
+  else if (!strcasecmp(type_string,"T_ANY")) return(T_ANY);
+  else return(T_NULL);
+}
+
+/* read the next line from the query_source stream, and build the
+   query to send.  */
+static int
+get_next_dns_request(test_t *test, char *request_buffer, int buflen) {
+
+  dns_data_t *my_data = GET_TEST_DATA(test);
+
+  char temp_name[NS_MAXDNAME]; /* from arpa/nameser.h */
+  char temp_class[64];   /* 64 seems like a bit much.  and by rights
+			    we probably should be doing stuff to make
+			    sure we don't overflow these things on the
+			    fscanf... */
+  char temp_type[64];
+  char temp_success[64];
+
+  if (my_data->request_source) {
+    /* ah, good, we do have a file */
+    if (fscanf(my_data->request_source,
+	       "%s %s %s %d\n",
+	       temp_name,
+	       temp_class,
+	       temp_type,
+	       temp_success) == EOF) {
+      rewind(my_data->request_source);
+      if (fscanf(my_data->request_source,
+		 "%s %s %s %d\n",
+		 temp_name,
+		 temp_class,
+		 temp_type,
+		 temp_success) == EOF) {
+	/* something like that should never happen */
+	return(-1);
+      }
+    }
+    return(res_mkquery(QUERY,
+		       temp_name,
+		       strtoclass(temp_class),
+		       strtotype(temp_type),
+		       NULL,
+		       0,
+		       NULL,
+		       request_buffer,
+		       buflen));
+  }
+  else {
+    /* well, now what should we do? */
+    return(-1);
+  }
+}
+dns_data_t *
+dns_test_init(test_t *test, int type, int protocol)
+{
+  dns_data_t *new_data;
+  xmlNodePtr  args;
+  xmlChar    *string;
+  xmlChar    *units;
+  xmlChar    *localhost;
+  xmlChar    *localport;
+  int         localfam;
+
+  int               count;
+  int               error;
+  struct addrinfo   hints;
+  struct addrinfo  *local_ai;
+  struct addrinfo  *local_temp;
+
+  /* allocate memory to store the information about this test */
+  new_data = (dns_data_t *)malloc(sizeof(dns_data_t));
+
+  args = test->node->xmlChildrenNode;
+  while (args != NULL) {
+    if (!xmlStrcmp(args->name,(const xmlChar *)"dependency_data")) {
+      test->dependency_data = args;
+    }
+    if (xmlStrcmp(args->name,(const xmlChar *)"socket_args")) {
+      args = args->next;
+      continue;
+    } 
+    break;
+  }
+ 
+  /* probably a good idea to make sure that new_data is real */
+  if ((args != NULL) &&
+      (NULL != new_data)) {
+    /* zero the dns test specific data structure */
+    test_specific_data_init(new_data);
+
+    string =  xmlGetProp(args,(const xmlChar *)"fill_file");
+    /* fopen the fill file it will be used when allocating buffer rings */
+    if (string) {
+      new_data->request_source = fopen((char *)string,"r");
+    }
+
+    /* we are relying on the good graces of the validating and
+       attribute filling of libxml when we parsed the message that got
+       us here... */
+    string =  xmlGetProp(args,(const xmlChar *)"send_buffer_size");
+    units  =  xmlGetProp(args,(const xmlChar *)"send_buffer_units");
+    new_data->send_buf_size = convert(string,units);
+
+    string =  xmlGetProp(args,(const xmlChar *)"recv_buffer_size");
+    units  =  xmlGetProp(args,(const xmlChar *)"recv_buffer_units");
+    new_data->recv_buf_size = convert(string,units);
+
+    /* we need to add code here to get stuff such as whether we should
+       use TCP, set TCP_NODELAY, keep the TCP connection open... */
+
+    /* we also neeed to add code to get stuff such as the name of the
+       remote DNS server, the port number and what address family to
+       use. this should be in this message rather than some dependent
+       data bit since there will really be no corresponding "recv_"
+       test.  raj 2005-11-17 */
+
+    /* now get and initialize the local addressing info */
+    string   =  xmlGetProp(args,(const xmlChar *)"family");
+    localfam = strtofam(string);
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family   = localfam;
+    hints.ai_socktype = type;
+    hints.ai_protocol = protocol;
+    hints.ai_flags    = 0;
+
+    localhost = xmlGetProp(args,(const xmlChar *)"local_host"),
+    localport = xmlGetProp(args,(const xmlChar *)"local_service"),
+    count = 0;
+    do {
+      error = getaddrinfo( (char *)localhost, (char *)localport,
+                              &hints, &local_ai);
+      count += 1;
+      if (error == EAI_AGAIN) {
+        if (test->debug) {
+          fprintf(test->where,
+		  "%s sleeping on getaddrinfo EAI_AGAIN\n",
+		  __func__);
+          fflush(test->where);
+        }
+        sleep(1);
+      }
+    } while ((error == EAI_AGAIN) && (count <= 5));
+    
+    if (test->debug) {
+      dump_addrinfo(test->where, local_ai, localhost, localport, localfam);
+    }
+
+    if (!error) {
+      /* OK, so we only do this once, but shouldn't we copy rather
+	 than assign here so we can do a freeaddrinfo()?  raj
+	 2005-11-17 */
+      new_data->locaddr = local_ai;
+    } else {
+      if (test->debug) {
+        fprintf(test->where,
+		"%s: getaddrinfo returned %d %s\n",
+		__func__,
+                error, 
+		gai_strerror(error));
+        fflush(test->where);
+      }
+      report_test_failure(test,
+                          (char *)__func__,
+                          DNSE_GETADDRINFO_ERROR,
+                          gai_strerror(error));
+    }
+  } else {
+    report_test_failure(test,
+                        (char *) __func__,
+                        DNSE_NO_SOCKET_ARGS,
+                        "no socket_arg element was found");
+  }
+
+  test->test_specific_data = new_data;
+  return(new_data);
+}
+
+static void
+update_elapsed_time(dns_data_t *my_data)
+{
+  my_data->elapsed_time.tv_usec += my_data->curr_time.tv_usec;
+  my_data->elapsed_time.tv_usec -= my_data->prev_time.tv_usec;
+    
+  my_data->elapsed_time.tv_sec += my_data->curr_time.tv_sec;
+  my_data->elapsed_time.tv_sec -= my_data->prev_time.tv_sec;
+  
+  if (my_data->curr_time.tv_usec < my_data->prev_time.tv_usec) {
+    my_data->elapsed_time.tv_usec += 1000000;
+    my_data->elapsed_time.tv_sec--;
+  }
+    
+  if (my_data->elapsed_time.tv_usec >= 1000000) {
+    my_data->elapsed_time.tv_usec -= 1000000;
+    my_data->elapsed_time.tv_sec++;
+  }
+}
+
+static int
+dns_test_clear_stats(dns_data_t *my_data)
+{
+  int i;
+  for (i = 0; i < DNS_MAX_COUNTERS; i++) {
+    my_data->stats.counter[i] = 0;
+  }
+  my_data->elapsed_time.tv_usec = 0;
+  my_data->elapsed_time.tv_sec  = 0;
+  gettimeofday(&(my_data->prev_time),NULL);
+  my_data->curr_time = my_data->prev_time;
+  return(NPE_SUCCESS);
+}
+
+void
+dns_test_decode_stats(xmlNodePtr stats, test_t *test)
+{
+  if (test->debug) {
+    fprintf(test->where,"dns_test_decode_stats: entered for %s test %s\n",
+            test->id, test->test_name);
+    fflush(test->where);
+  }
+}
+
+static xmlNodePtr
+dns_test_get_stats(test_t *test)
+{
+  xmlNodePtr  stats = NULL;
+  xmlAttrPtr  ap    = NULL;
+  int         i,j;
+  char        value[32];
+  char        name[32];
+  uint64_t    loc_cnt[DNS_MAX_COUNTERS];
+
+  dns_data_t *my_data = GET_TEST_DATA(test);
+
+  if (test->debug) {
+    fprintf(test->where,"dns_test_get_stats: entered for %s test %s\n",
+            test->id, test->test_name);
+    fflush(test->where);
+  }
+  if ((stats = xmlNewNode(NULL,(xmlChar *)"test_stats")) != NULL) {
+    /* set the properites of the test_stats message -
+       the tid and time stamps/values and counter values  sgb 2004-07-07 */
+
+    ap = xmlSetProp(stats,(xmlChar *)"tid",test->id);
+    for (i = 0; i < DNS_MAX_COUNTERS; i++) {
+      loc_cnt[i] = my_data->stats.counter[i];
+      if (test->debug) {
+        fprintf(test->where,"DNS_COUNTER%X = %#llx\n",i,loc_cnt[i]);
+      } 
+    }
+    if (GET_TEST_STATE == TEST_MEASURE) {
+      gettimeofday(&(my_data->curr_time), NULL);
+      if (ap != NULL) {
+        sprintf(value,"%#ld",my_data->curr_time.tv_sec);
+        ap = xmlSetProp(stats,(xmlChar *)"time_sec",(xmlChar *)value);
+        if (test->debug) {
+          fprintf(test->where,"time_sec=%s\n",value);
+          fflush(test->where);
+        }
+      }
+      if (ap != NULL) {
+        sprintf(value,"%#ld",my_data->curr_time.tv_usec);
+        ap = xmlSetProp(stats,(xmlChar *)"time_usec",(xmlChar *)value);
+        if (test->debug) {
+          fprintf(test->where,"time_usec=%s\n",value);
+          fflush(test->where);
+        }
+      }
+    } else {
+      if (ap != NULL) {
+        sprintf(value,"%#ld",my_data->elapsed_time.tv_sec);
+        ap = xmlSetProp(stats,(xmlChar *)"elapsed_sec",(xmlChar *)value);
+        if (test->debug) {
+          fprintf(test->where,"elapsed_sec=%s\n",value);
+          fflush(test->where);
+        }
+      }
+      if (ap != NULL) {
+        sprintf(value,"%#ld",my_data->elapsed_time.tv_usec);
+        ap = xmlSetProp(stats,(xmlChar *)"elapsed_usec",(xmlChar *)value);
+        if (test->debug) {
+          fprintf(test->where,"elapsed_usec=%s\n",value);
+          fflush(test->where);
+        }
+      }
+    }
+    for (i = 0; i < DNS_MAX_COUNTERS; i++) {
+      if (ap == NULL) {
+        break;
+      }
+      if (loc_cnt[i]) {
+        sprintf(value,"%#llx",my_data->stats.counter[i]);
+        sprintf(name,"cntr%1X_value",i);
+        ap = xmlSetProp(stats,(xmlChar *)name,(xmlChar *)value);
+        if (test->debug) {
+          fprintf(test->where,"%s=%s\n",name,value);
+          fflush(test->where);
+        }
+      }
+    }
+    if (ap == NULL) {
+      xmlFreeNode(stats);
+      stats = NULL;
+    }
+  }
+  if (test->debug) {
+    fprintf(test->where,"%s: exiting for %s test %s\n",
+            __func__, test->id, test->test_name);
+    fflush(test->where);
+  }
+  return(stats);
+} /* end of dns_test_get_stats */
+
+
+
+static void
+send_dns_rr_preinit(test_t *test)
+{
+  dns_data_t       *my_data;
+
+  my_data   = test->test_specific_data;
+
+  /* I don't think we will be using get_dependency_data */
+  /* get_dependency_data(test, SOCK_STREAM, IPPROTO_TCP); */
+  my_data->query_socket = create_data_socket(test);
+}
+
+static uint32_t
+send_dns_rr_init(test_t *test)
+{
+  dns_data_t       *my_data;
+
+  my_data   = test->test_specific_data;
+
+  if (test->debug) {
+    fprintf(test->where,"%s: in INIT state making connect call\n",__func__);
+    fflush(test->where);
+  }
+  if (connect(my_data->query_socket,
+              my_data->remaddr->ai_addr,
+              my_data->remaddr->ai_addrlen) < 0) {
+    report_test_failure(test,
+                        __func__,
+                        DNSE_CONNECT_FAILED,
+                        "data socket connect failed");
+  } else {
+    if (test->debug) {
+      fprintf(test->where,"%s: connected and moving to IDLE\n",__func__);
+      fflush(test->where);
+    }
+  }
+  return(TEST_IDLE);
+}
+
+static void
+send_dns_rr_idle_link(test_t *test, int last_len)
+{
+  int               len;
+  uint32_t          new_state;
+  dns_data_t       *my_data;
+
+  my_data   = test->test_specific_data;
+  len       = last_len;
+
+  new_state = CHECK_REQ_STATE;
+  while (new_state == TEST_LOADED) {
+    sleep(1);
+    new_state = CHECK_REQ_STATE;
+  }
+  if (new_state == TEST_IDLE) {
+    if (test->debug) {
+      fprintf(test->where,"%s: transition from LOAD to IDLE\n",__func__);
+      fflush(test->where);
+    }
+    /* it may not be pretty, but it is sufficient and effective for
+       our nefarious porpoises here - just close the socket,
+       regardless of flavor, as we don't care one whit about flushing,
+       and are not going to worry about attempts to reuse a TCP
+       connection in TIME_WAIT when TCP connections are being used. */
+    if (close(my_data->query_socket) == -1) {
+      report_test_failure(test,
+			  __func__,
+                          DNSE_SOCKET_SHUTDOWN_FAILED,
+                          "failure shuting down data socket");
+    } 
+    else {
+      my_data->query_socket = -1;
+    }
+  } else {
+    /* a transition to a state other than TEST_IDLE was requested
+       after the link was closed in the TEST_LOADED state */
+    report_test_failure(test,
+			__func__,
+                        DNSE_DATA_CONNECTION_CLOSED_ERROR,
+                        "data connection closed and non idle state requested");
+
+  }
+}
+
+static uint32_t
+send_dns_rr_meas(test_t *test)
+{
+  uint32_t          new_state;
+  int               len;
+  int               ret;
+  int               response_len;
+  int               bytes_left;
+  int               req_size;
+  uint16_t         *rsp_ptr;
+  uint16_t          message_id;
+  dns_data_t       *my_data;
+  dns_request_status_t *status_entry;
+  struct pollfd     fds;
+
+  /* this aught to be enough to hold it - modulo stuff like large
+     requests on TCP connections... and we make it of type uint16_t so
+     we don't have to worry about alignment when we pull shorts out of
+     it.  there is a crass joke there somewhere. raj 2005-11-18 */
+  uint16_t          request_buffer[NS_PACKETSZ/sizeof(uint16_t)];  
+
+
+  HISTOGRAM_VARS;
+  my_data   = test->test_specific_data;
+
+
+  /* go through and build the next request to send */
+  req_size = get_next_dns_request(test, 
+				  (char *)request_buffer, 
+				  sizeof(request_buffer));
+
+  /* set the ID as apropriate since it is a uint16_t, we'll not worry
+    about "overflow" as it will just be dealt with "naturally. we use
+    the magic number of "0" based on "knowing" that the ID is the
+    first thing in the message, and it seems there is no commonly
+    defined structure for a DNS reqeust header?  raj 2005-11-18 */
+
+  message_id = request_buffer[0] = my_data->request_id++; 
+
+  /* now stash some state away so we can deal with the response */
+  status_entry = &(my_data->outstanding_requests[message_id]);
+  if (status_entry->active) {
+    /* this could be bad?  or is it just an expired entry? */
+  }
+  else {
+    status_entry->active = 1;
+    status_entry->success = 1;
+    NETPERF_TIME_STAMP(status_entry->sent_time);
+  }
+  /* send data for the test. we can use send() rather than sendto()
+     because in _init we will have called connect() on the socket.
+     now, if we are using UDP and the server happens to reply from a
+     source IP address other than the one to which we have
+     connected... well...  raj 2005-11-18 */
+
+  /* if we are ever going to pace these things, we need logic to
+     decide if it is time to send another request or not */
+
+  if((len=send(my_data->query_socket,
+	       request_buffer,
+	       req_size,
+               0)) != req_size) {
+    /* this macro hides windows differences */
+    if (CHECK_FOR_SEND_ERROR(len)) {
+      report_test_failure(test,
+                          __func__,
+                          DNSE_DATA_SEND_ERROR,
+                          "data send error");
+    }
+  }
+  my_data->stats.named.queries_sent++;
+  my_data->stats.named.query_bytes_sent += len;
+
+  /* recv the request for the test, but first we really need some sort
+     of timeout on a poll call or whatnot... */
+
+  fds.fd = my_data->query_socket;
+  fds.events = POLLIN;
+  fds.revents = 0;
+
+  ret = poll(&fds,1,5000); /* magic constant alert - that is something
+			      that should come from the config
+			      file... */
+
+  switch (ret) {
+  case -1: 
+    /* something bad happened */
+    report_test_failure(test,
+			__func__,
+			DNSE_DATA_RECV_ERROR,
+			"poll_error");
+    
+    break;
+  case 0:
+    /* we had a timeout. invalidate the existing request so we will
+       ignore it if it was simply delayed. status_entry should still
+       be valid*/
+    memset(&status_entry,0,sizeof(status_entry));
+    break;
+  case 1:
+  
+    bytes_left = NS_PACKETSZ; /* we'll do something clever inside the
+				 loop to handle UDP vs TCP. */
+    rsp_ptr = request_buffer;  /* until we discover it is a bug, re-use
+				  the reqeust buffer */
+    while (bytes_left > 0) {
+      if ((len=recv(my_data->query_socket,
+		    rsp_ptr,
+		    bytes_left,
+		    0)) != 0) {
+	/* this macro hides windows differences */
+	if (CHECK_FOR_RECV_ERROR(len)) {
+	  report_test_failure(test,
+			      __func__,
+			      DNSE_DATA_RECV_ERROR,
+			      "data_recv_error");
+	  break;
+	}
+	/* do we have more to read this time around? */
+	if (!my_data->use_tcp) {
+	  /* we are UDP */
+	  response_len = len;
+	  bytes_left = 0;
+	}
+	else {
+	  /* not quite sure what to do here - probably have to parse the
+	     packet a bit more, update response_len etc... */
+	}
+	rsp_ptr    += len;
+	bytes_left -= len;
+      } 
+      else {
+	/* len is 0 the connection was closed exit the while loop */
+	break;
+      }
+    }
+    message_id = rsp_ptr[0];
+    status_entry  = &(my_data->outstanding_requests[message_id]);
+    if (status_entry->active) {
+      /* this is what we want to see */
+      /* code to timestamp enabled by HISTOGRAM */
+      HIST_TIMESTAMP(&time_two);
+      HIST_ADD(my_data->time_hist,
+	       delta_macro(&(status_entry->sent_time),&time_two));
+      my_data->stats.named.responses_received++;
+      my_data->stats.named.response_bytes_received += response_len;
+    }
+    else {
+      /* is this bad?  well, if we were in a transition from LOAD to
+	 MEAS state it could happen I suppose so for now we will simply
+	 ignore the message */
+    }
+
+    if (len == 0) {
+      /* how do we deal with a closed connection in the measured state */
+      report_test_failure(test,
+			  __func__,
+			  DNSE_DATA_CONNECTION_CLOSED_ERROR,
+			  "data connection closed during TEST_MEASURE state");
+    }
+  }
+  new_state = CHECK_REQ_STATE;
+  if (new_state == TEST_LOADED) {
+    /* transitioning to loaded state from measure state
+       set current timestamp and update elapsed time */
+    gettimeofday(&(my_data->curr_time), NULL);
+    update_elapsed_time(my_data);
+  }
+  return(new_state);
+}
+
+static uint32_t
+send_dns_rr_load(test_t *test)
+{
+  uint32_t          new_state;
+  int               len;
+  int               bytes_left;
+  int               req_size;
+  char             *rsp_ptr;
+  dns_data_t       *my_data;
+  char              request_buffer[NS_PACKETSZ];  /* that aught to be
+						     enough to hold it
+						     - modulo stuff
+						     like large
+						     requests on TCP
+						     connections... */
+
+  my_data   = test->test_specific_data;
+
+  /* go through and build the next request to send */
+  req_size = get_next_dns_request(test, 
+				  request_buffer, 
+				  sizeof(request_buffer));
+
+
+  /* send data for the test */
+  if((len=send(my_data->query_socket,
+	       request_buffer,
+               req_size,
+               0)) != req_size) {
+    /* this macro hides windows differences */
+    if (CHECK_FOR_SEND_ERROR(len)) {
+      report_test_failure(test,
+                          __func__,
+                          DNSE_DATA_SEND_ERROR,
+                          "data send error");
+    }
+  }
+  /* recv the request for the test */
+  rsp_ptr    = request_buffer;
+  bytes_left = NS_PACKETSZ;
+  while (bytes_left > 0) {
+    if ((len=recv(my_data->query_socket,
+                  rsp_ptr,
+                  bytes_left,
+                  0)) != 0) {
+      /* this macro hides windows differences */
+      if (CHECK_FOR_RECV_ERROR(len)) {
+        report_test_failure(test,
+                            __func__,
+                            DNSE_DATA_RECV_ERROR,
+                            "data_recv_error");
+        break;
+      }
+      /* do we have more to read this time around? */
+      if (!my_data->use_tcp) {
+	/* we are UDP */
+	bytes_left = 0;
+      }
+      else {
+	/* not quite sure what to do here - probably have to parse the
+	   packet a bit more */
+      }
+      rsp_ptr    += len;
+      bytes_left -= len;
+    }
+    else {
+      /* len is 0 the connection was closed exit the while loop */
+      break;
+    }
+  }
+
+  new_state = CHECK_REQ_STATE;
+  if ((len == 0) ||
+      (new_state == TEST_IDLE)) {
+    send_dns_rr_idle_link(test,len);
+    new_state = TEST_IDLE;
+  } else {
+    if (new_state == TEST_MEASURE) {
+      /* transitioning to measure state from loaded state
+         set previous timestamp */
+      gettimeofday(&(my_data->prev_time), NULL);
+    }
+  }
+  return(new_state);
+}
+
+int
+recv_tcp_rr_clear_stats(test_t *test)
+{
+  return(dns_test_clear_stats(GET_TEST_DATA(test)));
+}
+
+
+xmlNodePtr
+recv_tcp_rr_get_stats(test_t *test)
+{
+  return( dns_test_get_stats(test));
+}
+
+void
+recv_tcp_rr_decode_stats(xmlNodePtr stats,test_t *test)
+{
+  dns_test_decode_stats(stats,test);
+}
+
+
+int
+send_dns_rr_clear_stats(test_t *test)
+{
+  return(dns_test_clear_stats(GET_TEST_DATA(test)));
+}
+
+xmlNodePtr
+send_dns_rr_get_stats(test_t *test)
+{
+  return( dns_test_get_stats(test));
+}
+
+void
+send_dns_rr_decode_stats(xmlNodePtr stats,test_t *test)
+{
+  dns_test_decode_stats(stats,test);
+}
+
+
+
+
+/* This routine implements the UDP request/response test */
+/* (a.k.a. rr) for the sockets interface. It receives its */
+/* parameters via the xml node contained in the test structure */
+/* output to the standard output. */
+/* results are collected by the procedure send_dns_rr_get_stats */
+
+void
+send_dns_rr(test_t *test)
+{
+  uint32_t state, new_state;
+  dns_test_init(test, SOCK_STREAM, IPPROTO_TCP);
+  state = GET_TEST_STATE;
+  while ((state != TEST_ERROR) &&
+         (state != TEST_DEAD )) {
+    switch(state) {
+    case TEST_PREINIT:
+      send_dns_rr_preinit(test);
+      new_state = TEST_INIT;
+      break;
+    case TEST_INIT:
+      new_state = CHECK_REQ_STATE;
+      if (new_state == TEST_IDLE) {
+        new_state = send_dns_rr_init(test);
+      }
+      break;
+    case TEST_IDLE:
+      new_state = CHECK_REQ_STATE;
+      if (new_state == TEST_IDLE) {
+        sleep(1);
+      }
+      break;
+    case TEST_MEASURE:
+      new_state = send_dns_rr_meas(test);
+      break;
+    case TEST_LOADED:
+      new_state = send_dns_rr_load(test);
+      break;
+    default:
+      break;
+    } /* end of switch */
+    set_test_state(test, new_state);
+    state = GET_TEST_STATE;
+  } /* end of while */
+  wait_to_die(test);
+} /* end of send_dns_rr */
+
+
+/*  This implementation of report_dns_test_results will generate strange
+    results if transaction count and throughput tests are included in the
+    same test set. The first test in the set sets the headers and algorithm
+    for computing service demand */
+
+void
+dns_test_results_init(tset_t *test_set,char *report_flags,char *output)
+{
+  dns_results_t *rd;
+  FILE          *outfd;
+  int            max_count;
+
+  rd        = test_set->report_data;
+  max_count = test_set->confidence.max_count;
+  
+  if (output) {
+    if (test_set->debug) {
+      fprintf(test_set->where,
+              "dns_test_results_init: report going to file %s\n",
+              output);
+      fflush(test_set->where);
+    }
+    outfd = fopen(output,"a");
+  } else {
+    if (test_set->debug) {
+      fprintf(test_set->where,
+              "report_dns_test_results: report going to file stdout\n");
+      fflush(test_set->where);
+    }
+    outfd = stdout;
+  }
+  /* allocate and initialize report data */
+  rd = malloc(sizeof(dns_results_t) + 7 * max_count * sizeof(double));
+  if (rd) {
+    memset(rd, 0,
+           sizeof(sizeof(dns_results_t) + 7 * max_count * sizeof(double)));
+    rd->max_count      = max_count;
+    rd->results        = &(rd->results_start);
+    rd->xmit_results   = &(rd->results[max_count]);
+    rd->recv_results   = &(rd->xmit_results[max_count]);
+    rd->trans_results  = &(rd->recv_results[max_count]);
+    rd->utilization    = &(rd->trans_results[max_count]);
+    rd->servdemand     = &(rd->utilization[max_count]);
+    rd->run_time       = &(rd->servdemand[max_count]);
+    rd->result_minimum = MAXDOUBLE;
+    rd->result_maximum = MINDOUBLE;
+    rd->outfd          = outfd;
+    rd->sd_denominator = 0.0;
+    if (!strcmp(report_flags,"PRINT_RUN")) {
+      rd->print_run  = 1;
+    }
+    if (!strcmp(report_flags,"PRINT_TESTS")) {
+      rd->print_test = 1;
+    }
+    if (!strcmp(report_flags,"PRINT_ALL")) {
+      rd->print_run  = 1;
+      rd->print_test = 1;
+    }
+    if (test_set->debug) {
+      rd->print_run  = 1;
+      rd->print_test = 1;
+    }
+    test_set->report_data = rd;
+  } else {
+    /* could not allocate memory can't generate report */
+    fprintf(outfd,
+            "dns_test_results_init: malloc failed can't generate report\n");
+    fflush(outfd);
+    exit;
+  }
+}
+
+void
+process_test_stats(tset_t *test_set, xmlNodePtr stats, xmlChar *tid)
+{
+  int            i;
+  int            count;
+  int            index;
+  FILE          *outfd;
+  dns_results_t *rd;
+
+  double         elapsed_seconds;
+  double         result;
+  double         xmit_rate;
+  double         recv_rate;
+  double         xmit_trans_rate;
+  double         recv_trans_rate;
+
+#define TST_E_SEC         0
+#define TST_E_USEC        1
+#define TST_X_BYTES       5
+#define TST_R_BYTES       7
+#define TST_X_TRANS       8
+#define TST_R_TRANS       9
+
+#define MAX_TEST_CNTRS 12
+  double         test_cntr[MAX_TEST_CNTRS];
+  const char *cntr_name[] = {
+    "elapsed_sec",
+    "elapsed_usec",
+    "time_sec",
+    "time_usec",
+    "cntr0_value",
+    "cntr1_value",
+    "cntr2_value",
+    "cntr3_value",
+    "cntr4_value",
+    "cntr5_value",
+    "cntr6_value",
+    "cntr7_value"
+  };
+
+  rd     = test_set->report_data;
+  count  = test_set->confidence.count;
+  outfd  = rd->outfd;
+  index  = count - 1;
+
+  /* process test statistics */
+  if (test_set->debug) {
+    fprintf(test_set->where,"\tprocessing test_stats\n");
+    fflush(test_set->where);
+  }
+  for (i=0; i<MAX_TEST_CNTRS; i++) {
+    char *value_str =
+       (char *)xmlGetProp(stats, (const xmlChar *)cntr_name[i]);
+    if (value_str) {
+      test_cntr[i] = strtod(value_str,NULL);
+      if (test_cntr[i] == 0.0) {
+        uint64_t x;
+        sscanf(value_str,"%llx",&x);
+        test_cntr[i] = (double)x;
+      }
+    } else {
+      test_cntr[i] = 0.0;
+    }
+    if (test_set->debug) {
+      fprintf(test_set->where,"\t%12s test_cntr[%2d] = %10g\t'%s'\n",
+              cntr_name[i], i, test_cntr[i],
+              xmlGetProp(stats, (const xmlChar *)cntr_name[i]));
+    }
+  }
+  elapsed_seconds = test_cntr[TST_E_SEC] + test_cntr[TST_E_USEC]/1000000;
+  xmit_rate       = test_cntr[TST_X_BYTES]*8/(elapsed_seconds*1000000);
+  recv_rate       = test_cntr[TST_R_BYTES]*8/(elapsed_seconds*1000000);
+  xmit_trans_rate = test_cntr[TST_X_TRANS]/elapsed_seconds;
+  recv_trans_rate = test_cntr[TST_R_TRANS]/elapsed_seconds;
+  if (test_set->debug) {
+    fprintf(test_set->where,"\txmit_rate = %7g\t%7g\n",
+            xmit_rate, test_cntr[TST_X_BYTES]);
+    fprintf(test_set->where,"\trecv_rate = %7g\t%7g\n",
+            recv_rate, test_cntr[TST_R_BYTES]);
+    fprintf(test_set->where,"\txmit_trans_rate = %7g\t%7g\n",
+            xmit_trans_rate, test_cntr[TST_X_TRANS]);
+    fprintf(test_set->where,"\trecv_trans_rate = %7g\t%7g\n",
+            recv_trans_rate, test_cntr[TST_X_TRANS]);
+    fflush(test_set->where);
+  }
+  if (rd->sd_denominator == 0.0) {
+    if (xmit_rate > 0.0 || recv_rate > 0.0) {
+      rd->sd_denominator = 1000000.0/(8.0*1024.0);
+    } else {
+      rd->sd_denominator = 1.0;
+    }
+  }
+  if (test_set->debug) {
+    fprintf(test_set->where,"\tsd_denominator = %f\n",rd->sd_denominator);
+    fflush(test_set->where);
+  }
+  if (rd->sd_denominator != 1.0) {
+    result = recv_rate + xmit_rate;
+  } else {
+    result = recv_trans_rate + xmit_trans_rate;
+  }
+  if (test_set->debug) {
+    fprintf(test_set->where,"\tresult    = %f\n",result);
+    fflush(test_set->where);
+  }
+  /* accumulate results for the run */
+  rd->run_time[index]        += elapsed_seconds;
+  rd->results[index]         += result;
+  rd->xmit_results[index]    += xmit_rate;
+  rd->recv_results[index]    += recv_rate;
+  rd->trans_results[index]   += xmit_trans_rate;
+  rd->trans_results[index]   += recv_trans_rate;
+  
+  if (rd->print_test) {
+    /* Display per test results */
+    fprintf(outfd,"%3d  ", count);                    /*  0,5 */
+    fprintf(outfd,"%-6s ",  tid);                     /*  5,7 */
+    fprintf(outfd,"%-6.2f ",elapsed_seconds);         /* 12,7 */
+    if (rd->sd_denominator != 1.0) {
+      fprintf(outfd,"%7.2f ",result);                 /* 19,8 */
+      fprintf(outfd,"%7.2f ",xmit_rate);              /* 27,8 */
+      fprintf(outfd,"%7.2f ",recv_rate);              /* 35,8 */
+    } else {
+      fprintf(outfd,"%10.2f ",result);                /* 19,11 */
+    }
+    fprintf(outfd,"\n");
+    fflush(outfd);
+  }
+  /* end of printing dns per test instance results */
+}
+
+void
+process_sys_stats(tset_t *test_set, xmlNodePtr stats, xmlChar *tid)
+{
+  int            i;
+  int            count;
+  int            index;
+  FILE          *outfd;
+  dns_results_t *rd;
+  double         elapsed_seconds;
+  double         sys_util;
+  double         calibration;
+  double         local_idle;
+  double         local_busy;
+  double         local_cpus;
+
+#define MAX_SYS_CNTRS 10
+#define E_SEC         0
+#define E_USEC        1
+#define NUM_CPU       4
+#define CALIBRATE     5
+#define IDLE          6
+
+  double         sys_cntr[MAX_SYS_CNTRS];
+  const char *sys_cntr_name[] = {
+    "elapsed_sec",
+    "elapsed_usec",
+    "time_sec",
+    "time_usec",
+    "number_cpus",
+    "calibration",
+    "idle_count",
+    "",
+    "",
+    ""
+  };
+
+  rd     = test_set->report_data;
+  count  = test_set->confidence.count;
+  outfd  = rd->outfd;
+  index  = count - 1;
+
+  if (test_set->debug) {
+    fprintf(test_set->where,"\tprocessing sys_stats\n");
+    fflush(test_set->where);
+  }
+  for (i=0; i<MAX_SYS_CNTRS; i++) {
+    char *value_str =
+       (char *)xmlGetProp(stats, (const xmlChar *)sys_cntr_name[i]);
+    if (value_str) {
+      sys_cntr[i] = strtod(value_str,NULL);
+      if (sys_cntr[i] == 0.0) {
+        uint64_t x;
+        sscanf(value_str,"%llx",&x);
+        sys_cntr[i] = (double)x;
+      }
+    } else {
+      sys_cntr[i] = 0.0;
+    }
+    if (test_set->debug) {
+      fprintf(test_set->where,"\t%12s sys_stats[%d] = %10g '%s'\n",
+              sys_cntr_name[i], i, sys_cntr[i],
+              xmlGetProp(stats, (const xmlChar *)sys_cntr_name[i]));
+    }
+  }
+  local_cpus      = sys_cntr[NUM_CPU];
+  elapsed_seconds = sys_cntr[E_SEC] + sys_cntr[E_USEC]/1000000;
+  calibration     = sys_cntr[CALIBRATE];
+  local_idle      = sys_cntr[IDLE] / calibration;
+  local_busy      = (calibration-sys_cntr[IDLE])/calibration;
+
+  if (test_set->debug) {
+    fprintf(test_set->where,"\tnum_cpus        = %f\n",local_cpus);
+    fprintf(test_set->where,"\telapsed_seconds = %7.2f\n",elapsed_seconds);
+    fprintf(test_set->where,"\tidle_cntr       = %e\n",sys_cntr[IDLE]);
+    fprintf(test_set->where,"\tcalibrate_cntr  = %e\n",sys_cntr[CALIBRATE]);
+    fprintf(test_set->where,"\tlocal_idle      = %e\n",local_idle);
+    fprintf(test_set->where,"\tlocal_busy      = %e\n",local_busy);
+    fflush(test_set->where);
+  }
+  rd->utilization[index]  += local_busy;
+  if (rd->print_test) {
+    /* Display per test results */
+    fprintf(outfd,"%3d  ", count);                    /*  0,5 */
+    fprintf(outfd,"%-6s ",  tid);                     /*  5,7 */
+    fprintf(outfd,"%-6.2f ",elapsed_seconds);         /* 12,7 */
+    if (rd->sd_denominator != 1.0) {
+      fprintf(outfd,"%24s","");                       /* 19,24*/
+    } else {
+      fprintf(outfd,"%11s","");                       /* 19,11*/
+    }
+    fprintf(outfd,"%7.1e ",calibration);              /* 43,8 */
+    fprintf(outfd,"%6.3f ",local_idle*100.0);         /* 51,7 */
+    fprintf(outfd,"%6.3f ",local_busy*100.0);         /* 58,7 */
+    fprintf(outfd,"\n");                              /* 79,1 */
+    fflush(outfd);
+  }
+  /* end of printing sys stats instance results */
+}
+
+void
+process_stats_for_run(tset_t *test_set)
+{
+  dns_results_t *rd;
+  test_t        *test;
+  tset_elt_t    *set_elt;
+  xmlNodePtr     stats;
+  xmlNodePtr     prev_stats;
+  int            count; 
+  int            index; 
+ 
+  rd        = test_set->report_data;
+  set_elt   = test_set->tests;
+  count     = test_set->confidence.count;
+  index     = count - 1;
+
+  if (test_set->debug) {
+    fprintf(test_set->where,
+            "test_set %s has %d tests looking for statistics\n",
+            test_set->id,test_set->num_tests);
+    fflush(test_set->where);
+  }
+
+  if (test_set->debug) {
+    fprintf(test_set->where, "%s count = %d\n", __func__, count);
+    fflush(test_set->where);
+  }
+
+  rd->results[index]       =  0.0;
+  rd->xmit_results[index]  =  0.0;
+  rd->recv_results[index]  =  0.0;
+  rd->utilization[index]   =  0.0;
+  rd->servdemand[index]    =  0.0;
+  rd->run_time[index]      =  0.0;
+
+  while (set_elt != NULL) {
+    int stats_for_test;
+    test    = set_elt->test;
+    stats   = test->received_stats->xmlChildrenNode;
+    if (test_set->debug) {
+      if (stats) {
+        fprintf(test_set->where,
+                "\ttest %s has '%s' statistics\n",
+                test->id,stats->name);
+      } else {
+        fprintf(test_set->where,
+                "\ttest %s has no statistics available!\n",
+                test->id);
+      }
+      fflush(test_set->where);
+    }
+    stats_for_test = 0;
+    while(stats != NULL) {
+      /* process all the statistics records for this test */
+      if (test_set->debug) {
+        fprintf(test_set->where,"\tfound some statistics");
+        fflush(test_set->where);
+      }
+      if(!xmlStrcmp(stats->name,(const xmlChar *)"sys_stats")) {
+        /* process system statistics */
+        process_sys_stats(test_set, stats, test->id);
+        stats_for_test++;
+      }
+      if(!xmlStrcmp(stats->name,(const xmlChar *)"test_stats")) {
+        /* process test statistics */
+        process_test_stats(test_set, stats, test->id);
+        stats_for_test++;
+      }
+      /* other types of nodes just get skipped by this report routine */
+      /* delete statistics entry from test */
+      prev_stats = stats;
+      stats = stats->next;
+      xmlUnlinkNode(prev_stats);
+      xmlFreeNode(prev_stats);
+    }
+    /* should only have one stats record for each test otherwise error */
+    if (stats_for_test > 1) {
+      /* someone is playing games don't generate report*/
+      fprintf(test_set->where,
+              "More than one statistics measurement for test %d\n",
+              stats_for_test);
+      fprintf(test_set->where,
+              "%s was not designed to deal with this.\n",
+              __func__);
+      fprintf(test_set->where,
+              "exiting netperf now!!\n");
+      fflush(test_set->where);
+      exit;
+    }
+    set_elt = set_elt->next;
+  }
+  if (rd->result_minimum > rd->results[index]) {
+    rd->result_minimum = rd->results[index];
+  }
+  if (rd->result_maximum < rd->results[index]) {
+    rd->result_maximum = rd->results[index];
+  }
+}
+
+void
+update_results_and_confidence(tset_t *test_set)
+{
+  dns_results_t *rd;
+  double         confidence;
+  
+  rd        = test_set->report_data;
+
+    /* calculate confidence and summary result values */
+  confidence                    = get_confidence(rd->run_time,
+                                      &(test_set->confidence),
+                                      &(rd->ave_time));
+  rd->result_confidence         = get_confidence(rd->results,
+                                      &(test_set->confidence),
+                                      &(rd->result_measured_mean));
+  rd->cpu_util_confidence       = get_confidence(rd->utilization,
+                                      &(test_set->confidence),
+                                      &(rd->cpu_util_measured_mean));
+  rd->service_demand_confidence = get_confidence(rd->servdemand,
+                                      &(test_set->confidence),
+                                      &(rd->service_demand_measured_mean));
+  if (rd->result_confidence > rd->cpu_util_confidence) {
+    if (rd->cpu_util_confidence > rd->service_demand_confidence) {
+      confidence  = rd->service_demand_confidence;
+    } else {
+      confidence  = rd->cpu_util_confidence;
+    }
+  } else {
+    if (rd->result_confidence > rd->service_demand_confidence) {
+      confidence  = rd->service_demand_confidence;
+    } else {
+      confidence  = rd->result_confidence;
+    }
+  }
+  test_set->confidence.value = confidence;
+}
+
+void
+print_run_results(tset_t *test_set)
+{
+  dns_results_t *rd;
+  FILE          *outfd;
+  int            i;
+  int            count;
+  int            index;
+
+#define HDR_LINES 3
+  char *field1[HDR_LINES]   = { "INST",  "NUM",  " "       };   /* 4 */
+  char *field2[HDR_LINES]   = { "SET",   "Name", " "       };   /* 6 */
+  char *field3[HDR_LINES]   = { "RUN",   "Time", "sec"     };   /* 6 */
+  char *field4A[HDR_LINES]  = { "DATA",  "RATE", "mb/s"    };   /* 7 */
+  char *field4B[HDR_LINES]  = { "TRANS", "RATE", "tran/s"  };   /* 7 */
+  char *field5[HDR_LINES]   = { "XMIT",  "Rate", "mb/s"    };   /* 7 */
+  char *field6[HDR_LINES]   = { "RECV",  "Rate", "mb/s"    };   /* 7 */
+  char *field7[HDR_LINES]   = { "SD",    "usec", "/KB"     };   /* 7 */
+  char *field8[HDR_LINES]   = { "CPU",   "Util", "%/100"   };   /* 6 */
+#ifdef OFF
+  char *field9[HDR_LINES]   = { "???",   "???",  "???"     };   /* 6 */
+  char *field10[HDR_LINES]  = { "???",   "???",  "???"     };   /* 6 */
+  char *field11[HDR_LINES]  = { "???",   "???",  "???"     };   /* 6 */
+#endif
+
+  rd    = test_set->report_data;
+  count = test_set->confidence.count;
+  outfd = rd->outfd;
+  index = count - 1;
+  
+
+  /* Display per run header */
+  fprintf(outfd,"\n");
+  for (i=0;i < HDR_LINES; i++) {
+    fprintf(outfd,"%-4s ",field1[i]);                         /*  0,5 */
+    fprintf(outfd,"%-6s ",field2[i]);                         /*  5,7 */
+    fprintf(outfd,"%-6s ",field3[i]);                         /* 12,7 */
+    if (rd->sd_denominator != 1.0) {
+      fprintf(outfd,"%7s ",field4A[i]);                       /* 19,8 */
+      fprintf(outfd,"%7s ",field5[i]);                        /* 27,8 */
+      fprintf(outfd,"%7s ",field6[i]);                        /* 35,8 */
+    } else {
+      fprintf(outfd,"%10s ",field4B[i]);                      /* 19,11 */
+    }
+    fprintf(outfd,"%7s ",field7[i]);                          /* 43,8 */
+    fprintf(outfd,"%6s ",field8[i]);                          /* 51,7 */
+#ifdef OFF
+    fprintf(outfd,"%6s ",field9[i]);                          /* 58,7 */
+    fprintf(outfd,"%6s ",field10[i]);                         /* 65,7 */
+    fprintf(outfd,"%6s ",field11[i]);                         /* 72,7 */
+#endif
+    fprintf(outfd,"\n");
+  }
+  
+  /* Display per run results */
+  fprintf(outfd,"%-3d  ", count);                             /*  0,5 */
+  fprintf(outfd,"%-6s ",  test_set->id);                      /*  5,7 */
+  fprintf(outfd,"%-6.2f ",rd->run_time[index]);               /* 12,7 */
+  if (rd->sd_denominator != 1.0) {
+    fprintf(outfd,"%7.2f ",rd->results[index]);               /* 19,8 */
+    fprintf(outfd,"%7.2f ",rd->xmit_results[index]);          /* 27,8 */
+    fprintf(outfd,"%7.2f ",rd->recv_results[index]);          /* 35,8 */
+  } else {
+    fprintf(outfd,"%10.2f ",rd->results[index]);              /* 19,11*/
+  }
+  fprintf(outfd,"%7.3f ",rd->servdemand[index]);              /* 43,8 */
+  fprintf(outfd,"%6.4f ",rd->utilization[index]);             /* 51,7 */
+#ifdef OFF
+  fprintf(outfd,"%6.4f ",something to be added later);        /* 58,7 */
+  fprintf(outfd,"%6.4f ",something to be added later);        /* 65,7 */
+  fprintf(outfd,"%6.4f ",something to be added later);        /* 72,7 */
+#endif
+  fprintf(outfd,"\n");                                        /* 79,1 */
+  fflush(outfd);
+}
+
+void
+print_results_summary(tset_t *test_set)
+{
+  dns_results_t *rd;
+  FILE          *outfd;
+  int            i;
+
+#define HDR_LINES 3
+                                                                /* field
+                                                                   width*/
+  char *field1[HDR_LINES]   = { "AVE",   "Over", "Num"     };   /* 4 */
+  char *field2[HDR_LINES]   = { "SET",   "Name", " "       };   /* 6 */
+  char *field3[HDR_LINES]   = { "TEST",  "Time", "sec"     };   /* 6 */
+  char *field4A[HDR_LINES]  = { "DATA",  "RATE", "mb/s"    };   /* 7 */
+  char *field5A[HDR_LINES]  = { "conf",  "+/-",  "mb/s"    };   /* 7 */
+  char *field6A[HDR_LINES]  = { "Min",   "Rate", "mb/s"    };   /* 7 */
+  char *field7A[HDR_LINES]  = { "Max",   "Rate", "mb/s"    };   /* 7 */
+  char *field8[HDR_LINES]   = { "CPU",   "Util", "%/100"   };   /* 6 */
+  char *field9[HDR_LINES]   = { "+/-",   "Util", "%/100"   };   /* 6 */
+  char *field10A[HDR_LINES] = { "SD",    "usec", "/KB"     };   /* 6 */
+  char *field11A[HDR_LINES] = { "+/-",   "usec", "/KB"     };   /* 6 */
+
+  char *field4B[HDR_LINES]  = { "TRANS", "RATE", "tran/s"  };   /* 7 */
+  char *field5B[HDR_LINES]  = { "conf",  "+/-",  "tran/s"  };   /* 7 */
+  char *field6B[HDR_LINES]  = { "Min",   "Rate", "tran/s"  };   /* 7 */
+  char *field7B[HDR_LINES]  = { "Max",   "Rate", "tran/s"  };   /* 7 */
+
+  char *field10B[HDR_LINES] = { "SD",    "usec", "/tran"   };   /* 6 */
+  char *field11B[HDR_LINES] = { "+/-",   "usec", "/tran"   };   /* 6 */
+
+  char *field4[HDR_LINES];
+  char *field5[HDR_LINES];
+  char *field6[HDR_LINES];
+  char *field7[HDR_LINES];
+
+  char *field10[HDR_LINES];
+  char *field11[HDR_LINES];
+  
+  rd    = test_set->report_data;
+  outfd = rd->outfd;
+
+  if (rd->sd_denominator != 1.0) {
+    for (i = 0; i < HDR_LINES; i++) {
+      field4[i]  = field4A[i];
+      field5[i]  = field5A[i];
+      field6[i]  = field6A[i];
+      field7[i]  = field7A[i];
+      field10[i] = field10A[i];
+      field11[i] = field11A[i];
+    }
+  } else {
+    for (i = 0; i < HDR_LINES; i++) {
+      field4[i]  = field4B[i];
+      field5[i]  = field5B[i];
+      field6[i]  = field6B[i];
+      field7[i]  = field7B[i];
+      field10[i] = field10B[i];
+      field11[i] = field11B[i];
+    }
+  }
+
+  /* Print the summary header */
+  fprintf(outfd,"\n");
+  for (i = 0; i < HDR_LINES; i++) {
+    fprintf(outfd,"%-4s ",field1[i]);                             /*  0,5 */
+    fprintf(outfd,"%-6s ",field2[i]);                             /*  5,7 */
+    fprintf(outfd,"%-6s ",field3[i]);                             /* 12,7 */
+    fprintf(outfd,"%7s ",field4[i]);                              /* 19,8 */
+    fprintf(outfd,"%7s ",field5[i]);                              /* 27,8 */
+    fprintf(outfd,"%7s ",field6[i]);                              /* 35,8 */
+    fprintf(outfd,"%7s ",field7[i]);                              /* 43,8 */
+    fprintf(outfd,"%6s ",field8[i]);                              /* 51,7 */
+    fprintf(outfd,"%6s ",field9[i]);                              /* 58,7 */
+    fprintf(outfd,"%6s ",field10[i]);                             /* 65,7 */
+    fprintf(outfd,"%6s ",field11[i]);                             /* 72,7 */
+    fprintf(outfd,"\n");
+  }
+  
+  /* print the summary results line */
+  fprintf(outfd,"A%-3d ",test_set->confidence.count);             /*  0,5 */
+  fprintf(outfd,"%-6s ",test_set->id);                            /*  5,7 */
+  fprintf(outfd,"%-6.2f ",rd->ave_time);                          /* 12,7 */
+  if (rd->sd_denominator != 1.0) {
+    fprintf(outfd,"%7.2f ",rd->result_measured_mean);             /* 19,8 */
+    fprintf(outfd,"%7.3f ",rd->result_confidence);                /* 27,8 */
+    fprintf(outfd,"%7.2f ",rd->result_minimum);                   /* 35,8 */
+    fprintf(outfd,"%7.2f ",rd->result_maximum);                   /* 43,8 */
+  } else {
+    fprintf(outfd,"%7.0f ",rd->result_measured_mean);             /* 19,8 */
+    fprintf(outfd,"%7.2f ",rd->result_confidence);                /* 27,8 */
+    fprintf(outfd,"%7.0f ",rd->result_minimum);                   /* 35,8 */
+    fprintf(outfd,"%7.0f ",rd->result_maximum);                   /* 43,8 */
+  }
+  fprintf(outfd,"%6.4f ",rd->cpu_util_measured_mean);             /* 51,7 */
+  fprintf(outfd,"%6.4f ",rd->cpu_util_confidence);                /* 58,7 */
+  fprintf(outfd,"%6.3f ",rd->service_demand_measured_mean);       /* 65,7 */
+  fprintf(outfd,"%6.3f ",rd->service_demand_confidence);          /* 72,7 */
+  fprintf(outfd,"\n");                                            /* 79,1 */
+  fflush(outfd);
+}
+
+void
+report_dns_test_results(tset_t *test_set, char *report_flags, char *output)
+{
+  dns_results_t *rd;
+  int count;
+  int max_count;
+  int min_count;
+
+  rd  = test_set->report_data;
+
+  if (rd == NULL) {
+    dns_test_results_init(test_set,report_flags,output);
+    rd  = test_set->report_data;
+  }
+    
+  /* process statistics for this run */
+  process_stats_for_run(test_set);
+  /* calculate confidence and summary result values */
+  update_results_and_confidence(test_set);
+
+  if (rd->print_run) {
+    print_run_results(test_set);
+  }
+
+  count        = test_set->confidence.count;
+  max_count    = test_set->confidence.max_count;
+  min_count    = test_set->confidence.min_count;
+  /* always print summary results at end of last call through loop */
+  if (count == max_count) {
+
+/*  if ((count == max_count) || 
+      ((rd->confidence >= 0) && (count >= min_count))) */
+
+    print_results_summary(test_set);
+  }
+} /* end of report_dns_test_results */
+

Added: trunk/src/nettest_dns.h
===================================================================
--- trunk/src/nettest_dns.h	2005-11-17 04:53:38 UTC (rev 19)
+++ trunk/src/nettest_dns.h	2005-11-18 19:45:00 UTC (rev 20)
@@ -0,0 +1,162 @@
+/*        Copyright (C) 2005 Hewlett-Packard Company */
+
+/*
+
+This file is part of netperf4.
+
+Netperf4 is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+Netperf4 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of netperf4 with the OpenSSL project's
+"OpenSSL" library (or with modified versions of it that use the same
+license as the "OpenSSL" library), and distribute the linked
+executables.  You must obey the GNU General Public License in all
+respects for all of the code used other than "OpenSSL".  If you modify
+this file, you may extend this exception to your version of the file,
+but you are not obligated to do so.  If you do not wish to do so,
+delete this exception statement from your version.
+
+*/
+
+/* This file contains the test-specific definitions for netperf4's DNS
+   tests */
+
+enum {
+  SEND_CALLS = 0,
+  BYTES_SENT,
+  RECV_CALLS,
+  BYTES_RECEIVED,
+  TRANS_SENT,
+  TRANS_RECEIVED,
+  CONNECT_CALLS,
+  ACCEPT_CALLS,
+  DNS_MAX_COUNTERS
+};
+
+/* we don't have an ID field because that will be implicit in the
+   array index - at least at first until we decide that is consuming
+   too much memory or something :) raj 2005-11-17 */
+
+/* I wonder if we can ass-u-me that checking against the request id is
+   sufficient or if we need to also check against stuff like the type
+   and the class? raj 2005-11-17 */
+
+  /* until we get the gethrtime() stuff done, this will be a struct
+     timeval and... this should probably really be in netperf.h... */
+#define NETPERF_TIMESTAMP_T struct timeval
+#define NETPERF_TIME_STAMP(s) gettimeofday(&(s),NULL);
+
+typedef struct dns_request_status {
+  unsigned short active; /* was there a query sent with this id for
+		 which we are awaiting a response */
+  unsigned short success; /* should the request have been successful
+			     or not */
+  NETPERF_TIMESTAMP_T sent_time;
+} dns_request_status_t;
+
+typedef struct  dns_test_data {
+  /* address information */
+  struct addrinfo *locaddr;        /* local address informtion */
+  struct addrinfo *remaddr;        /* remote address informtion */
+
+  FILE            *request_source; /* pointer to file from which we
+				      pull requests */
+
+  int              query_socket;   /* socket for sending queries */
+
+  /* misc parameters */
+  int   use_tcp;        /* should queries be sent on a tcp connection */
+  int   no_delay;       /* do we disable the nagle algorithm for send */
+  int   keepalive;      /* do we keep the TCP connection open */
+  int   sbuf_size_ret;  /* send socket buffer size returned on creation */
+  int   send_buf_size;  /* send socket buffer size */
+  int   rbuf_size_ret;  /* receive socket buffer size returned on creation */
+  int   recv_buf_size;  /* receive socket buffer size */
+
+  uint16_t  request_id; /* this is used to match requests with
+			   responses and serves as the index into the
+			   outstanding queries array */
+
+  dns_request_status_t outstanding_requests[UINT16_MAX];
+
+  /* Statistics Counters - they should all be uint64_t */
+  union {
+    uint64_t  counter[DNS_MAX_COUNTERS];
+    struct {
+      uint64_t  queries_sent; /* the number of queries sent */
+      uint64_t  query_bytes_sent;   /* their byte count */
+      uint64_t  responses_received; /* the number of responses
+				       received */
+      uint64_t  response_bytes_received; /* their byte count */
+      uint64_t  connect_calls;
+    } named;
+  } stats;
+  struct timeval  elapsed_time;
+  struct timeval  prev_time;
+  struct timeval  curr_time;
+
+  /* Place for HISTOGRAM fields */
+  HIST time_hist;
+} dns_data_t;
+
+typedef struct  dns_results_data {
+  int     max_count;
+  int     print_test;
+  int     print_run;
+  FILE   *outfd;
+  double *results;
+  double *xmit_results;
+  double *recv_results;
+  double *trans_results;
+  double *utilization;
+  double *servdemand;
+  double *run_time;
+  double ave_time;
+  double result_measured_mean;
+  double result_confidence;
+  double result_minimum;
+  double result_maximum;
+  double cpu_util_measured_mean;
+  double cpu_util_confidence;
+  double service_demand_measured_mean;
+  double service_demand_confidence;
+  double confidence;
+  double sd_denominator;
+  double results_start;  /* must be the last field in structure */
+} dns_results_t;
+
+/* Error codes to be used within nettest_dns */
+enum {
+  DNSE_MAX_ERROR = -32,
+  DNSE_SOCKET_SHUTDOWN_FAILED,
+  DNSE_BIND_FAILED,
+  DNSE_GETADDRINFO_ERROR,
+  DNSE_XMLSETPROP_ERROR,
+  DNSE_XMLNEWNODE_ERROR,
+  DNSE_NO_SOCKET_ARGS,
+  DNSE_SOCKET_ERROR,
+  DNSE_SETSOCKOPT_ERROR,
+  DNSE_LISTEN_FAILED,
+  DNSE_GETSOCKNAME_FAILED,
+  DNSE_REQUESTED_STATE_INVALID,
+  DNSE_ACCEPT_FAILED,
+  DNSE_DATA_RECV_ERROR,
+  DNSE_TEST_STATE_CORRUPTED,
+  DNSE_CONNECT_FAILED,
+  DNSE_DATA_CONNECTION_CLOSED_ERROR,
+  DNSE_DATA_SEND_ERROR=-1,
+  DNSE_SUCCESS = 0
+};



More information about the netperf-dev mailing list