[netperf-dev] netperf4 commit notice r216 - in trunk/suites: . multi
raj at netperf.org
raj at netperf.org
Thu Mar 15 13:52:05 PST 2007
Author: raj
Date: 2007-03-15 13:52:04 -0800 (Thu, 15 Mar 2007)
New Revision: 216
Added:
trunk/suites/multi/
trunk/suites/multi/Makefile.am
trunk/suites/multi/Makefile.in
trunk/suites/multi/driver.c
trunk/suites/multi/multi_driver.c
trunk/suites/multi/nettest_multi.c
trunk/suites/multi/nettest_multi.h
trunk/suites/multi/prototype.c
Log:
allow configure to work by checking-in the incomplete multi tests
Added: trunk/suites/multi/Makefile.am
===================================================================
--- trunk/suites/multi/Makefile.am 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/Makefile.am 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,7 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+# in theory, the stuff below should deal with creating the requisite libs
+lib_LTLIBRARIES = nettest_multi.la
+
+nettest_multi_la_SOURCES = nettest_multi.c nettest_multi.h
+nettest_multi_la_LDFLAGS = -module
Added: trunk/suites/multi/Makefile.in
===================================================================
--- trunk/suites/multi/Makefile.in 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/Makefile.in 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,460 @@
+# Makefile.in generated by automake 1.7.9 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBOJBS = @LIBOJBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+NETSYS_SOURCE = @NETSYS_SOURCE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WANT_DISK_FALSE = @WANT_DISK_FALSE@
+WANT_DISK_TRUE = @WANT_DISK_TRUE@
+WANT_DNS_FALSE = @WANT_DNS_FALSE@
+WANT_DNS_TRUE = @WANT_DNS_TRUE@
+WANT_MULTI_FALSE = @WANT_MULTI_FALSE@
+WANT_MULTI_TRUE = @WANT_MULTI_TRUE@
+WANT_VST_FALSE = @WANT_VST_FALSE@
+WANT_VST_TRUE = @WANT_VST_TRUE@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+# in theory, the stuff below should deal with creating the requisite libs
+lib_LTLIBRARIES = nettest_multi.la
+
+nettest_multi_la_SOURCES = nettest_multi.c nettest_multi.h
+nettest_multi_la_LDFLAGS = -module
+subdir = suites/multi
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(lib_LTLIBRARIES)
+
+nettest_multi_la_LIBADD =
+am_nettest_multi_la_OBJECTS = nettest_multi.lo
+nettest_multi_la_OBJECTS = $(am_nettest_multi_la_OBJECTS)
+
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+ at AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/nettest_multi.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(nettest_multi_la_SOURCES)
+DIST_COMMON = $(srcdir)/Makefile.in Makefile.am
+SOURCES = $(nettest_multi_la_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu suites/multi/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+libLTLIBRARIES_INSTALL = $(INSTALL)
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \
+ $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" = "$$p" && dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+nettest_multi.la: $(nettest_multi_la_OBJECTS) $(nettest_multi_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(nettest_multi_la_LDFLAGS) $(nettest_multi_la_OBJECTS) $(nettest_multi_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_multi.Plo at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+ at am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+ at am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+ at am__fastdepCC_TRUE@ fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+ at am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+ at am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+ at am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+ at am__fastdepCC_TRUE@ fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+
+.c.lo:
+ at am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+ at am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+ at am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \
+ at am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+ at am__fastdepCC_TRUE@ fi
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-info-am \
+ uninstall-libLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Added: trunk/suites/multi/driver.c
===================================================================
--- trunk/suites/multi/driver.c 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/driver.c 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,108 @@
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+void
+dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+ char *host, char *port, int family)
+{
+ struct sockaddr *ai_addr;
+ struct addrinfo *temp;
+ temp=info;
+
+ fprintf(dumploc,
+ "getaddrinfo returned the following for host '%s' ",
+ host ? (char *)host : "n/a");
+ fprintf(dumploc,
+ "port '%s' ",
+ port ? (char *)port : "n/a");
+ fprintf(dumploc, "family %d\n", family);
+ while (temp) {
+ /* I was under the impression that fprintf would be kind with
+ things like NULL string pointers, but when porting to Solaris,
+ this started dumping core, so we start to workaround it. raj
+ 2006-06-29 */
+ fprintf(dumploc,
+ "\tcannonical name: '%s'\n",
+ temp->ai_canonname ? temp->ai_canonname : "n/a");
+ fprintf(dumploc,
+ "\tflags: %x family: %d: socktype: %d protocol %d addrlen %d\n",
+ temp->ai_flags,
+ temp->ai_family,
+ temp->ai_socktype,
+ temp->ai_protocol,
+ temp->ai_addrlen);
+ ai_addr = temp->ai_addr;
+ if (ai_addr != NULL) {
+ fprintf(dumploc,
+ "\tsa_family: %d sadata: %d %d %d %d %d %d\n",
+ ai_addr->sa_family,
+ (u_char)ai_addr->sa_data[0],
+ (u_char)ai_addr->sa_data[1],
+ (u_char)ai_addr->sa_data[2],
+ (u_char)ai_addr->sa_data[3],
+ (u_char)ai_addr->sa_data[4],
+ (u_char)ai_addr->sa_data[5]);
+ }
+ temp = temp->ai_next;
+ }
+ fflush(dumploc);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+ int sock;
+ int ret;
+ int trans = 0;
+ char buf[128];
+
+ struct sockaddr_in to;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sock < 0) {
+ perror("socket");
+ exit(-1);
+ }
+
+ bzero(&to,sizeof(to));
+
+ to.sin_family = AF_INET;
+ to.sin_port = htons(atoi(argv[2]));
+ to.sin_addr.s_addr = inet_addr(argv[1]);
+
+ ret = connect(sock,(struct sockaddr *)&to,sizeof(to));
+
+ if (ret < 0) {
+ perror("connect");
+ exit(-1);
+ }
+
+ while (1) {
+
+ ret = send(sock,buf,1,0);
+
+ if (ret < 0) {
+ break;
+ }
+
+ ret = recv(sock,buf,1,0);
+
+ if (ret < 0) {
+ break;
+ }
+ trans++;
+ }
+ perror("out of loop");
+ printf("trans %d\n",trans);
+}
Added: trunk/suites/multi/multi_driver.c
===================================================================
--- trunk/suites/multi/multi_driver.c 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/multi_driver.c 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,833 @@
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int debug = 0;
+
+#define SOCKET int
+#define netperf_socklen_t socklen_t
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define CLOSE_SOCKET close
+
+/* connection FLAGS */
+#define CONNECTION_LISTENING 0x1
+#define CONNECTION_READING 0x2
+#define CONNECTION_WRITING 0x4
+#define CONNECTION_CLOSING 0x8
+
+typedef struct connection {
+ void *next;
+ void *prev;
+ void *buffer_base;
+ char *buffer_curr;
+ int sock;
+ int bytes_total;
+ int bytes_remaining;
+ int bytes_completed;
+ unsigned int flags;
+ int buffer_size;
+} connection_t;
+
+
+void
+dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+ char *host, char *port, int family)
+{
+ struct sockaddr *ai_addr;
+ struct addrinfo *temp;
+ temp=info;
+
+ fprintf(dumploc,
+ "getaddrinfo returned the following for host '%s' ",
+ host ? (char *)host : "n/a");
+ fprintf(dumploc,
+ "port '%s' ",
+ port ? (char *)port : "n/a");
+ fprintf(dumploc, "family %d\n", family);
+ while (temp) {
+ /* I was under the impression that fprintf would be kind with
+ things like NULL string pointers, but when porting to Solaris,
+ this started dumping core, so we start to workaround it. raj
+ 2006-06-29 */
+ fprintf(dumploc,
+ "\tcannonical name: '%s'\n",
+ temp->ai_canonname ? temp->ai_canonname : "n/a");
+ fprintf(dumploc,
+ "\tflags: %x family: %d: socktype: %d protocol %d addrlen %d\n",
+ temp->ai_flags,
+ temp->ai_family,
+ temp->ai_socktype,
+ temp->ai_protocol,
+ temp->ai_addrlen);
+ ai_addr = temp->ai_addr;
+ if (ai_addr != NULL) {
+ fprintf(dumploc,
+ "\tsa_family: %d sadata: %d %d %d %d %d %d\n",
+ ai_addr->sa_family,
+ (u_char)ai_addr->sa_data[0],
+ (u_char)ai_addr->sa_data[1],
+ (u_char)ai_addr->sa_data[2],
+ (u_char)ai_addr->sa_data[3],
+ (u_char)ai_addr->sa_data[4],
+ (u_char)ai_addr->sa_data[5]);
+ }
+ temp = temp->ai_next;
+ }
+ fflush(dumploc);
+}
+
+SOCKET
+establish_connection(char *hostname, char *service, int af, netperf_socklen_t *addrlenp)
+{
+ SOCKET sockfd;
+ int error;
+ int count;
+ int len = *addrlenp;
+ int one = 1;
+ struct addrinfo hints, *res, *res_temp;
+
+ if (debug) {
+ fprintf(stderr,
+ "establish_connection: host '%s' service '%s' af %d socklen %d\n",
+ hostname ? hostname : "n/a",
+ service ? service : "n/a",
+ af,
+ len);
+ fflush(stderr);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+
+ count = 0;
+ do {
+ error = getaddrinfo(hostname,
+ service,
+ &hints,
+ &res);
+ count += 1;
+ if (error == EAI_AGAIN) {
+ if (debug) {
+ fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n");
+ fflush(stderr);
+ }
+ usleep(1000);
+ }
+ } while ((error == EAI_AGAIN) && (count <= 5));
+
+ if (error) {
+ fprintf(stderr,
+ "establish_connection: could not resolve host '%s' service '%s'\n",
+ hostname,service);
+ fprintf(stderr,"\tgetaddrinfo returned %d %s\n",
+ error,gai_strerror(error));
+ fflush(stderr);
+ return(-1);
+ }
+
+
+ if (debug) {
+ dump_addrinfo(stderr, res, hostname,
+ service, AF_UNSPEC);
+ }
+
+ res_temp = res;
+
+ do {
+
+ sockfd = socket(res_temp->ai_family,
+ res_temp->ai_socktype,
+ res_temp->ai_protocol);
+ if (sockfd == INVALID_SOCKET) {
+ if (debug) {
+ fprintf(stderr,"establish_connection: socket error trying next one\n");
+ fflush(stderr);
+ }
+ continue;
+ }
+ /* The Windows DDK compiler is quite picky about pointers so we
+ cast one as a void to placate it. */
+ if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&one,sizeof(one)) ==
+ SOCKET_ERROR) {
+ fprintf(stderr,"establish_connection: SO_REUSEADDR failed\n");
+ fflush(stderr);
+ }
+ if (connect(sockfd, res_temp->ai_addr, res_temp->ai_addrlen) == 0) {
+ break;
+ }
+ fprintf(stderr,"establish_connection: connect error close and try next\n");
+ fflush(stderr);
+ CLOSE_SOCKET(sockfd);
+ } while ( (res_temp = res_temp->ai_next) != NULL );
+
+ if (res_temp == NULL) {
+ fprintf(stderr,"establish_connection: allocate server socket failed\n");
+ fflush(stderr);
+ sockfd = -1;
+ }
+ else {
+ if (addrlenp) *addrlenp = res_temp->ai_addrlen;
+ }
+
+ fcntl(sockfd,F_SETFL, O_NONBLOCK);
+
+ freeaddrinfo(res);
+
+ return (sockfd);
+
+}
+
+typedef struct event_state_select {
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ int numfds;
+ int maxfd;
+ int minfd;
+} event_state_select_t;
+
+void *
+init_event_state() {
+ event_state_select_t *temp;
+
+ if (debug) {
+ fprintf(stderr,"Initializing event state\n");
+ }
+ temp = (event_state_select_t *)malloc(sizeof(event_state_select_t));
+ if (temp) {
+ FD_ZERO(&(temp->readfds));
+ FD_ZERO(&(temp->writefds));
+ FD_ZERO(&(temp->exceptfds));
+ }
+ temp->numfds = 0;
+ temp->maxfd = -1;
+ temp->minfd = -1;
+ if (debug) {
+ fprintf(stderr,
+ "Initialized event state at %p, readfds at %p\n",
+ temp,
+ &(temp->readfds));
+ }
+ return temp;
+}
+
+int
+clear_all_events(void *event_state, SOCKET sock) {
+
+ int i;
+ event_state_select_t *temp = event_state;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to clear sock %d from the event set at %p\n",
+ sock,
+ event_state);
+ }
+
+ FD_CLR(sock,&(temp->readfds));
+ FD_CLR(sock,&(temp->writefds));
+ FD_CLR(sock,&(temp->exceptfds));
+
+ temp->numfds -= 1;
+
+ if (debug) {
+ fprintf(stderr,
+ "initiating maxfd_check sock %d temp->maxfd %d\n",
+ sock,
+ temp->maxfd);
+ }
+
+ if (sock == temp->maxfd) {
+ for (i = temp->maxfd; i >= 0; i--) {
+ if (FD_ISSET(i,&(temp->readfds)) ||
+ FD_ISSET(i,&(temp->writefds)) ||
+ FD_ISSET(i, &(temp->exceptfds))) {
+ temp->maxfd = i;
+ if (debug) {
+ fprintf(stderr,"maxfd is now %d\n",i);
+ }
+ break;
+ }
+ }
+ }
+ else if (sock == temp->minfd) {
+ for (i = temp->minfd; i < FD_SETSIZE; i++) {
+ if (FD_ISSET(i,&(temp->readfds)) ||
+ FD_ISSET(i,&(temp->writefds)) ||
+ FD_ISSET(i, &(temp->exceptfds))) {
+ temp->minfd = i;
+ if (debug) {
+ fprintf(stderr,"maxfd is now %i\n",i);
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+
+}
+int
+set_readable_event(void *event_state, SOCKET sock) {
+ event_state_select_t *temp;
+ temp = event_state;
+ if (debug) {
+ fprintf(stderr,"requesting readability for socket %d\n",sock);
+ }
+ if (!FD_ISSET(sock,&(temp->readfds))) {
+ FD_SET(sock,&(temp->readfds));
+ temp->numfds += 1;
+ temp->maxfd = (sock > temp->maxfd) ? sock : temp->maxfd;
+ temp->minfd = (sock < temp->minfd) ? sock : temp->minfd;
+ }
+ if (debug) {
+ fprintf(stderr,"minfd is now %d maxfd is now %d\n",
+ temp->minfd,
+ temp->maxfd);
+ }
+ return 0;
+}
+
+int
+set_writable_event(void *event_state, SOCKET sock) {
+ event_state_select_t *temp;
+ temp = event_state;
+ if (debug) {
+ fprintf(stderr,"requesting writability for socket %d\n",sock);
+ }
+ if (!FD_ISSET(sock,&(temp->writefds))) {
+ FD_SET(sock,&(temp->writefds));
+ temp->numfds += 1;
+ temp->maxfd = (sock > temp->maxfd) ? sock : temp->maxfd;
+ temp->minfd = (sock < temp->maxfd) ? sock : temp->maxfd;
+ }
+ if (debug) {
+ fprintf(stderr,"maxfd is now %d\n",temp->maxfd);
+ }
+ return 0;
+}
+
+typedef struct uber_state {
+ connection_t *connection_list;
+ void *event_state;
+ int rdwr_since_accept;
+} uber_state_t;
+
+connection_t *
+find_connection(uber_state_t *uber_state, SOCKET sock) {
+
+ connection_t *temp;
+
+ temp = uber_state->connection_list;
+
+ if (debug) {
+ fprintf(stderr,
+ "searching connection list starting from %p for %d\n",temp,sock);
+ }
+ while (temp) {
+ if (debug) {
+ fprintf(stderr,"examining connection %p whose sock is %d\n",
+ temp,
+ temp->sock);
+ }
+ if (temp->sock == sock) break;
+ temp = temp->next;
+ }
+
+ if (debug) {
+ fprintf(stderr,"returning %p from find_connection\n",temp);
+ }
+ return temp;
+
+}
+int
+wait_for_events_and_walk(uber_state_t *uber_state) {
+ struct timeval timeout;
+ event_state_select_t *event_state = uber_state->event_state;
+
+ fd_set loc_readfds;
+ fd_set loc_writefds;
+
+ connection_t *temp_connection;
+
+ int ret;
+ int i;
+ int did_something;
+
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+
+ if (debug) {
+ fprintf(stderr,"about to go into select\n");
+ }
+
+ /* rather blunt, but should be effective for now */
+ memcpy(&loc_readfds, &(event_state->readfds),sizeof(fd_set));
+ memcpy(&loc_writefds, &(event_state->writefds),sizeof(fd_set));
+
+ ret = select(event_state->maxfd + 1,
+ &loc_readfds,
+ &loc_writefds,
+ NULL, /* ignore exception for now */
+ &timeout);
+
+ if (debug) {
+ fprintf(stderr,
+ "select returned %d errno %d minfd %d maxfd %d\n",
+ ret,
+ errno,
+ event_state->minfd,
+ event_state->maxfd);
+ }
+
+ if (ret > 0) {
+ /* first, the reads and accepts */
+ for (i = event_state->minfd; i <= event_state->maxfd; i++) {
+ if (FD_ISSET(i,&loc_readfds)) {
+ temp_connection = find_connection(uber_state,i);
+ if (debug) {
+ fprintf(stderr,
+ "fd %d is readable on connection %p\n",
+ i,
+ temp_connection);
+ }
+ /* is this our listen endpoint or something else? */
+ if (temp_connection->flags & CONNECTION_LISTENING ) {
+ /* accept a connection */
+ SOCKET new_sock;
+ new_sock = accept_new_connection(uber_state,
+ temp_connection);
+ if (INVALID_SOCKET != new_sock) {
+ /* on the very good chance that this new connection is for
+ an FD higher than our listen endpoint, we set
+ loc_readfds so we go ahead and try to read from the new
+ connection when we get to that point in our walk of the
+ fdset returned from select(). */
+ FD_SET(new_sock,&loc_readfds);
+ }
+ /* if we got one connection, we should see about draining
+ the accept queue, eventually module some limit on the
+ number of concurrent connections we will allow */
+ while (new_sock >= 0) {
+ new_sock = accept_new_connection(uber_state,
+ temp_connection);
+ if (INVALID_SOCKET != new_sock) {
+ /* on the very good chance that this new connection is for
+ an FD higher than our listen endpoint, we set
+ loc_readfds so we go ahead and try to read from the new
+ connection when we get to that point in our walk of the
+ fdset returned from select(). */
+ FD_SET(new_sock,&loc_readfds);
+ }
+ }
+ }
+ else if (temp_connection->flags & CONNECTION_READING) {
+ /* read some bytes */
+ }
+ else {
+ /* something screwy happened */
+ fprintf(stderr,
+ "YO, we got readable on connection %p but we weren't reading\n",
+ temp_connection);
+ }
+ }
+ }
+
+ /* now the writes */
+ for (i = event_state->minfd; i <= event_state->maxfd; i++) {
+ if (FD_ISSET(i,&loc_writefds)) {
+ temp_connection = find_connection(uber_state,i);
+ if (debug > 2) {
+ fprintf(stderr,
+ "fd %d is writable on connection %p\n",i,temp_connection);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+remove_old_connection(uber_state_t *uber_state, connection_t *old_connection) {
+
+ connection_t *prev_conn = NULL;
+ connection_t *curr_conn;
+
+ curr_conn = uber_state->connection_list;
+
+ while (NULL != curr_conn) {
+ if (curr_conn == old_connection) {
+ /* we have a match */
+ if (NULL != prev_conn) {
+ /* we were somewhere in the middle, or at the end */
+ prev_conn->next = curr_conn->next;
+ }
+ else {
+ /* we were at the beginning */
+ uber_state->connection_list = curr_conn->next;
+ }
+ break;
+ }
+ else {
+ prev_conn = curr_conn;
+ curr_conn = curr_conn->next;
+ }
+ }
+ /* whether we have found it in the list or not, we want to free the
+ buffers and the connection entry */
+ free(old_connection->buffer_base);
+ free(old_connection);
+
+ return 0;
+
+}
+connection_t *
+add_new_connection(uber_state_t *uber_state, SOCKET init_socket, int flags, int initial_buf_size) {
+ connection_t *temp_conn;
+
+ temp_conn = malloc(sizeof(connection_t));
+ if (NULL != temp_conn) {
+ temp_conn->sock = init_socket;
+ temp_conn->bytes_total = 1;
+ temp_conn->bytes_remaining = 1;
+ temp_conn->bytes_completed = 0;
+ temp_conn->flags = flags;
+ temp_conn->buffer_size = initial_buf_size;
+ temp_conn->buffer_base = NULL;
+ temp_conn->buffer_size = 0;
+ /* if the caller asked for an initial buffer to be allocated,
+ allocate one */
+ if (initial_buf_size > 0) {
+ temp_conn->buffer_base = malloc(initial_buf_size);
+ if (NULL != temp_conn->buffer_base) {
+ temp_conn->buffer_size = initial_buf_size;
+ }
+ }
+ /* doesn't matter here if buffer_base is NULL */
+ temp_conn->buffer_curr = temp_conn->buffer_base;
+ temp_conn->next = uber_state->connection_list;
+ uber_state->connection_list = temp_conn;
+ }
+ if (flags & (CONNECTION_READING | CONNECTION_LISTENING)) {
+ set_readable_event(uber_state->event_state,init_socket);
+ }
+ if (flags & CONNECTION_WRITING) {
+ set_writable_event(uber_state->event_state,init_socket);
+ }
+
+ return temp_conn;
+}
+
+int
+accept_new_connection(uber_state_t *uber_state, connection_t *listen_connection)
+{
+ SOCKET new_conn;
+ connection_t *new_connection;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to accept on connection %p fd %d\n",
+ listen_connection,
+ listen_connection->sock);
+ }
+
+ /* we don't care if the accept actually accepted a new connection,
+ just that we tried calling accept. */
+ uber_state->rdwr_since_accept = 0;
+
+
+ new_conn = accept(listen_connection->sock,NULL,NULL);
+
+ if (INVALID_SOCKET != new_conn) {
+
+ /* one day we will want to see if this is inherited across
+ accept() calls, but for now we just go ahead and make the
+ call */
+
+ fcntl(new_conn,F_SETFL, O_NONBLOCK);
+
+ new_connection = add_new_connection(uber_state,
+ new_conn,
+ CONNECTION_READING,
+ 128);
+ if (debug) {
+ fprintf(stderr,
+ "accepted a connection to %p on fd %d\n",
+ new_connection,
+ new_conn);
+ }
+ }
+
+ return new_conn;
+}
+
+int
+close_a_connection(uber_state_t *uber_state, connection_t *close_connection) {
+
+ int ret;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to close connection %p\n",
+ close_connection);
+ }
+
+ ret = close(close_connection->sock);
+ if (debug) {
+ fprintf(stderr,"close_connection thinks event_state is %p\n",
+ uber_state->event_state);
+ }
+ ret = clear_all_events(uber_state->event_state,close_connection->sock);
+ /* mark the connection for removal at some later time, don't remove
+ it here because we may be called from a loop that is walking the
+ connection list */
+ close_connection->flags = CONNECTION_CLOSING;
+
+ /* ret = remove_old_connection(uber_state, close_connection); */
+
+ return 0;
+}
+
+int
+write_on_connection(uber_state_t *uber_state, connection_t *write_connection) {
+
+ int bytes_written;
+ int did_something=1;
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "about to write on connection %p\n",write_connection);
+ }
+
+ /* actually writing bytes doesn't matter, just that we tried */
+ uber_state->rdwr_since_accept += 1;
+
+ bytes_written = send(write_connection->sock,
+ write_connection->buffer_curr,
+ write_connection->bytes_remaining,
+ 0);
+
+ if (bytes_written > 0) {
+ /* wrote something, was it everything? */
+ write_connection->bytes_remaining -= bytes_written;
+ if (write_connection->bytes_remaining > 0) {
+ write_connection->buffer_curr =
+ write_connection->buffer_curr + bytes_written;
+ write_connection->flags = CONNECTION_WRITING;
+ }
+ else {
+ /* we wrote everything we wanted. set things up so we read next
+ time around */
+ write_connection->buffer_curr = write_connection->buffer_base;
+ write_connection->bytes_remaining = write_connection->bytes_total;
+ write_connection->flags = CONNECTION_READING;
+ }
+ }
+ else if (bytes_written == 0) {
+ /* didn't do anything */
+ did_something = 0;
+ }
+ else {
+ /* it was < 0 - wonder what the error was? */
+ did_something = 0;
+ }
+ if (debug > 2) {
+ fprintf(stderr,
+ "wrote %d bytes on connection %p\n",
+ bytes_written,
+ write_connection);
+ }
+ return did_something;
+}
+
+int
+read_on_connection(uber_state_t *uber_state, connection_t *read_connection) {
+
+ int bytes_read;
+ char *temp_buf;
+ int did_something = 1;
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "about to read <= %d bytes on connection %p\n",
+ read_connection->bytes_remaining,
+ read_connection);
+ }
+
+ /* we don't actually care if the recv returns any bytes, just that
+ we called recv. */
+ uber_state->rdwr_since_accept += 1;
+
+ bytes_read = recv(read_connection->sock,
+ read_connection->buffer_curr,
+ read_connection->bytes_remaining,
+ 0);
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "read %d bytes from connection %p\n",
+ bytes_read,
+ read_connection);
+ }
+
+ if (bytes_read > 0) {
+ /* got some bytes */
+ read_connection->bytes_remaining -= bytes_read;
+ /* did we get all we wanted? */
+ if (!read_connection->bytes_remaining) {
+ /* yes we did. see about writing something back. if the write
+ call was able to write the entire response in one swell foop
+ it will leave us in CONNECTION_READING mode. otherwise it
+ will switch us to CONNECTION_WRITING mode until we complete
+ our writes. we can do this because we are a program that
+ does one thing at a time */
+ read_connection->bytes_remaining = read_connection->bytes_total;
+ read_connection->bytes_completed = 0;
+ write_on_connection(uber_state, read_connection);
+ }
+ }
+ else if (bytes_read == 0) {
+ uber_state->rdwr_since_accept += 1;
+ /* remote closed - should this count as having doen work or not? */
+ close_a_connection(uber_state,read_connection);
+ }
+ else {
+ /* it was < 0 we should reall check against EAGAIN */
+ /* errors or EAGAIN don't count as having done something */
+ did_something = 0;
+ }
+
+ return did_something;
+
+}
+
+int
+walk_connection_list(uber_state_t *uber_state) {
+
+ connection_t *temp_connection = uber_state->connection_list;
+ connection_t *del_connection;
+
+ int did_something = 0;
+ int ret;
+
+ while(temp_connection) {
+ switch (temp_connection->flags) {
+ case CONNECTION_LISTENING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a LISTEN connection\n",temp_connection);
+ }
+ /* only bother doing an accept on the blind walk of the list
+ when we've done some transactions. otherwise, the drop into
+ the select loop will catch things for us. we ass-u-me that
+ for the test the actual connection rate is << the transaction
+ rate. otherwise we'll need some additional heuristics -
+ perhaps domething involving how long it has been since an
+ accept() or how many consecutive accepts without a new
+ connection we've made. */
+ if (uber_state->rdwr_since_accept > 1000) {
+ ret = accept_new_connection(uber_state,temp_connection);
+ /* did we get one, and are there any more? */
+ while (ret > 0) {
+ /* if we came-in here, it means we got a connection above, so
+ we did do something. it probably isn't worth the added
+ conditional to only set did_something once... */
+ did_something = 1;
+ ret = accept_new_connection(uber_state,temp_connection);
+ }
+ }
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_READING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a READING connection\n",temp_connection);
+ }
+ ret = read_on_connection(uber_state,temp_connection);
+ if (ret > 0) did_something = 1;
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_WRITING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a WRITING connection\n",temp_connection);
+ }
+ ret = write_on_connection(uber_state,temp_connection);
+ if (ret > 0) did_something = 1;
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_CLOSING:
+ /* ok, just how should we deal with this then? */
+ del_connection = temp_connection;
+ temp_connection = temp_connection->next;
+ remove_old_connection(uber_state, del_connection);
+ break;
+ }
+ }
+ return did_something;
+}
+
+
+int
+main(int argc, char *argv[]) {
+
+ int temp;
+ int loops = 0;
+ int did_work;
+ socklen_t addrlen = sizeof(struct sockaddr_storage);
+ uber_state_t *uber_state;
+ event_state_select_t *mumble;
+ connection_t *connection_list;
+
+ connection_t *temp_connection;
+
+ uber_state = (uber_state_t *)malloc(sizeof(uber_state_t));
+ uber_state->connection_list = NULL;
+ uber_state->event_state = init_event_state();
+ mumble = uber_state->event_state;
+ uber_state->rdwr_since_accept = 0;
+
+ fprintf(stderr,"Hello there, let's generate some transactions. Uberstate %p connection_list %p event_state %p\n", uber_state,uber_state->connection_list,uber_state->event_state);
+
+ for (loops = 0; loops < atoi(argv[3]); loops++) {
+ temp = establish_connection(argv[1],argv[2],AF_INET,&addrlen);
+
+ /* initialize our event_state minfd */
+ /* mumble->minfd = temp; */
+
+ temp_connection = add_new_connection(uber_state,
+ temp,
+ CONNECTION_WRITING,
+ 128);
+
+ fprintf(stderr,"temp_connection is at %p\n",temp_connection);
+ }
+
+ do {
+ loops++;
+ if (debug > 1) {
+ fprintf(stderr,"\nabout to walk loop %d\n",loops);
+ }
+ did_work = walk_connection_list(uber_state);
+ if (!did_work) {
+ if (debug) {
+ fprintf(stderr,
+ "walk_connection_list did no work, time to wait\n");
+ }
+ did_work = wait_for_events_and_walk(uber_state);
+ }
+ } while (1);
+
+}
Added: trunk/suites/multi/nettest_multi.c
===================================================================
--- trunk/suites/multi/nettest_multi.c 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/nettest_multi.c 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,2389 @@
+/*
+
+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_multi_d[]="\
+@(#)(c) Copyright 2006 Hewlett-Packard Co. $Id:$";
+
+#ifdef DIRTY
+#define MAKE_DIRTY(mydata,ring) /* DIRTY is not currently supported */
+#else
+#define MAKE_DIRTY(mydata,ring) /* DIRTY is not currently supported */
+#endif
+
+/*
+ nettest_multi_bsd.c
+
+ These tests are the ones that will handle more than one
+ socket/connection per thread. Initially, we will be starting with
+ the recv_multi_tcp_rr() test in support of our aggregate 'TCP_RR'
+ testing. After that we will expand to include other classic
+ "nettest_bsd" tests.
+
+ It is expected that a "multi" test will be driven by N of the
+ classic "nettest_bsd" tests - ie the recv_multi_tcp_rr() will be
+ driven by a number of classic send_tcp_rr() tests. We will not
+ preclude a multi driving a multi, but we will not be trying for that
+ the first time out.
+
+ One of the more "fun" aspects will be the sort of "event
+ notification" to be used. Different mechanisms would integrate into
+ the code in different ways, and it may or may not be possible to
+ abstract that very well. All that remains to be seen I suppose. Of
+ course, if someone is feeling very strongly about a given mechanism,
+ there is nothing to preclude them from writing something that runs
+ outside the netperf4 harness that the other classic tests connect to
+ and get the measurements via the classic tests.
+
+ For now, we will concentrate on the classic event notification
+ mechanisms - select() and poll() and some of their derivatives.
+
+ Also for now, we do not attempt to spread the connections across
+ multiple threads within the benchmark itself. If multiple threads
+ are desired, multiple instances of the test should be run within the
+ same netserver and control connection. If multiple processes are
+ desired, then a test per control connection should be used.
+
+ the actual test routines...
+
+ send_multi_tcp_stream() send on multiple tcp streams test
+ recv_multi_tcp_stream() receive on multiple tcp streams test
+ send_multi_tcp_rr() tcp req/rsp on multiple connections
+ recv_multi_tcp_rr() recv multiple tcp req/rsp tests
+ send_multi_udp_stream() perform a multiple udp stream test
+ recv_multi_udp_stream() catch multiple udp stream tests
+ send_multi_udp_rr() perform a multiple udp req/rsp test
+ recv_multi_udp_rr() catch a udp req/rsp test
+
+*/
+
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+/* between the next three we aught to find DBL_MAX */
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#include "netperf.h"
+
+#include "nettest_multi.h"
+
+#include "netconfidence.h"
+
+#ifdef WIN32
+#define CHECK_FOR_INVALID_SOCKET (temp_socket == INVALID_SOCKET)
+#define CHECK_FOR_RECV_ERROR(len) (len == SOCKET_ERROR)
+#define GET_ERRNO WSAGetLastError()
+#else
+#define CHECK_FOR_INVALID_SOCKET (temp_socket < 0)
+#define CHECK_FOR_RECV_ERROR(len) (len < 0)
+#define GET_ERRNO errno
+#endif
+
+
+#if !defined(WANT_FIRST_BURST)
+#define BURST_VARS /* Burst variable declarations go here */
+#define TCP_CHECK_BURST_SEND /* Code to send tcp burst goes here */
+#define UDP_CHECK_FOR_RETRANS /* Code to retrans udp packets goes here */
+#define UDP_CHECK_BURST_SEND /* Code to send udp burst goes here */
+#define UDP_CHECK_BURST_RECV /* code for dropped udp packets goes here */
+#else
+#define TCP_CHECK_BURST_SEND \
+ if (my_data->burst_count > my_data->pending_responses) { \
+ my_data->pending_responses++; \
+ my_data->send_ring = my_data->send_ring->next; \
+ continue; \
+ }
+#define UDP_CHECK_FOR_RETRANS \
+ if (my_data->retry_array != NULL) { \
+ int retry; \
+ retry = my_data->retry_index; \
+ /* A burst size has been specified check if retransmission is needed */ \
+ if (my_data->retry_array[retry] != NULL) { \
+ /* a retransmission is needed a response was not received */ \
+ buffer_ptr = my_data->retry_array[retry]; \
+ my_data->stats.named.retransmits++; \
+ } \
+ buffer_ptr[0] = retry; \
+ }
+#define UDP_CHECK_BURST_SEND \
+ if (my_data->retry_array != NULL) { \
+ int retry = my_data->retry_index; \
+ int pending = my_data->pending_responses; \
+ int burst = my_data->burst_count; \
+ if (my_data->retry_array[retry] == NULL) { \
+ my_data->retry_array[retry] = buffer_ptr; \
+ retry++; \
+ if (retry == burst) { \
+ retry = 0; \
+ } \
+ pending++; \
+ my_data->pending_responses = pending; \
+ my_data->retry_index = retry; \
+ if (pending < burst) { \
+ my_data->send_ring = my_data->send_ring->next; \
+ continue; \
+ } \
+ } \
+ }
+#define UDP_CHECK_BURST_RECV \
+ if (my_data->retry_array != NULL) { \
+ my_data->retry_array[buffer_ptr[0]] = NULL; \
+ my_data->pending_responses--; \
+ }
+#endif
+
+
+static void
+report_test_failure(test_t *test, const char *function, int err_code, const 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 = (char *)function;
+ test->err_str = (char *)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",
+ BSDE_REQUESTED_STATE_INVALID,
+ strdup(error_msg));
+ }
+ }
+ }
+}
+
+static void
+wait_to_die(test_t *test)
+{
+ while (GET_TEST_STATE != TEST_DEAD) {
+ if (CHECK_REQ_STATE == TEST_DEAD) {
+ free(GET_TEST_DATA(test));
+ SET_TEST_DATA(test,NULL);
+ SET_TEST_STATE(TEST_DEAD);
+ }
+ }
+}
+
+
+
+static void
+dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+ xmlChar *host, xmlChar *port, int family)
+{
+ struct sockaddr *ai_addr;
+ struct addrinfo *temp;
+ temp=info;
+
+ fprintf(dumploc, "getaddrinfo returned the following for host '%s' ", host);
+ fprintf(dumploc, "port '%s' ", port);
+ fprintf(dumploc, "family %d\n", family);
+ while (temp) {
+ fprintf(dumploc,
+ "\tcannonical name: '%s'\n",temp->ai_canonname);
+ fprintf(dumploc,
+ "\tflags: %d family: %d: socktype: %d protocol %d addrlen %d\n",
+ temp->ai_flags,
+ temp->ai_family,
+ temp->ai_socktype,
+ temp->ai_protocol,
+ temp->ai_addrlen);
+ ai_addr = temp->ai_addr;
+ if (ai_addr != NULL) {
+ fprintf(dumploc,
+ "\tsa_family: %d sadata: %d %d %d %d %d %d\n",
+ ai_addr->sa_family,
+ (u_char)ai_addr->sa_data[0],
+ (u_char)ai_addr->sa_data[1],
+ (u_char)ai_addr->sa_data[2],
+ (u_char)ai_addr->sa_data[3],
+ (u_char)ai_addr->sa_data[4],
+ (u_char)ai_addr->sa_data[5]);
+ }
+ temp = temp->ai_next;
+ }
+ fflush(dumploc);
+}
+
+static int
+strtofam(xmlChar *familystr)
+{
+ if (!xmlStrcmp(familystr,(const xmlChar *)"AF_INET")) {
+ return(AF_INET);
+ }
+ else if (!xmlStrcmp(familystr,(const xmlChar *)"AF_UNSPEC")) {
+ return(AF_UNSPEC);
+#ifdef AF_INET6
+ }
+ else if (!xmlStrcmp(familystr,(const xmlChar *)"AF_INET6")) {
+ return(AF_INET6);
+#endif /* AF_INET6 */
+ }
+ else {
+ /* we should never get here if the validator is doing its thing */
+ return(-1);
+ }
+}
+
+static void
+get_dependency_data(test_t *test, int type, int protocol)
+{
+ bsd_data_t *my_data = GET_TEST_DATA(test);
+
+ 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);
+ }
+ g_usleep(1000000);
+ }
+ } 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,"%s: getaddrinfo returned %d %s\n",
+ __func__, error, gai_strerror(error));
+ fflush(test->where);
+ }
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_GETADDRINFO_ERROR,
+ gai_strerror(error));
+ }
+ if (string) free(string);
+ if (remotehost) free(remotehost);
+ if (remoteport) free(remoteport);
+}
+
+
+static void
+set_dependent_data(test)
+ test_t *test;
+{
+
+ bsd_data_t *my_data = GET_TEST_DATA(test);
+ 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",
+ BSDE_XMLSETPROP_ERROR,
+ "error setting properties for dependency data");
+ }
+ }
+ else {
+ report_test_failure(test,
+ "set_dependent_data",
+ BSDE_XMLNEWNODE_ERROR,
+ "error getting new node for dependency data");
+ }
+}
+
+
+static 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 allocate a circular list of buffers for either */
+ /* send or receive operations. each of these buffers will be aligned */
+ /* and offset as per the users request. the circumference of this */
+ /* ring will be controlled by the setting of send_width. the buffers */
+ /* will be filled with data from the file specified in fill_file. if */
+ /* fill_file is an empty string, the buffers will not be filled with */
+ /* any particular data */
+
+static ring_elt_ptr
+allocate_buffer_ring(width, buffer_size, alignment, offset, fill_source)
+ int width;
+ int buffer_size;
+ int alignment;
+ int offset;
+ FILE *fill_source;
+{
+ ring_elt_ptr first_link = NULL;
+ ring_elt_ptr temp_link = NULL;
+ ring_elt_ptr prev_link;
+
+ int i;
+ int malloc_size;
+ int bytes_left;
+ int bytes_read;
+ int do_fill = 0;
+
+ malloc_size = buffer_size + alignment + offset;
+
+ /* did the user wish to have the buffers pre-filled with data from a */
+ /* particular source? */
+ if (fill_source != (FILE *)NULL) {
+ do_fill = 1;
+ }
+
+ prev_link = NULL;
+ for (i = 1; i <= width; i++) {
+ /* get the ring element */
+ temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt));
+ /* remember the first one so we can close the ring at the end */
+ if (i == 1) {
+ first_link = temp_link;
+ }
+ temp_link->buffer_base = (char *)g_malloc(malloc_size);
+#ifndef G_OS_WIN32
+ temp_link->buffer_ptr = (char *)(( (long)(temp_link->buffer_base) +
+ (long)alignment - 1) &
+ ~((long)alignment - 1));
+#else
+ /* 64-bit Windows is P64, not LP64 like the rest of the world,
+ so we cannot cast as a "long" */
+ temp_link->buffer_ptr = (char *)(( (ULONG_PTR)(temp_link->buffer_base) +
+ (long)alignment - 1) &
+ ~((long)alignment - 1));
+#endif
+ temp_link->buffer_ptr += offset;
+ /* is where the buffer fill code goes. */
+ if (do_fill) {
+ bytes_left = buffer_size;
+ while (bytes_left) {
+ if (((bytes_read = fread(temp_link->buffer_ptr,
+ 1,
+ bytes_left,
+ fill_source)) == 0) &&
+ (feof(fill_source))){
+ rewind(fill_source);
+ }
+ bytes_left -= bytes_read;
+ }
+ }
+ else {
+ /* put our own special "stamp" upon the buffer */
+ strncpy(temp_link->buffer_ptr,
+ NETPERF_RING_BUFFER_STRING,
+ buffer_size);
+ }
+ temp_link->next = prev_link;
+ prev_link = temp_link;
+ }
+ first_link->next = temp_link;
+
+ return(first_link); /* it's a circle, doesn't matter which we return */
+}
+
+
+ /* 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 SOCKET
+create_data_socket(test)
+ test_t *test;
+{
+ bsd_data_t *my_data = GET_TEST_DATA(test);
+
+ 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 loc_sndavoid = my_data->send_avoid;
+ int loc_rcvavoid = my_data->recv_avoid;
+
+ SOCKET temp_socket;
+ int one;
+ netperf_socklen_t sock_opt_len;
+
+ if (test->debug) {
+ fprintf(test->where,
+ "%s: calling socket family = %d type = %d\n",
+ __func__, 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,
+ (char *)__func__,
+ BSDE_SOCKET_ERROR,
+ "error creating socket");
+ return(temp_socket);
+ }
+
+ if (test->debug) {
+ fprintf(test->where,
+ "%s: socket %d obtained...\n",
+ __func__, 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,
+ (void *)&lss_size, sizeof(int)) < 0) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_SETSOCKOPT_ERROR,
+ "error setting local send socket buffer size");
+ return(temp_socket);
+ }
+ if (test->debug > 1) {
+ fprintf(test->where,
+ "nettest_bsd: 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,
+ (void *)&lsr_size, sizeof(int)) < 0) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_SETSOCKOPT_ERROR,
+ "error setting local recv socket buffer size");
+ return(temp_socket);
+ }
+ if (test->debug > 1) {
+ fprintf(test->where,
+ "nettest_bsd: %s: SO_RCVBUF of %d requested.\n",
+ __func__, 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_bsd: %s: getsockopt SO_SNDBUF: errno %d\n",
+ __func__, 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_bsd: %s: getsockopt SO_RCVBUF: errno %d\n",
+ __func__, errno);
+ fflush(test->where);
+ lsr_size = -1;
+ }
+ if (test->debug) {
+ fprintf(test->where,
+ "nettest_bsd: %s: socket sizes determined...\n",
+ __func__);
+ 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... */
+
+#ifdef SO_RCV_COPYAVOID
+ if (loc_rcvavoid) {
+ if (setsockopt(temp_socket,
+ SOL_SOCKET,
+ SO_RCV_COPYAVOID,
+ &loc_rcvavoid,
+ sizeof(int)) < 0) {
+ fprintf(test->where,
+ "nettest_bsd: %s: Could not enable receive copy avoidance",
+ __func__);
+ fflush(test->where);
+ loc_rcvavoid = 0;
+ }
+ }
+#else
+ /* it wasn't compiled in... */
+ loc_rcvavoid = 0;
+#endif /* SO_RCV_COPYAVOID */
+
+#ifdef SO_SND_COPYAVOID
+ if (loc_sndavoid) {
+ if (setsockopt(temp_socket,
+ SOL_SOCKET,
+ SO_SND_COPYAVOID,
+ &loc_sndavoid,
+ sizeof(int)) < 0) {
+ fprintf(test->where,
+ "nettest_bsd: %s: Could not enable send copy avoidance\n",
+ __func__);
+ fflush(test->where);
+ loc_sndavoid = 0;
+ }
+ }
+#else
+ /* it was not compiled in... */
+ loc_sndavoid = 0;
+#endif
+
+ /* 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,
+ "nettest_bsd: %s: nodelay: errno %d\n",
+ __func__, errno);
+ fflush(test->where);
+ }
+
+ if (test->debug > 1) {
+ fprintf(test->where,
+ "netperf: %s: TCP_NODELAY requested...\n", __func__);
+ fflush(test->where);
+ }
+ }
+#else /* TCP_NODELAY */
+
+ my_data->no_delay = 0;
+
+#endif /* TCP_NODELAY */
+
+ return(temp_socket);
+
+}
+
+
+typedef struct interest_set {
+ int num_allocated;
+ int num_active;
+ struct pollfd *fds;
+} interest_set_t;
+
+static void
+add_to_set_of_interest(SOCKET sock, short what, void *interest_set) {
+ struct pollfd *interesting_fds;
+
+ interesting_fds = interest_set;
+
+}
+
+static void
+del_from_set_of_interest(SOCKET sock, short what, void *interest_set) {
+}
+
+static int
+wait_for_something_interesting(void *interest_set, int how_long) {
+}
+
+bsd_data_t *
+bsd_test_init(test_t *test, int type, int protocol)
+{
+ bsd_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;
+
+ /* allocate memory to store the information about this test */
+ new_data = (bsd_data_t *)malloc(sizeof(bsd_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 bsd test specific data structure */
+ memset(new_data,0,sizeof(bsd_data_t));
+
+ string = xmlGetProp(args,(const xmlChar *)"fill_file");
+ /* fopen the fill file it will be used when allocating buffer rings */
+ if (string) {
+ new_data->fill_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 *)"send_size");
+ units = xmlGetProp(args,(const xmlChar *)"send_size_units");
+ new_data->send_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);
+
+ string = xmlGetProp(args,(const xmlChar *)"recv_size");
+ units = xmlGetProp(args,(const xmlChar *)"recv_size_units");
+ new_data->recv_size = convert(string,units);
+
+ string = xmlGetProp(args,(const xmlChar *)"req_size");
+ new_data->req_size = atoi((char *)string);
+
+ string = xmlGetProp(args,(const xmlChar *)"rsp_size");
+ new_data->rsp_size = atoi((char *)string);
+
+ /* relying on the DTD to give us defaults isn't always the most
+ robust way to go about doing things. */
+ string = xmlGetProp(args,(const xmlChar *)"port_min");
+ if (string) {
+ new_data->port_min = atoi((char *)string);
+ }
+ else {
+ new_data->port_min = -1;
+ }
+
+ string = xmlGetProp(args,(const xmlChar *)"port_max");
+ if (string) {
+ new_data->port_max = atoi((char *)string);
+ }
+ else {
+ new_data->port_max = -1;
+ }
+
+ string = xmlGetProp(args,(const xmlChar *)"send_width");
+ new_data->send_width = atoi((char *)string);
+ if (new_data->send_width == 0) {
+ new_data->send_width = new_data->send_buf_size/new_data->send_size + 1;
+ if (new_data->send_width == 1) new_data->send_width = 2;
+ }
+
+ string = xmlGetProp(args,(const xmlChar *)"recv_width");
+ new_data->recv_width = atoi((char *)string);
+ if (new_data->recv_width == 0) {
+ new_data->recv_width = new_data->recv_buf_size/new_data->recv_size + 1;
+ if (new_data->recv_width == 1) new_data->recv_width = 2;
+ }
+
+ string = xmlGetProp(args,(const xmlChar *)"send_align");
+ new_data->send_align = atoi((char *)string);
+
+ string = xmlGetProp(args,(const xmlChar *)"recv_align");
+ new_data->recv_align = atoi((char *)string);
+
+ string = xmlGetProp(args,(const xmlChar *)"send_offset");
+ new_data->send_offset = atoi((char *)string);
+
+ string = xmlGetProp(args,(const xmlChar *)"recv_offset");
+ new_data->recv_offset = atoi((char *)string);
+
+ string = xmlGetProp(args,(const xmlChar *)"burst_count");
+ if (string) {
+ count = atoi((char *)string);
+ new_data->burst_count = count;
+ if (count >= new_data->send_width) {
+ new_data->send_width = count + 1;
+ }
+ string = xmlGetProp(test->node,(const xmlChar *)"test_name");
+ if (!xmlStrcmp(string, (const xmlChar *)"send_udp_rr")) {
+ new_data->retry_array = malloc(count * sizeof(char *));
+ if (new_data->retry_array) {
+ memset(new_data->retry_array, 0, count * sizeof(char *));
+ }
+ }
+ }
+
+ string = xmlGetProp(args,(const xmlChar *)"interval_time");
+ if (string) {
+ new_data->interval = atoi((char *)string);
+ }
+
+ /* 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,"Sleeping on getaddrinfo EAI_AGAIN\n");
+ fflush(test->where);
+ }
+ g_usleep(1000000);
+ }
+ } while ((error == EAI_AGAIN) && (count <= 5));
+
+ if (test->debug) {
+ dump_addrinfo(test->where, local_ai, localhost, localport, localfam);
+ }
+
+ if (!error) {
+ 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__,
+ BSDE_GETADDRINFO_ERROR,
+ gai_strerror(error));
+ }
+ }
+ else {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_NO_SOCKET_ARGS,
+ "no socket_arg element was found");
+ }
+
+ SET_TEST_DATA(test,new_data);
+ return(new_data);
+}
+
+static void
+update_elapsed_time(bsd_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
+bsd_test_clear_stats(bsd_data_t *my_data)
+{
+ int i;
+ for (i = 0; i < BSD_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
+bsd_test_decode_stats(xmlNodePtr stats,test_t *test)
+{
+ if (test->debug) {
+ fprintf(test->where,"bsd_test_decode_stats: entered for %s test %s\n",
+ test->id, test->test_name);
+ fflush(test->where);
+ }
+}
+
+static xmlNodePtr
+bsd_test_get_stats(test_t *test)
+{
+ xmlNodePtr stats = NULL;
+ xmlAttrPtr ap = NULL;
+ int i;
+ char value[32];
+ char name[32];
+ uint64_t loc_cnt[BSD_MAX_COUNTERS];
+
+ bsd_data_t *my_data = GET_TEST_DATA(test);
+
+ if (test->debug) {
+ fprintf(test->where,"bsd_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 < BSD_MAX_COUNTERS; i++) {
+ loc_cnt[i] = my_data->stats.counter[i];
+ if (test->debug) {
+ fprintf(test->where,"BSD_COUNTER%X = %#"PRIx64"\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 < BSD_MAX_COUNTERS; i++) {
+ if (ap == NULL) {
+ break;
+ }
+ if (loc_cnt[i]) {
+ sprintf(value,"%#"PRIx64,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 bsd_test_get_stats */
+
+
+static void
+recv_multi_tcp_rr_preinit(test_t *test)
+{
+ int rc;
+ SOCKET s_listen;
+ bsd_data_t *my_data;
+ struct sockaddr myaddr;
+ netperf_socklen_t mylen;
+
+ my_data = GET_TEST_DATA(test);
+
+ mylen = sizeof(myaddr);
+
+ my_data->recv_ring = allocate_buffer_ring(my_data->recv_width,
+ my_data->req_size,
+ my_data->recv_align,
+ my_data->recv_offset,
+ my_data->fill_source);
+ my_data->send_ring = allocate_buffer_ring(my_data->send_width,
+ my_data->rsp_size,
+ my_data->send_align,
+ my_data->send_offset,
+ my_data->fill_source);
+ s_listen = create_data_socket(test);
+ my_data->s_listen = s_listen;
+ if (test->debug) {
+ dump_addrinfo(test->where, my_data->locaddr,
+ (xmlChar *)NULL, (xmlChar *)NULL, -1);
+ fprintf(test->where,
+ "%s:create_data_socket returned %d\n",
+ __func__, s_listen);
+ fflush(test->where);
+ }
+ rc = bind(s_listen, my_data->locaddr->ai_addr, my_data->locaddr->ai_addrlen);
+ if (test->debug) {
+ fprintf(test->where,
+ "%s:bind returned %d errno=%d\n",
+ __func__, rc, errno);
+ fflush(test->where);
+ }
+ if (rc == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_BIND_FAILED,
+ "data socket bind failed");
+ }
+ /* we might actually have quite a few attemtped connections at one
+ time, might as well let them queue when necessary. raj
+ 2006-07-06 */
+ else if (listen(s_listen,512) == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_LISTEN_FAILED,
+ "data socket listen failed");
+ }
+ else if (getsockname(s_listen,&myaddr,&mylen) == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_GETSOCKNAME_FAILED,
+ "getting the listen socket name failed");
+ }
+ else {
+ memcpy(my_data->locaddr->ai_addr,&myaddr,mylen);
+ my_data->locaddr->ai_addrlen = mylen;
+ set_dependent_data(test);
+ }
+}
+
+static uint32_t
+recv_multi_tcp_rr_init(test_t *test)
+{
+ SOCKET s_data;
+ bsd_data_t *my_data;
+ struct sockaddr peeraddr;
+ netperf_socklen_t peerlen;
+
+ my_data = GET_TEST_DATA(test);
+
+ peerlen = sizeof(peeraddr);
+
+ if (test->debug) {
+ fprintf(test->where, "%s:waiting in accept\n", __func__);
+ fflush(test->where);
+ }
+ if ((s_data = accept(my_data->s_listen,
+ &peeraddr,
+ &peerlen)) == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_ACCEPT_FAILED,
+ "listen socket accept failed");
+ }
+ else {
+ if (test->debug) {
+ fprintf(test->where,
+ "%s:accept returned successfully %d\n",
+ __func__, s_data);
+ fflush(test->where);
+ }
+ my_data->s_data = s_data;
+ }
+ return(TEST_IDLE);
+}
+
+static void
+recv_multi_tcp_rr_idle_link(test_t *test, int last_len)
+{
+ int len;
+ uint32_t new_state;
+ bsd_data_t *my_data;
+ struct sockaddr peeraddr;
+ netperf_socklen_t peerlen;
+
+ my_data = GET_TEST_DATA(test);
+
+ len = last_len;
+ peerlen = sizeof(peeraddr);
+
+ new_state = CHECK_REQ_STATE;
+ while (new_state == TEST_LOADED) {
+ g_usleep(1000000);
+ 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);
+ }
+ if (shutdown(my_data->s_data,SHUT_WR) == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_SOCKET_SHUTDOWN_FAILED,
+ "data_recv_error");
+ }
+ else {
+ while (len > 0) {
+ len=recv(my_data->s_data,
+ my_data->recv_ring->buffer_ptr,
+ my_data->req_size, 0);
+ }
+ CLOSE_SOCKET(my_data->s_data);
+ if (test->debug) {
+ fprintf(test->where,"%s: waiting in accept\n",__func__);
+ fflush(test->where);
+ }
+ if ((my_data->s_data=accept(my_data->s_listen,
+ &peeraddr,
+ &peerlen)) == -1) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_ACCEPT_FAILED,
+ "listen socket accept failed");
+ }
+ else {
+ if (test->debug) {
+ fprintf(test->where,
+ "%s: accept returned successfully %d\n",
+ __func__,
+ my_data->s_data);
+ fflush(test->where);
+ }
+ }
+ }
+ }
+ 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,
+ (char *)__func__,
+ BSDE_DATA_CONNECTION_CLOSED_ERROR,
+ "data connection closed and non idle state requested");
+ }
+}
+
+static uint32_t
+recv_multi_tcp_rr_meas(test_t *test)
+{
+ int len = -1;
+ int bytes_left;
+ char *req_ptr;
+ uint32_t new_state;
+ bsd_data_t *my_data;
+
+ HISTOGRAM_VARS;
+ my_data = GET_TEST_DATA(test);
+
+ /* code to timestamp enabled by WANT_HISTOGRAM */
+ HIST_TIMESTAMP(&time_one);
+ /* recv the request for the test */
+ req_ptr = my_data->recv_ring->buffer_ptr;
+ bytes_left = my_data->req_size;
+ while (bytes_left > 0) {
+ if ((len=recv(my_data->s_data,
+ req_ptr,
+ bytes_left,
+ 0)) != 0) {
+ /* this macro hides windows differences */
+ if (CHECK_FOR_RECV_ERROR(len)) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_DATA_RECV_ERROR,
+ "data_recv_error");
+ break;
+ }
+ req_ptr += len;
+ bytes_left -= len;
+ }
+ else {
+ /* just got a data connection close break out of while loop */
+ break;
+ }
+ }
+ if (len == 0) {
+ /* how do we deal with a closed connection in the measured state */
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_DATA_CONNECTION_CLOSED_ERROR,
+ "data connection closed during TEST_MEASURE state");
+ }
+ else {
+ my_data->stats.named.trans_received++;
+ if ((len=send(my_data->s_data,
+ my_data->send_ring->buffer_ptr,
+ my_data->rsp_size,
+ 0)) != my_data->rsp_size) {
+ /* this macro hides windows differences */
+ if (CHECK_FOR_SEND_ERROR(len)) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_DATA_SEND_ERROR,
+ "data_send_error");
+ }
+ }
+ }
+ /* code to timestamp enabled by WANT_HISTOGRAM */
+ HIST_TIMESTAMP(&time_two);
+ HIST_ADD(my_data->time_hist,&time_one,&time_two);
+ my_data->recv_ring = my_data->recv_ring->next;
+ my_data->send_ring = my_data->send_ring->next;
+ 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
+recv_multi_tcp_rr_load(test_t *test)
+{
+ int len=-1;
+ int bytes_left;
+ char *req_ptr;
+ uint32_t new_state;
+ bsd_data_t *my_data;
+
+ my_data = GET_TEST_DATA(test);
+
+ /* recv the request for the test */
+ req_ptr = my_data->recv_ring->buffer_ptr;
+ bytes_left = my_data->req_size;
+ while (bytes_left > 0) {
+ if ((len=recv(my_data->s_data,
+ req_ptr,
+ bytes_left,
+ 0)) != 0) {
+ /* this macro hides windows differences */
+ if (CHECK_FOR_RECV_ERROR(len)) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_DATA_RECV_ERROR,
+ "data_recv_error");
+ break;
+ }
+ req_ptr += len;
+ bytes_left -= len;
+ }
+ else {
+ /* just got a data connection close break out of while loop */
+ break;
+ }
+ }
+ /* check for state transition */
+ new_state = CHECK_REQ_STATE;
+ if ((len == 0) ||
+ (new_state == TEST_IDLE)) {
+ /* just got a data connection close or
+ a request to transition to the idle state */
+ recv_multi_tcp_rr_idle_link(test,len);
+ new_state = TEST_IDLE;
+ }
+ else {
+ if ((len=send(my_data->s_data,
+ my_data->send_ring->buffer_ptr,
+ my_data->rsp_size,
+ 0)) != my_data->rsp_size) {
+ /* this macro hides windows differences */
+ if (CHECK_FOR_SEND_ERROR(len)) {
+ report_test_failure(test,
+ (char *)__func__,
+ BSDE_DATA_SEND_ERROR,
+ "data_send_error");
+ }
+ }
+ my_data->recv_ring = my_data->recv_ring->next;
+ my_data->send_ring = my_data->send_ring->next;
+ 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_multi_tcp_rr_clear_stats(test_t *test)
+{
+ return(bsd_test_clear_stats(GET_TEST_DATA(test)));
+}
+
+
+xmlNodePtr
+recv_multi_tcp_rr_get_stats(test_t *test)
+{
+ return( bsd_test_get_stats(test));
+}
+
+void
+recv_multi_tcp_rr_decode_stats(xmlNodePtr stats,test_t *test)
+{
+ bsd_test_decode_stats(stats,test);
+}
+
+
+
+/* This routine implements the server-side of the TCP request/response */
+/* test (a.k.a. rr) for the sockets interface. It receives its */
+/* parameters via the xml node contained in the test structure. */
+/* results are collected by the procedure recv_multi_tcp_rr_get_stats */
+
+void
+recv_multi_tcp_rr(test_t *test)
+{
+ uint32_t state, new_state;
+ bsd_test_init(test, SOCK_STREAM, IPPROTO_TCP);
+ state = GET_TEST_STATE;
+ while ((state != TEST_ERROR) &&
+ (state != TEST_DEAD )) {
+ switch(state) {
+ case TEST_PREINIT:
+ recv_multi_tcp_rr_preinit(test);
+ new_state = TEST_INIT;
+ break;
+ case TEST_INIT:
+ new_state = CHECK_REQ_STATE;
+ if (new_state == TEST_IDLE) {
+ new_state = recv_multi_tcp_rr_init(test);
+ }
+ break;
+ case TEST_IDLE:
+ new_state = CHECK_REQ_STATE;
+ if (new_state == TEST_IDLE) {
+ g_usleep(1000000);
+ }
+ break;
+ case TEST_MEASURE:
+ new_state = recv_multi_tcp_rr_meas(test);
+ break;
+ case TEST_LOADED:
+ new_state = recv_multi_tcp_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 recv_multi_tcp_rr */
+
+
+/* This implementation of report_bsd_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
+bsd_test_results_init(tset_t *test_set, char *report_flags, char *output)
+{
+ bsd_results_t *rd;
+ FILE *outfd;
+ int max_count;
+ size_t malloc_size;
+
+ rd = test_set->report_data;
+ max_count = test_set->confidence.max_count;
+
+ if (output) {
+ if (test_set->debug) {
+ fprintf(test_set->where,
+ "bsd_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_bsd_test_results: report going to file stdout\n");
+ fflush(test_set->where);
+ }
+ outfd = stdout;
+ }
+ /* allocate and initialize report data */
+ malloc_size = sizeof(bsd_results_t) + 7 * max_count * sizeof(double);
+ rd = malloc(malloc_size);
+ if (rd) {
+
+ /* original code took sizeof a math equation so memset only zeroed the */
+ /* first sizeof(size_t) bytes. This should work better sgb 20060203 */
+
+ memset(rd, 0, malloc_size);
+ 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]);
+ /* we should initialize result_confidence here? */
+ rd->result_confidence = 0.0;
+ rd->result_minimum = DBL_MAX;
+ rd->result_maximum = DBL_MIN;
+ rd->outfd = outfd;
+ rd->sd_denominator = 0.0;
+ if (NULL != report_flags) {
+ 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;
+ rd->print_per_cpu = 1;
+ }
+ }
+ if (test_set->debug) {
+ rd->print_run = 1;
+ rd->print_test = 1;
+ rd->print_per_cpu = 1;
+ }
+ test_set->report_data = rd;
+ }
+ else {
+ /* could not allocate memory can't generate report */
+ fprintf(outfd,
+ "bsd_test_results_init: malloc failed can't generate report\n");
+ fflush(outfd);
+ exit(-1);
+ }
+}
+
+static void
+process_test_stats(tset_t *test_set, xmlNodePtr stats, xmlChar *tid)
+{
+ int i;
+ int count;
+ int index;
+ FILE *outfd;
+ bsd_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;
+ /* MUST use the PRIx64 macro to get the proper format under
+ Windows or we get garbage. raj 2006-04-12 */
+ sscanf(value_str,"%"PRIx64,&x);
+ test_cntr[i] = (double)x;
+ }
+ }
+ else {
+ test_cntr[i] = 0.0;
+ }
+ if (test_set->debug) {
+ unsigned char *string = NULL;
+ string = xmlGetProp(stats, (const xmlChar *)cntr_name[i]);
+ fprintf(test_set->where,"\t%12s test_cntr[%2d] = %10g\t'%s'\n",
+ cntr_name[i], i, test_cntr[i],
+ string ? (char *)string : "n/a");
+ }
+ }
+ elapsed_seconds = test_cntr[TST_E_SEC] + test_cntr[TST_E_USEC]/1000000.0;
+ xmit_rate = test_cntr[TST_X_BYTES]*8/(elapsed_seconds*1000000.0);
+ recv_rate = test_cntr[TST_R_BYTES]*8/(elapsed_seconds*1000000.0);
+ 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_trans_rate > 0.0 || recv_trans_rate > 0.0) {
+ rd->sd_denominator = 1.0;
+ } else {
+ rd->sd_denominator = 1000000.0/(8.0*1024.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 bsd per test instance results */
+}
+
+static double
+process_sys_stats(tset_t *test_set, xmlNodePtr stats, xmlChar *tid)
+{
+ int i;
+ int count;
+ int index;
+ FILE *outfd;
+ bsd_results_t *rd;
+ char *value_str;
+ xmlNodePtr cpu;
+ double elapsed_seconds;
+ 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++) {
+ 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;
+ /* MUST use PRIx64 to get proper results under Windows */
+ sscanf(value_str,"%"PRIx64,&x);
+ sys_cntr[i] = (double)x;
+ }
+ }
+ else {
+ sys_cntr[i] = 0.0;
+ }
+ if (test_set->debug) {
+ unsigned char *string = NULL;
+ string = xmlGetProp(stats, (const xmlChar *)sys_cntr_name[i]);
+ fprintf(test_set->where,
+ "\t%12s sys_stats[%d] = %10g '%s'\n",
+ sys_cntr_name[i],
+ i,
+ sys_cntr[i],
+ string ? (char *) string : "n/a");
+ }
+ }
+ 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_per_cpu) {
+ cpu = stats->xmlChildrenNode;
+ while (cpu != NULL) {
+ if (!xmlStrcmp(cpu->name,(const xmlChar *)"per_cpu_stats")) {
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"cpu_id");
+ fprintf(outfd," cpu%2s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"calibration");
+ fprintf(outfd,"%s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"idle_count");
+ fprintf(outfd,"%s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"user_count");
+ fprintf(outfd,"%s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"sys_count");
+ fprintf(outfd,"%s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"int_count");
+ fprintf(outfd,"%s ", value_str);
+ value_str = (char *)xmlGetProp(cpu, (const xmlChar *)"other_count");
+ fprintf(outfd,"%s\n", value_str);
+ fflush(outfd);
+ }
+ cpu = cpu->next;
+ }
+ }
+
+ 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 */
+ return(local_cpus);
+}
+
+static void
+process_stats_for_run(tset_t *test_set)
+{
+ bsd_results_t *rd;
+ test_t *test;
+ tset_elt_t *set_elt;
+ xmlNodePtr stats;
+ xmlNodePtr prev_stats;
+ int count;
+ int index;
+ int num_of_tests;
+ double num_of_cpus;
+
+ 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;
+
+ num_of_tests = 0;
+ num_of_cpus = 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 */
+ num_of_cpus = 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++;
+ num_of_tests++;
+ }
+ /* 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(-1);
+ }
+ 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];
+ }
+ rd->run_time[index] = rd->run_time[index] / (double)num_of_tests;
+
+ /* now calculate service demand for this test run. Remember the cpu */
+ /* utilization is in the range 0.0 to 1.0 so we need to multiply by */
+ /* the number of cpus and 1,000,000.0 to get to microseconds of cpu */
+ /* time per unit of work. The result is in transactions per second */
+ /* or in million bits per second so the sd_denominator is factored */
+ /* in to convert service demand into usec/trans or usec/Kbytes. */
+
+ if ((rd->results[index] != 0.0) && (num_of_cpus != 0.0)) {
+ rd->servdemand[index] = rd->utilization[index] * num_of_cpus * 1000000.0 /
+ (rd->results[index] * rd->sd_denominator);
+ }
+ NETPERF_DEBUG_EXIT(test_set->debug,test_set->where);
+}
+
+static void
+update_results_and_confidence(tset_t *test_set)
+{
+ bsd_results_t *rd;
+ double confidence;
+ double temp;
+
+ rd = test_set->report_data;
+
+ NETPERF_DEBUG_ENTRY(test_set->debug,test_set->where);
+
+ /* calculate confidence and summary result values */
+ confidence = (test_set->get_confidence)(rd->run_time,
+ &(test_set->confidence),
+ &(rd->ave_time),
+ &(temp));
+ rd->result_confidence = (test_set->get_confidence)(rd->results,
+ &(test_set->confidence),
+ &(rd->result_measured_mean),
+ &(rd->result_interval));
+ if (test_set->debug) {
+ fprintf(test_set->where,
+ "\tresults conf = %.2f%%\tmean = %10f +/- %8f\n",
+ 100.0 * rd->result_confidence,
+ rd->result_measured_mean, rd->result_interval);
+ fflush(test_set->where);
+ }
+ rd->cpu_util_confidence = (test_set->get_confidence)(rd->utilization,
+ &(test_set->confidence),
+ &(rd->cpu_util_measured_mean),
+ &(rd->cpu_util_interval));
+ if (test_set->debug) {
+ fprintf(test_set->where,
+ "\tcpu_util conf = %.2f%%\tmean = %10f +/- %8f\n",
+ 100.0 * rd->cpu_util_confidence,
+ rd->cpu_util_measured_mean, rd->cpu_util_interval);
+ fflush(test_set->where);
+ }
+ rd->service_demand_confidence = (test_set->get_confidence)(rd->servdemand,
+ &(test_set->confidence),
+ &(rd->service_demand_measured_mean),
+ &(rd->service_demand_interval));
+ if (test_set->debug) {
+ fprintf(test_set->where,
+ "\tserv_demand conf = %.2f%%\tmean = %10f +/- %8f\n",
+ 100.0 * rd->service_demand_confidence,
+ rd->service_demand_measured_mean, rd->service_demand_interval);
+ fflush(test_set->where);
+ }
+
+ if (rd->result_confidence > rd->cpu_util_confidence) {
+ confidence = rd->result_confidence;
+ }
+ else {
+ confidence = rd->cpu_util_confidence;
+ }
+ if (rd->service_demand_confidence > confidence) {
+ confidence = rd->service_demand_confidence;
+ }
+
+ if (test_set->confidence.min_count > 1) {
+ test_set->confidence.value = test_set->confidence.interval - confidence;
+ }
+ if (test_set->debug) {
+ fprintf(test_set->where,
+ "\t%3drun confidence = %.2f%%\tcheck value = %f\n",
+ test_set->confidence.count,
+ 100.0 * confidence, test_set->confidence.value);
+ fflush(test_set->where);
+ }
+ NETPERF_DEBUG_EXIT(test_set->debug,test_set->where)
+}
+
+static void
+print_run_results(tset_t *test_set)
+{
+ bsd_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);
+}
+
+
+static void
+print_did_not_meet_confidence(tset_t *test_set)
+{
+ bsd_results_t *rd;
+ FILE *outfd;
+
+ rd = test_set->report_data;
+ outfd = rd->outfd;
+
+
+ /* print the confidence failed line */
+ fprintf(outfd,"\n");
+ fprintf(outfd,"!!! WARNING\n");
+ fprintf(outfd,"!!! Desired confidence was not achieved within ");
+ fprintf(outfd,"the specified iterations. (%d)\n",
+ test_set->confidence.max_count);
+ fprintf(outfd,
+ "!!! This implies that there was variability in ");
+ fprintf(outfd,
+ "the test environment that\n");
+ fprintf(outfd,
+ "!!! must be investigated before going further.\n");
+ fprintf(outfd,
+ "!!! Confidence intervals: RESULT : %6.2f%%\n",
+ 100.0 * rd->result_confidence);
+ fprintf(outfd,
+ "!!! CPU util : %6.2f%%\n",
+ 100.0 * rd->cpu_util_confidence);
+ fprintf(outfd,
+ "!!! ServDemand : %6.2f%%\n",
+ 100.0 * rd->service_demand_confidence);
+ fflush(outfd);
+}
+
+
+static void
+print_results_summary(tset_t *test_set)
+{
+ bsd_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_interval); /* 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_interval); /* 58,7 */
+ fprintf(outfd,"%6.3f ",rd->service_demand_measured_mean); /* 65,7 */
+ fprintf(outfd,"%6.3f ",rd->service_demand_interval); /* 72,7 */
+ fprintf(outfd,"\n"); /* 79,1 */
+ fflush(outfd);
+}
+
+void
+report_bsd_test_results(tset_t *test_set, char *report_flags, char *output)
+{
+ bsd_results_t *rd;
+ int count;
+ int max_count;
+ int min_count;
+
+ rd = test_set->report_data;
+
+ if (rd == NULL) {
+ bsd_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) ||
+ ((test_set->confidence.value >= 0) && (count >= min_count))) {
+ print_results_summary(test_set);
+ if ((test_set->confidence.value < 0) && (min_count > 1)) {
+ print_did_not_meet_confidence(test_set);
+ }
+ }
+} /* end of report_bsd_test_results */
+
Added: trunk/suites/multi/nettest_multi.h
===================================================================
--- trunk/suites/multi/nettest_multi.h 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/nettest_multi.h 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,185 @@
+/* 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 BSD */
+ /* sockets tests */
+
+struct ring_elt {
+ struct ring_elt *next; /* next element in the ring */
+ char *buffer_base; /* in case we have to free it at somepoint */
+ char *buffer_ptr; /* the aligned and offset pointer */
+};
+
+typedef struct ring_elt *ring_elt_ptr;
+
+enum {
+ SEND_CALLS = 0,
+ BYTES_SENT,
+ RECV_CALLS,
+ BYTES_RECEIVED,
+ TRANS_SENT,
+ TRANS_RECEIVED,
+ CONNECT_CALLS,
+ ACCEPT_CALLS,
+ RETRANSMITS,
+ BSD_MAX_COUNTERS
+};
+
+typedef struct bsd_test_data {
+ /* address information */
+ struct addrinfo *locaddr; /* local address informtion */
+ struct addrinfo *remaddr; /* remote address informtion */
+
+ SOCKET s_listen; /* listen sockets for catching type tests */
+ SOCKET s_data; /* data socket for executing tests */
+
+ struct ring_elt *send_ring; /* address of the send_ring */
+ struct ring_elt *recv_ring; /* address of the recv_ring */
+ FILE *fill_source; /* pointer to file for filling rings */
+
+ /* send parameters */
+ int sbuf_size_ret; /* send socket buffer size returned on creation */
+ int send_buf_size; /* send socket buffer size */
+ int send_size; /* how many bytes to send at one time? */
+ int send_avoid; /* do we want to avoid send copies? */
+ int send_align; /* 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 */
+ int burst_count; /* number of sends in an interval or first burst */
+ int interval; /* minimum time from start to start of bursts */
+
+ /* recv parameters */
+ int rbuf_size_ret; /* receive socket buffer size returned on creation */
+ int recv_buf_size; /* receive socket buffer size */
+ int recv_size; /* how many bytes do receive at one time? */
+ int recv_avoid; /* do we want to avoid copies on receives? */
+ int recv_align; /* what is the alignment of the receive buffer? */
+ int recv_offset; /* and at what offset from that alignment? */
+ int recv_dirty_cnt; /* how many integers in the receive buffer */
+ /* should be made dirty before calling recv? */
+ int recv_clean_cnt; /* how many integers should be read from the */
+ /* recv buffer before calling recv? */
+
+ /* connection parameters */
+ /* request/response parameters */
+ int request_size; /* number of bytes to send */
+ int response_size; /* number of bytes to receive */
+
+ /* other parameters */
+ int port_min;
+ int port_max;
+ int send_width;
+ int recv_width;
+ int req_size;
+ int rsp_size;
+
+ /* data structures for UDP RR packet loss detection and retransmission. */
+ int retry_index;
+ int pending_responses;
+ char **retry_array; /* addresses of entries in the send_ring */
+
+ /* Statistics Counters */
+ union {
+ uint64_t counter[BSD_MAX_COUNTERS];
+ struct {
+ uint64_t send_calls;
+ uint64_t bytes_sent;
+ uint64_t recv_calls;
+ uint64_t bytes_received;
+ uint64_t trans_sent;
+ uint64_t trans_received;
+ uint64_t connect_calls;
+ uint64_t accepts;
+ uint64_t retransmits;
+ } named;
+ } stats;
+ struct timeval elapsed_time;
+ struct timeval prev_time;
+ struct timeval curr_time;
+
+ /* Place for HISTOGRAM fields */
+ HIST time_hist;
+} bsd_data_t;
+
+typedef struct bsd_results_data {
+ int max_count;
+ int print_test;
+ int print_run;
+ int print_per_cpu;
+ 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_interval;
+ double result_confidence;
+ double result_minimum;
+ double result_maximum;
+ double cpu_util_measured_mean;
+ double cpu_util_interval;
+ double cpu_util_confidence;
+ double service_demand_measured_mean;
+ double service_demand_interval;
+ double service_demand_confidence;
+ double confidence;
+ double sd_denominator;
+ double results_start; /* must be the last field in structure */
+} bsd_results_t;
+
+/* Error codes to be used within nettest_bsd */
+enum {
+ BSDE_MAX_ERROR = -32,
+ BSDE_SOCKET_SHUTDOWN_FAILED,
+ BSDE_BIND_FAILED,
+ BSDE_GETADDRINFO_ERROR,
+ BSDE_XMLSETPROP_ERROR,
+ BSDE_XMLNEWNODE_ERROR,
+ BSDE_NO_SOCKET_ARGS,
+ BSDE_SOCKET_ERROR,
+ BSDE_SETSOCKOPT_ERROR,
+ BSDE_LISTEN_FAILED,
+ BSDE_GETSOCKNAME_FAILED,
+ BSDE_REQUESTED_STATE_INVALID,
+ BSDE_ACCEPT_FAILED,
+ BSDE_DATA_RECV_ERROR,
+ BSDE_TEST_STATE_CORRUPTED,
+ BSDE_CONNECT_FAILED,
+ BSDE_DATA_CONNECTION_CLOSED_ERROR,
+ BSDE_DATA_SEND_ERROR=-1,
+ BSDE_SUCCESS = 0
+};
Added: trunk/suites/multi/prototype.c
===================================================================
--- trunk/suites/multi/prototype.c 2007-03-15 00:27:14 UTC (rev 215)
+++ trunk/suites/multi/prototype.c 2007-03-15 21:52:04 UTC (rev 216)
@@ -0,0 +1,835 @@
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int debug = 0;
+
+#define SOCKET int
+#define netperf_socklen_t socklen_t
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define CLOSE_SOCKET close
+
+/* connection FLAGS */
+#define CONNECTION_LISTENING 0x1
+#define CONNECTION_READING 0x2
+#define CONNECTION_WRITING 0x4
+#define CONNECTION_CLOSING 0x8
+
+typedef struct connection {
+ void *next;
+ void *prev;
+ void *buffer_base;
+ char *buffer_curr;
+ int sock;
+ int bytes_total;
+ int bytes_remaining;
+ int bytes_completed;
+ unsigned int flags;
+ int buffer_size;
+} connection_t;
+
+
+void
+dump_addrinfo(FILE *dumploc, struct addrinfo *info,
+ char *host, char *port, int family)
+{
+ struct sockaddr *ai_addr;
+ struct addrinfo *temp;
+ temp=info;
+
+ fprintf(dumploc,
+ "getaddrinfo returned the following for host '%s' ",
+ host ? (char *)host : "n/a");
+ fprintf(dumploc,
+ "port '%s' ",
+ port ? (char *)port : "n/a");
+ fprintf(dumploc, "family %d\n", family);
+ while (temp) {
+ /* I was under the impression that fprintf would be kind with
+ things like NULL string pointers, but when porting to Solaris,
+ this started dumping core, so we start to workaround it. raj
+ 2006-06-29 */
+ fprintf(dumploc,
+ "\tcannonical name: '%s'\n",
+ temp->ai_canonname ? temp->ai_canonname : "n/a");
+ fprintf(dumploc,
+ "\tflags: %x family: %d: socktype: %d protocol %d addrlen %d\n",
+ temp->ai_flags,
+ temp->ai_family,
+ temp->ai_socktype,
+ temp->ai_protocol,
+ temp->ai_addrlen);
+ ai_addr = temp->ai_addr;
+ if (ai_addr != NULL) {
+ fprintf(dumploc,
+ "\tsa_family: %d sadata: %d %d %d %d %d %d\n",
+ ai_addr->sa_family,
+ (u_char)ai_addr->sa_data[0],
+ (u_char)ai_addr->sa_data[1],
+ (u_char)ai_addr->sa_data[2],
+ (u_char)ai_addr->sa_data[3],
+ (u_char)ai_addr->sa_data[4],
+ (u_char)ai_addr->sa_data[5]);
+ }
+ temp = temp->ai_next;
+ }
+ fflush(dumploc);
+}
+
+
+SOCKET
+establish_listen(char *hostname, char *service, int af, netperf_socklen_t *addrlenp)
+{
+ SOCKET sockfd;
+ int error;
+ int count;
+ int len = *addrlenp;
+ int one = 1;
+ struct addrinfo hints, *res, *res_temp;
+
+ if (debug) {
+ fprintf(stderr,
+ "establish_listen: host '%s' service '%s' af %d socklen %d\n",
+ hostname ? hostname : "n/a",
+ service ? service : "n/a",
+ af,
+ len);
+ fflush(stderr);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ count = 0;
+ do {
+ error = getaddrinfo(hostname,
+ service,
+ &hints,
+ &res);
+ count += 1;
+ if (error == EAI_AGAIN) {
+ if (debug) {
+ fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n");
+ fflush(stderr);
+ }
+ usleep(1000);
+ }
+ } while ((error == EAI_AGAIN) && (count <= 5));
+
+ if (error) {
+ fprintf(stderr,
+ "establish_listen: could not resolve host '%s' service '%s'\n",
+ hostname,service);
+ fprintf(stderr,"\tgetaddrinfo returned %d %s\n",
+ error,gai_strerror(error));
+ fflush(stderr);
+ return(-1);
+ }
+
+
+ if (debug) {
+ dump_addrinfo(stderr, res, hostname,
+ service, AF_UNSPEC);
+ }
+
+ res_temp = res;
+
+ do {
+
+ sockfd = socket(res_temp->ai_family,
+ res_temp->ai_socktype,
+ res_temp->ai_protocol);
+ if (sockfd == INVALID_SOCKET) {
+ if (debug) {
+ fprintf(stderr,"establish_listen: socket error trying next one\n");
+ fflush(stderr);
+ }
+ continue;
+ }
+ /* The Windows DDK compiler is quite picky about pointers so we
+ cast one as a void to placate it. */
+ if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&one,sizeof(one)) ==
+ SOCKET_ERROR) {
+ fprintf(stderr,"establish_listen: SO_REUSEADDR failed\n");
+ fflush(stderr);
+ }
+ if (bind(sockfd, res_temp->ai_addr, res_temp->ai_addrlen) == 0) {
+ break;
+ }
+ fprintf(stderr,"establish_listen: bind error close and try next\n");
+ fflush(stderr);
+ CLOSE_SOCKET(sockfd);
+ } while ( (res_temp = res_temp->ai_next) != NULL );
+
+ if (res_temp == NULL) {
+ fprintf(stderr,"establish_listen: allocate server socket failed\n");
+ fflush(stderr);
+ sockfd = -1;
+ } else if (listen (sockfd,20) == -1) {
+ fprintf(stderr,"establish_listen: setting the listen backlog failed\n");
+ fflush(stderr);
+ CLOSE_SOCKET(sockfd);
+ sockfd = -1;
+ } else {
+ if (addrlenp) *addrlenp = res_temp->ai_addrlen;
+ }
+
+ fcntl(sockfd,F_SETFL, O_NONBLOCK);
+
+ freeaddrinfo(res);
+
+ return (sockfd);
+
+}
+
+
+typedef struct event_state_select {
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ int numfds;
+ int maxfd;
+ int minfd;
+} event_state_select_t;
+
+void *
+init_event_state() {
+ event_state_select_t *temp;
+
+ if (debug) {
+ fprintf(stderr,"Initializing event state\n");
+ }
+ temp = (event_state_select_t *)malloc(sizeof(event_state_select_t));
+ if (temp) {
+ FD_ZERO(&(temp->readfds));
+ FD_ZERO(&(temp->writefds));
+ FD_ZERO(&(temp->exceptfds));
+ }
+ temp->numfds = 0;
+ temp->maxfd = -1;
+ temp->minfd = -1;
+ if (debug) {
+ fprintf(stderr,
+ "Initialized event state at %p, readfds at %p\n",
+ temp,
+ &(temp->readfds));
+ }
+ return temp;
+}
+
+int
+clear_all_events(void *event_state, SOCKET sock) {
+
+ int i;
+ event_state_select_t *temp = event_state;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to clear sock %d from the event set at %p\n",
+ sock,
+ event_state);
+ }
+
+ FD_CLR(sock,&(temp->readfds));
+ FD_CLR(sock,&(temp->writefds));
+ FD_CLR(sock,&(temp->exceptfds));
+
+ temp->numfds -= 1;
+
+ if (debug) {
+ fprintf(stderr,
+ "initiating maxfd_check sock %d temp->maxfd %d\n",
+ sock,
+ temp->maxfd);
+ }
+
+ if (sock == temp->maxfd) {
+ for (i = temp->maxfd; i >= 0; i--) {
+ if (FD_ISSET(i,&(temp->readfds)) ||
+ FD_ISSET(i,&(temp->writefds)) ||
+ FD_ISSET(i, &(temp->exceptfds))) {
+ temp->maxfd = i;
+ if (debug) {
+ fprintf(stderr,"maxfd is now %d\n",i);
+ }
+ break;
+ }
+ }
+ }
+ else if (sock == temp->minfd) {
+ for (i = temp->minfd; i < FD_SETSIZE; i++) {
+ if (FD_ISSET(i,&(temp->readfds)) ||
+ FD_ISSET(i,&(temp->writefds)) ||
+ FD_ISSET(i, &(temp->exceptfds))) {
+ temp->minfd = i;
+ if (debug) {
+ fprintf(stderr,"maxfd is now %i\n",i);
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+
+}
+int
+set_readable_event(void *event_state, SOCKET sock) {
+ event_state_select_t *temp;
+ temp = event_state;
+ if (debug) {
+ fprintf(stderr,"requesting readability for socket %d\n",sock);
+ }
+ if (!FD_ISSET(sock,&(temp->readfds))) {
+ FD_SET(sock,&(temp->readfds));
+ temp->numfds += 1;
+ temp->maxfd = (sock > temp->maxfd) ? sock : temp->maxfd;
+ temp->minfd = (sock < temp->minfd) ? sock : temp->minfd;
+ }
+ if (debug) {
+ fprintf(stderr,"minfd is now %d maxfd is now %d\n",
+ temp->minfd,
+ temp->maxfd);
+ }
+ return 0;
+}
+
+int
+set_writable_event(void *event_state, SOCKET sock) {
+ event_state_select_t *temp;
+ temp = event_state;
+ if (debug) {
+ fprintf(stderr,"requesting writability for socket %d\n",sock);
+ }
+ if (!FD_ISSET(sock,&(temp->writefds))) {
+ FD_SET(sock,&(temp->writefds));
+ temp->numfds += 1;
+ temp->maxfd = (sock > temp->maxfd) ? sock : temp->maxfd;
+ temp->minfd = (sock < temp->maxfd) ? sock : temp->maxfd;
+ }
+ if (debug) {
+ fprintf(stderr,"maxfd is now %d\n",temp->maxfd);
+ }
+ return 0;
+}
+
+typedef struct uber_state {
+ connection_t *connection_list;
+ void *event_state;
+ int rdwr_since_accept;
+} uber_state_t;
+
+connection_t *
+find_connection(uber_state_t *uber_state, SOCKET sock) {
+
+ connection_t *temp;
+
+ temp = uber_state->connection_list;
+
+ if (debug) {
+ fprintf(stderr,
+ "searching connection list starting from %p for %d\n",temp,sock);
+ }
+ while (temp) {
+ if (debug) {
+ fprintf(stderr,"examining connection %p whose sock is %d\n",
+ temp,
+ temp->sock);
+ }
+ if (temp->sock == sock) break;
+ temp = temp->next;
+ }
+
+ if (debug) {
+ fprintf(stderr,"returning %p from find_connection\n",temp);
+ }
+ return temp;
+
+}
+int
+wait_for_events_and_walk(uber_state_t *uber_state) {
+ struct timeval timeout;
+ event_state_select_t *event_state = uber_state->event_state;
+
+ fd_set loc_readfds;
+ fd_set loc_writefds;
+
+ connection_t *temp_connection;
+
+ int ret;
+ int i;
+ int did_something;
+
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+
+ if (debug) {
+ fprintf(stderr,"about to go into select\n");
+ }
+
+ /* rather blunt, but should be effective for now */
+ memcpy(&loc_readfds, &(event_state->readfds),sizeof(fd_set));
+ memcpy(&loc_writefds, &(event_state->writefds),sizeof(fd_set));
+
+ ret = select(event_state->maxfd + 1,
+ &loc_readfds,
+ &loc_writefds,
+ NULL, /* ignore exception for now */
+ &timeout);
+
+ if (debug) {
+ fprintf(stderr,
+ "select returned %d errno %d minfd %d maxfd %d\n",
+ ret,
+ errno,
+ event_state->minfd,
+ event_state->maxfd);
+ }
+
+ if (ret > 0) {
+ /* first, the reads and accepts */
+ for (i = event_state->minfd; i <= event_state->maxfd; i++) {
+ if (FD_ISSET(i,&loc_readfds)) {
+ temp_connection = find_connection(uber_state,i);
+ if (debug) {
+ fprintf(stderr,
+ "fd %d is readable on connection %p\n",
+ i,
+ temp_connection);
+ }
+ /* is this our listen endpoint or something else? */
+ if (temp_connection->flags & CONNECTION_LISTENING ) {
+ /* accept a connection */
+ SOCKET new_sock;
+ new_sock = accept_new_connection(uber_state,
+ temp_connection);
+ if (INVALID_SOCKET != new_sock) {
+ /* on the very good chance that this new connection is for
+ an FD higher than our listen endpoint, we set
+ loc_readfds so we go ahead and try to read from the new
+ connection when we get to that point in our walk of the
+ fdset returned from select(). */
+ FD_SET(new_sock,&loc_readfds);
+ }
+ /* if we got one connection, we should see about draining
+ the accept queue, eventually module some limit on the
+ number of concurrent connections we will allow */
+ while (new_sock >= 0) {
+ new_sock = accept_new_connection(uber_state,
+ temp_connection);
+ if (INVALID_SOCKET != new_sock) {
+ /* on the very good chance that this new connection is for
+ an FD higher than our listen endpoint, we set
+ loc_readfds so we go ahead and try to read from the new
+ connection when we get to that point in our walk of the
+ fdset returned from select(). */
+ FD_SET(new_sock,&loc_readfds);
+ }
+ }
+ }
+ else if (temp_connection->flags & CONNECTION_READING) {
+ /* read some bytes */
+ }
+ else {
+ /* something screwy happened */
+ fprintf(stderr,
+ "YO, we got readable on connection %p but we weren't reading\n",
+ temp_connection);
+ }
+ }
+ }
+
+ /* now the writes */
+ for (i = event_state->minfd; i <= event_state->maxfd; i++) {
+ if (FD_ISSET(i,&loc_writefds)) {
+ temp_connection = find_connection(uber_state,i);
+ fprintf(stderr,
+ "fd %d is writable on connection %p\n",i,temp_connection);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+remove_old_connection(uber_state_t *uber_state, connection_t *old_connection) {
+
+ connection_t *prev_conn = NULL;
+ connection_t *curr_conn;
+
+ curr_conn = uber_state->connection_list;
+
+ while (NULL != curr_conn) {
+ if (curr_conn == old_connection) {
+ /* we have a match */
+ if (NULL != prev_conn) {
+ /* we were somewhere in the middle, or at the end */
+ prev_conn->next = curr_conn->next;
+ }
+ else {
+ /* we were at the beginning */
+ uber_state->connection_list = curr_conn->next;
+ }
+ break;
+ }
+ else {
+ prev_conn = curr_conn;
+ curr_conn = curr_conn->next;
+ }
+ }
+ /* whether we have found it in the list or not, we want to free the
+ buffers and the connection entry */
+ free(old_connection->buffer_base);
+ free(old_connection);
+
+ return 0;
+
+}
+connection_t *
+add_new_connection(uber_state_t *uber_state, SOCKET init_socket, int flags, int initial_buf_size) {
+ connection_t *temp_conn;
+
+ temp_conn = malloc(sizeof(connection_t));
+ if (NULL != temp_conn) {
+ temp_conn->sock = init_socket;
+ temp_conn->bytes_total = 1;
+ temp_conn->bytes_remaining = 1;
+ temp_conn->bytes_completed = 0;
+ temp_conn->flags = flags;
+ temp_conn->buffer_size = initial_buf_size;
+ temp_conn->buffer_base = NULL;
+ temp_conn->buffer_size = 0;
+ /* if the caller asked for an initial buffer to be allocated,
+ allocate one */
+ if (initial_buf_size > 0) {
+ temp_conn->buffer_base = malloc(initial_buf_size);
+ if (NULL != temp_conn->buffer_base) {
+ temp_conn->buffer_size = initial_buf_size;
+ }
+ }
+ /* doesn't matter here if buffer_base is NULL */
+ temp_conn->buffer_curr = temp_conn->buffer_base;
+ temp_conn->next = uber_state->connection_list;
+ uber_state->connection_list = temp_conn;
+ }
+ if (flags & (CONNECTION_READING | CONNECTION_LISTENING)) {
+ set_readable_event(uber_state->event_state,init_socket);
+ }
+ if (flags & CONNECTION_WRITING) {
+ set_writable_event(uber_state->event_state,init_socket);
+ }
+
+ return temp_conn;
+}
+
+int
+accept_new_connection(uber_state_t *uber_state, connection_t *listen_connection)
+{
+ SOCKET new_conn;
+ connection_t *new_connection;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to accept on connection %p fd %d\n",
+ listen_connection,
+ listen_connection->sock);
+ }
+
+ /* we don't care if the accept actually accepted a new connection,
+ just that we tried calling accept. */
+ uber_state->rdwr_since_accept = 0;
+
+
+ new_conn = accept(listen_connection->sock,NULL,NULL);
+
+ if (INVALID_SOCKET != new_conn) {
+
+ /* one day we will want to see if this is inherited across
+ accept() calls, but for now we just go ahead and make the
+ call */
+
+ fcntl(new_conn,F_SETFL, O_NONBLOCK);
+
+ new_connection = add_new_connection(uber_state,
+ new_conn,
+ CONNECTION_READING,
+ 128);
+ if (debug) {
+ fprintf(stderr,
+ "accepted a connection to %p on fd %d\n",
+ new_connection,
+ new_conn);
+ }
+ }
+
+ return new_conn;
+}
+
+int
+close_a_connection(uber_state_t *uber_state, connection_t *close_connection) {
+
+ int ret;
+
+ if (debug) {
+ fprintf(stderr,
+ "about to close connection %p\n",
+ close_connection);
+ }
+
+ ret = close(close_connection->sock);
+ if (debug) {
+ fprintf(stderr,"close_connection thinks event_state is %p\n",
+ uber_state->event_state);
+ }
+ ret = clear_all_events(uber_state->event_state,close_connection->sock);
+ /* mark the connection for removal at some later time, don't remove
+ it here because we may be called from a loop that is walking the
+ connection list */
+ close_connection->flags = CONNECTION_CLOSING;
+
+ /* ret = remove_old_connection(uber_state, close_connection); */
+
+ return 0;
+}
+
+int
+write_on_connection(uber_state_t *uber_state, connection_t *write_connection) {
+
+ int bytes_written;
+ int did_something=1;
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "about to write on connection %p\n",write_connection);
+ }
+
+ /* actually writing bytes doesn't matter, just that we tried */
+ uber_state->rdwr_since_accept += 1;
+
+ bytes_written = send(write_connection->sock,
+ write_connection->buffer_curr,
+ write_connection->bytes_remaining,
+ 0);
+
+ if (bytes_written > 0) {
+ /* wrote something, was it everything? */
+ write_connection->bytes_remaining -= bytes_written;
+ if (write_connection->bytes_remaining > 0) {
+ write_connection->buffer_curr =
+ write_connection->buffer_curr + bytes_written;
+ write_connection->flags = CONNECTION_WRITING;
+ }
+ else {
+ /* we wrote everything we wanted. set things up so we read next
+ time around */
+ write_connection->buffer_curr = write_connection->buffer_base;
+ write_connection->bytes_remaining = write_connection->bytes_total;
+ write_connection->flags = CONNECTION_READING;
+ }
+ }
+ else if (bytes_written == 0) {
+ /* didn't do anything */
+ did_something = 0;
+ }
+ else {
+ /* it was < 0 - wonder what the error was? */
+ did_something = 0;
+ }
+ if (debug > 2) {
+ fprintf(stderr,
+ "wrote %d bytes on connection %p\n",
+ bytes_written,
+ write_connection);
+ }
+ return did_something;
+}
+
+int
+read_on_connection(uber_state_t *uber_state, connection_t *read_connection) {
+
+ int bytes_read;
+ char *temp_buf;
+ int did_something = 1;
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "about to read <= %d bytes on connection %p\n",
+ read_connection->bytes_remaining,
+ read_connection);
+ }
+
+ /* we don't actually care if the recv returns any bytes, just that
+ we called recv. */
+ uber_state->rdwr_since_accept += 1;
+
+ bytes_read = recv(read_connection->sock,
+ read_connection->buffer_curr,
+ read_connection->bytes_remaining,
+ 0);
+
+ if (debug > 2) {
+ fprintf(stderr,
+ "read %d bytes from connection %p\n",
+ bytes_read,
+ read_connection);
+ }
+
+ if (bytes_read > 0) {
+ /* got some bytes */
+ read_connection->bytes_remaining -= bytes_read;
+ /* did we get all we wanted? */
+ if (!read_connection->bytes_remaining) {
+ /* yes we did. see about writing something back. if the write
+ call was able to write the entire response in one swell foop
+ it will leave us in CONNECTION_READING mode. otherwise it
+ will switch us to CONNECTION_WRITING mode until we complete
+ our writes. we can do this because we are a program that
+ does one thing at a time */
+ read_connection->bytes_remaining = read_connection->bytes_total;
+ read_connection->bytes_completed = 0;
+ write_on_connection(uber_state, read_connection);
+ }
+ }
+ else if (bytes_read == 0) {
+ uber_state->rdwr_since_accept += 1;
+ /* remote closed - should this count as having doen work or not? */
+ close_a_connection(uber_state,read_connection);
+ }
+ else {
+ /* it was < 0 we should reall check against EAGAIN */
+ /* errors or EAGAIN don't count as having done something */
+ did_something = 0;
+ }
+
+ return did_something;
+
+}
+
+int
+walk_connection_list(uber_state_t *uber_state) {
+
+ connection_t *temp_connection = uber_state->connection_list;
+ connection_t *del_connection;
+
+ int did_something = 0;
+ int ret;
+
+ while(temp_connection) {
+ switch (temp_connection->flags) {
+ case CONNECTION_LISTENING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a LISTEN connection\n",temp_connection);
+ }
+ /* only bother doing an accept on the blind walk of the list
+ when we've done some transactions. otherwise, the drop into
+ the select loop will catch things for us. we ass-u-me that
+ for the test the actual connection rate is << the transaction
+ rate. otherwise we'll need some additional heuristics -
+ perhaps domething involving how long it has been since an
+ accept() or how many consecutive accepts without a new
+ connection we've made. */
+ if (uber_state->rdwr_since_accept > 1000) {
+ ret = accept_new_connection(uber_state,temp_connection);
+ /* did we get one, and are there any more? */
+ while (ret > 0) {
+ /* if we came-in here, it means we got a connection above, so
+ we did do something. it probably isn't worth the added
+ conditional to only set did_something once... */
+ did_something = 1;
+ ret = accept_new_connection(uber_state,temp_connection);
+ }
+ }
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_READING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a READING connection\n",temp_connection);
+ }
+ ret = read_on_connection(uber_state,temp_connection);
+ if (ret > 0) did_something = 1;
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_WRITING:
+ if (debug > 2) {
+ fprintf(stderr,
+ "connection at %p is a WRITING connection\n",temp_connection);
+ }
+ ret = write_on_connection(uber_state,temp_connection);
+ if (ret > 0) did_something = 1;
+ temp_connection = temp_connection->next;
+ break;
+ case CONNECTION_CLOSING:
+ /* ok, just how should we deal with this then? */
+ del_connection = temp_connection;
+ temp_connection = temp_connection->next;
+ remove_old_connection(uber_state, del_connection);
+ break;
+ }
+ }
+ return did_something;
+}
+
+
+int
+main(int argc, char *argv[]) {
+
+ int temp;
+ int loops = 0;
+ int did_work;
+ socklen_t addrlen = sizeof(struct sockaddr_storage);
+ uber_state_t *uber_state;
+ event_state_select_t *mumble;
+ connection_t *connection_list;
+
+ connection_t *temp_connection;
+
+ uber_state = (uber_state_t *)malloc(sizeof(uber_state_t));
+ uber_state->connection_list = NULL;
+ uber_state->event_state = init_event_state();
+ mumble = uber_state->event_state;
+ uber_state->rdwr_since_accept = 0;
+
+ fprintf(stderr,"Hello there, let's handle some transactions. Uberstate %p connection_list %p event_state %p\n", uber_state,uber_state->connection_list,uber_state->event_state);
+
+ temp = establish_listen(argv[1],argv[2],AF_INET,&addrlen);
+
+ /* initialize our event_state minfd */
+ mumble->minfd = temp;
+
+ temp_connection = add_new_connection(uber_state,
+ temp,
+ CONNECTION_LISTENING,
+ 0);
+
+ fprintf(stderr,"temp_connection is at %p\n",temp_connection);
+
+ do {
+ loops++;
+ if (debug > 1) {
+ fprintf(stderr,"\nabout to walk loop %d\n",loops);
+ }
+ did_work = walk_connection_list(uber_state);
+ if (!did_work) {
+ if (debug) {
+ fprintf(stderr,
+ "walk_connection_list did no work, time to wait\n");
+ }
+ did_work = wait_for_events_and_walk(uber_state);
+ }
+ } while (1);
+
+}
More information about the netperf-dev
mailing list