[netperf-dev] netperf2 commit notice r164 - in trunk: . src
raj at netperf.org
raj at netperf.org
Fri Jan 11 16:51:22 PST 2008
Author: raj
Date: 2008-01-11 16:51:20 -0800 (Fri, 11 Jan 2008)
New Revision: 164
Added:
trunk/src/nettest_omni.c
Modified:
trunk/AUTHORS
trunk/Release_Notes
trunk/config.h.in
trunk/configure
trunk/configure.ac
trunk/src/Makefile.am
trunk/src/Makefile.in
trunk/src/netlib.h
trunk/src/nettest_bsd.c
trunk/src/nettest_bsd.h
Log:
checkin first bits of non-working omni code
Modified: trunk/AUTHORS
===================================================================
--- trunk/AUTHORS 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/AUTHORS 2008-01-12 00:51:20 UTC (rev 164)
@@ -210,6 +210,8 @@
Alexander Duyck
Fixes to replace struct sockaddr_in with struct sockaddr_storage
+Fixes to UDP_RR to preclude hangs on Windows
+Fizes to UDP_RR to honour -f and -B options
Anonymous
Support for sendfile() on OSX
Modified: trunk/Release_Notes
===================================================================
--- trunk/Release_Notes 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/Release_Notes 2008-01-12 00:51:20 UTC (rev 164)
@@ -2,6 +2,13 @@
Things changed in this release:
+*) The UDP_RR test now understands the global -f option to change
+ output units. It also understands the -B option to tag
+ results. Courtesy of Alexander Duyck.
+
+*) A fix has been added for hanging UDP_RR tests under
+ Windows. Courtesy of Alexander Duyck.
+
*) Use vfork() on those platforms without fork(), courtesy of Matt
Waddel
Modified: trunk/config.h.in
===================================================================
--- trunk/config.h.in 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/config.h.in 2008-01-12 00:51:20 UTC (rev 164)
@@ -307,6 +307,9 @@
/* Define to one to enable paced operation support. May affect results. */
#undef WANT_INTERVALS
+/* Define to one to include OMNI tests. */
+#undef WANT_OMNI
+
/* Define to one to include SCTP tests. */
#undef WANT_SCTP
Modified: trunk/configure
===================================================================
--- trunk/configure 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/configure 2008-01-12 00:51:20 UTC (rev 164)
@@ -1305,6 +1305,7 @@
results.
--enable-unixdomain include Unix Domain socket tests
--enable-dlpi include DLPI (link-layer) tests
+ --enable-omni include OMNI (link-layer) tests
--enable-xti include XTI socket tests
--enable-sdp include SDP socket tests
--enable-exs include ICSC async sockets tests
@@ -7864,7 +7865,53 @@
fi
+# see if we should be including the OMNI tests
+{ echo "$as_me:$LINENO: checking whether to include OMNI tests" >&5
+echo $ECHO_N "checking whether to include OMNI tests... $ECHO_C" >&6; }
+
+# Check whether --enable-omni was given.
+if test "${enable_omni+set}" = set; then
+ enableval=$enable_omni;
+fi
+
+
+case "$enable_omni" in
+ yes)
+ use_omni=true
+ ;;
+ no)
+ use_omni=false
+ ;;
+ '')
+ use_omni=false
+ ;;
+ *)
+ { { echo "$as_me:$LINENO: error: --enable-omni takes yes or no" >&5
+echo "$as_me: error: --enable-omni takes yes or no" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+esac
+
+if $use_omni
+then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+if $use_omni
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define WANT_OMNI
+_ACEOF
+
+fi
+
+
# see if we should be including the XTI tests
{ echo "$as_me:$LINENO: checking whether to include XTI tests" >&5
Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/configure.ac 2008-01-12 00:51:20 UTC (rev 164)
@@ -267,7 +267,41 @@
AC_DEFINE([WANT_DLPI],,[Define to one to include DLPI tests.])
fi
+# see if we should be including the OMNI tests
+AC_MSG_CHECKING(whether to include OMNI tests)
+
+AC_ARG_ENABLE(omni,
+ [AS_HELP_STRING([--enable-omni],[include OMNI (link-layer) tests])])
+
+case "$enable_omni" in
+ yes)
+ use_omni=true
+ ;;
+ no)
+ use_omni=false
+ ;;
+ '')
+ use_omni=false
+ ;;
+ *)
+ AC_MSG_ERROR([--enable-omni takes yes or no])
+ ;;
+esac
+
+if $use_omni
+then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+if $use_omni
+then
+ AC_DEFINE([WANT_OMNI],,[Define to one to include OMNI tests.])
+fi
+
+
# see if we should be including the XTI tests
AC_MSG_CHECKING(whether to include XTI tests)
Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/src/Makefile.am 2008-01-12 00:51:20 UTC (rev 164)
@@ -10,7 +10,7 @@
EXTRA_DIST = netcpu_none.c netcpu_looper.c netcpu_pstat.c netcpu_pstatnew.c netcpu_perfstat.c netcpu_procstat.c netcpu_kstat.c netcpu_kstat10.c netcpu_sysctl.c netcpu_ntperf.c netcpu_osx.c dirs NetPerfDir/* NetServerDir/* netperf_version.h.in
-COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h
+COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h nettest_omni.c
netperf_SOURCES = netperf.c $(COMMON_SRC) $(USE_CPU_SOURCE)
netserver_SOURCES = netserver.c $(COMMON_SRC) $(USE_CPU_SOURCE)
Modified: trunk/src/Makefile.in
===================================================================
--- trunk/src/Makefile.in 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/src/Makefile.in 2008-01-12 00:51:20 UTC (rev 164)
@@ -139,7 +139,7 @@
EXTRA_DIST = netcpu_none.c netcpu_looper.c netcpu_pstat.c netcpu_pstatnew.c netcpu_perfstat.c netcpu_procstat.c netcpu_kstat.c netcpu_kstat10.c netcpu_sysctl.c netcpu_ntperf.c netcpu_osx.c dirs NetPerfDir/* NetServerDir/* netperf_version.h.in
-COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h
+COMMON_SRC = hist.h netlib.c netlib.h netcpu.h netsh.c netsh.h nettest_bsd.c nettest_bsd.h nettest_dlpi.c nettest_dlpi.h nettest_unix.c nettest_unix.h nettest_xti.c nettest_xti.h nettest_sctp.c nettest_sctp.h netperf_version.h nettest_sdp.c nettest_sdp.h nettest_omni.c
netperf_SOURCES = netperf.c $(COMMON_SRC) $(USE_CPU_SOURCE)
netserver_SOURCES = netserver.c $(COMMON_SRC) $(USE_CPU_SOURCE)
@@ -158,7 +158,7 @@
am__objects_1 = netlib.$(OBJEXT) netsh.$(OBJEXT) nettest_bsd.$(OBJEXT) \
nettest_dlpi.$(OBJEXT) nettest_unix.$(OBJEXT) \
nettest_xti.$(OBJEXT) nettest_sctp.$(OBJEXT) \
- nettest_sdp.$(OBJEXT)
+ nettest_sdp.$(OBJEXT) nettest_omni.$(OBJEXT)
am__objects_2 = netcpu_ at NETCPU_SOURCE@.$(OBJEXT)
am_netperf_OBJECTS = netperf.$(OBJEXT) $(am__objects_1) $(am__objects_2)
netperf_OBJECTS = $(am_netperf_OBJECTS)
@@ -180,6 +180,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/netserver.Po ./$(DEPDIR)/netsh.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/nettest_bsd.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/nettest_dlpi.Po \
+ at AMDEP_TRUE@ ./$(DEPDIR)/nettest_omni.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/nettest_sctp.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/nettest_sdp.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/nettest_unix.Po \
@@ -254,6 +255,7 @@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/netsh.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_bsd.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_dlpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_omni.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_sctp.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_sdp.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/nettest_unix.Po at am__quote@
Modified: trunk/src/netlib.h
===================================================================
--- trunk/src/netlib.h 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/src/netlib.h 2008-01-12 00:51:20 UTC (rev 164)
@@ -158,6 +158,10 @@
#define TCP_MAERTS_RESPONSE 95
#define TCP_MAERTS_RESULTS 96
+#define DO_OMNI 97
+#define OMNI_RESPONSE 98
+#define OMNI_RESULTS 99
+
#define DO_LWPSTR_STREAM 100
#define LWPSTR_STREAM_RESPONSE 110
#define LWPSTR_STREAM_RESULTS 120
@@ -349,7 +353,8 @@
(((return_value) == SOCKET_ERROR) && \
((errno == EINTR) || \
(errno == WSAECONNABORTED) || \
- (errno == WSAECONNRESET) ))
+ (errno == WSAECONNRESET) || \
+ (errno == ENOTSOCK) ))
#define SOCKET_EADDRINUSE(return_value) \
(((return_value) == SOCKET_ERROR) && \
((errno == WSAEADDRINUSE) ))
Modified: trunk/src/nettest_bsd.c
===================================================================
--- trunk/src/nettest_bsd.c 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/src/nettest_bsd.c 2008-01-12 00:51:20 UTC (rev 164)
@@ -816,6 +816,30 @@
}
}
+static void
+extract_inet_address_and_port(struct addrinfo *res, void *addr, int len, int *port)
+{
+ switch(res->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *foo = (struct sockaddr_in *)res->ai_addr;
+ *port = foo->sin_port;
+ memcpy(addr,&(foo->sin_addr),min(len,sizeof(foo->sin_addr)));
+ break;
+ }
+#if defined(AF_INET6)
+ case AF_INET6: {
+ struct sockaddr_in6 *foo = (struct sockaddr_in6 *)res->ai_addr;
+ *port = foo->sin6_port;
+ memcpy(addr,&(foo->sin6_addr),min(len,sizeof(foo->sin6_addr)));
+ break;
+ }
+#endif
+ default:
+ *port = 0xDEADBEEF;
+ strncpy(addr,"UNKN FAMILY",len);
+ }
+}
+
/* this routine will set the port number of the sockaddr in the
addrinfo to the specified value, based on the address family */
void
@@ -1958,7 +1982,7 @@
"%7.2f %s\n";
char *tput_fmt_1 =
- "%6d %6d %6d %-6.2f %7.2f %s \n";
+ "%6d %6d %6d %-6.2f %7.2f %s\n";
char *cpu_title = "\
Recv Send Send Utilization Service Demand\n\
@@ -6822,12 +6846,19 @@
Socket Size Request Resp. Elapsed Trans.\n\
Send Recv Size Size Time Rate \n\
bytes Bytes bytes bytes secs. per sec \n\n";
+
+ char *tput_title_band = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed \n\
+Send Recv Size Size Time Throughput \n\
+bytes Bytes bytes bytes secs. %s/sec \n\n";
char *tput_fmt_0 =
- "%7.2f\n";
+ "%7.2f %s\n";
char *tput_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
+%-6d %-6d %-6d %-6d %-6.2f %7.2f %s\n";
+
char *tput_fmt_1_line_2 = "\
%-6d %-6d\n";
@@ -6836,12 +6867,18 @@
Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
Send Recv Size Size Time Rate local remote local remote\n\
bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
+
+ char *cpu_title_tput = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Tput CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time %-8.8s local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %c %% %c us/Tr us/Tr\n\n";
char *cpu_fmt_0 =
- "%6.3f %c\n";
+ "%6.3f %c %s\n";
char *cpu_fmt_1_line_1 = "\
-%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
+%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f %s\n";
char *cpu_fmt_1_line_2 = "\
%-6d %-6d\n";
@@ -7067,7 +7104,14 @@
/* Set-up the test end conditions. For a request/response test, they */
/* can be either time or transaction based. */
-
+
+#ifdef WIN32
+ /* The test timer can fire during recv operations on the socket,
+ so to make the start_timer below work we have to move
+ it to close send_socket while we are blocked on recv. */
+ win_kludge_socket = send_socket;
+#endif /* WIN32 */
+
if (test_time) {
/* The user wanted to end the test after a period of time. */
times_up = 0;
@@ -7344,22 +7388,37 @@
fprintf(where,
cpu_fmt_0,
local_service_demand,
- local_cpu_method);
+ local_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+
}
else {
fprintf(where,
cpu_fmt_0,
remote_service_demand,
- remote_cpu_method);
+ remote_cpu_method,
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
+
}
break;
case 1:
case 2:
if (print_headers) {
- fprintf(where,
- cpu_title,
- local_cpu_method,
- remote_cpu_method);
+ if ('x' == libfmt) {
+ fprintf(where,
+ cpu_title,
+ local_cpu_method,
+ remote_cpu_method);
+ }
+ else {
+ fprintf(where,
+ cpu_title_tput,
+ format_units(),
+ local_cpu_method,
+ remote_cpu_method);
+ }
}
fprintf(where,
@@ -7369,11 +7428,15 @@
req_size, /* how large were the requests */
rsp_size, /* guess */
elapsed_time, /* how long was the test */
- nummessages/elapsed_time,
+ ('x' == libfmt) ? thruput :
+ calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+ 1.0),
local_cpu_utilization, /* local cpu */
remote_cpu_utilization, /* remote cpu */
local_service_demand, /* local service demand */
- remote_service_demand); /* remote service demand */
+ remote_service_demand, /* remote service demand */
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
fprintf(where,
cpu_fmt_1_line_2,
rss_size,
@@ -7387,12 +7450,18 @@
case 0:
fprintf(where,
tput_fmt_0,
- nummessages/elapsed_time);
+ ('x' == libfmt) ? thruput :
+ calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+ 1.0),
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
break;
case 1:
case 2:
if (print_headers) {
- fprintf(where,tput_title,format_units());
+ fprintf(where,
+ ('x' == libfmt) ? tput_title : tput_title_band,
+ format_units());
}
fprintf(where,
@@ -7402,7 +7471,11 @@
req_size, /* how large were the requests */
rsp_size, /* how large were the responses */
elapsed_time, /* how long did it take */
- nummessages/elapsed_time);
+ ('x' == libfmt) ? thruput :
+ calc_thruput_interval_omni(thruput * (req_size+rsp_size),
+ 1.0),
+ ((print_headers) ||
+ (result_brand == NULL)) ? "" : result_brand);
fprintf(where,
tput_fmt_1_line_2,
rss_size, /* remote recvbuf size */
Modified: trunk/src/nettest_bsd.h
===================================================================
--- trunk/src/nettest_bsd.h 2007-12-08 00:01:02 UTC (rev 163)
+++ trunk/src/nettest_bsd.h 2008-01-12 00:51:20 UTC (rev 164)
@@ -15,6 +15,87 @@
#define NF_INET 4
#define NF_INET6 6
+#ifdef WANT_OMNI
+struct omni_request_struct {
+ int32_t send_buf_size; /* SO_SNDBUF */
+ uint32_t send_size; /* bytes per send() call */
+ uint32_t send_alignment; /* alignment of send buffer */
+ uint32_t send_offset; /* offset from send alignment */
+ uint32_t request_size; /* size of a request */
+
+ int32_t recv_buf_size; /* SO_RCVBUF */
+ uint32_t receive_size; /* size of buffers in recv */
+ uint32_t recv_alignment; /* alignment of recv buffer */
+ uint32_t recv_offset; /* offset from recv alignment */
+ uint32_t response_size; /* size of a response */
+
+ uint32_t no_delay; /* do we set mumble_NODELAY? */
+ uint32_t use_sendfile; /* use sendfile rather than send? */
+ uint32_t connect_test; /* does the test include connect? */
+
+ uint32_t measure_cpu; /* do we measure CPU? */
+ float cpu_rate; /* do we know how fast the cpu is already? */
+
+ int32_t test_length; /* how long is the test? */
+
+ uint32_t so_rcvavoid; /* avoid copies on recv? */
+ uint32_t so_sndavoid; /* avoid copies on send? */
+ uint32_t send_dirty_count; /* bytes to dirty before calling send */
+ uint32_t recv_dirty_count; /* bytes to dirty before calling recv */
+ uint32_t recv_clean_count; /* bytes to access before calling recv */
+
+ uint32_t checksum_off; /* should checksums be disabled? */
+ uint32_t data_port; /* what port number should netserver use? */
+ uint32_t ipfamily; /* address family of the data connection */
+ uint32_t socket_type; /* dgram? stream? other? */
+ uint32_t protocol; /* the protocol of the data connection */
+ uint32_t direction; /* which way flows the data? */
+ uint32_t netperf_port; /* when netserver needs netperf's data port */
+ uint32_t ipaddr[4]; /* when netserver needs netperf's data IP */
+};
+
+struct omni_response_struct {
+ int32_t recv_buf_size;
+ uint32_t receive_size;
+
+ int32_t send_buf_size;
+ uint32_t send_size;
+
+ uint32_t no_delay;
+ uint32_t use_sendfile;
+
+ uint32_t measure_cpu;
+ float cpu_rate;
+
+ uint32_t test_length;
+
+ uint32_t so_rcvavoid;
+ uint32_t so_sndavoid;
+
+ uint32_t data_port; /* connect to this port number */
+};
+
+struct omni_results_struct {
+ double bytes_received;
+ uint32_t recv_calls;
+ int32_t recv_buf_size; /* SO_RCVBUF at end of test */
+
+ double bytes_sent;
+ uint32_t send_calls;
+ int32_t send_buf_size; /* SO_SNDBUF at end of test */
+
+ uint32_t trans_received;
+
+ float elapsed_time; /* length of test in seconds */
+
+ float cpu_util;
+ float serv_dem;
+ uint32_t cpu_method; /* how was CPU util measured? */
+ uint32_t num_cpus; /* number of CPUs in remote */
+};
+
+#endif /* WANT_OMNI */
+
struct tcp_stream_request_struct {
int send_buf_size;
int recv_buf_size; /* how big does the client want it - the */
@@ -64,6 +145,8 @@
float serv_dem; /* -1 if not measured */
int cpu_method; /* how was cpu util measured? */
int num_cpus; /* how many CPUs had the remote? */
+ int recv_buf_size; /* how large was it at the end? */
+ int send_buf_size; /* how large was it at the end? */
};
struct tcp_maerts_request_struct {
Added: trunk/src/nettest_omni.c
===================================================================
--- trunk/src/nettest_omni.c (rev 0)
+++ trunk/src/nettest_omni.c 2008-01-12 00:51:20 UTC (rev 164)
@@ -0,0 +1,1962 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WANT_OMNI
+char nettest_omni_id[]="\
+@(#)nettest_dlpi.c (c) Copyright 2008 Hewlett-Packard Co. Version 2.5.0pre";
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#ifndef WIN32
+#include <errno.h>
+#include <signal.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef NOSTDLIBH
+#include <malloc.h>
+#endif /* NOSTDLIBH */
+
+#ifdef WANT_SCTP
+#include <netinet/sctp.h>
+#endif
+
+#ifndef WIN32
+#if !defined(__VMS)
+#include <sys/ipc.h>
+#endif /* !defined(__VMS) */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#else /* WIN32 */
+#include <process.h>
+#define netperf_socklen_t socklen_t
+#include <winsock2.h>
+
+/* while it is unlikely that anyone running Windows 2000 or NT 4 is
+ going to be trying to compile this, if they are they will want to
+ define DONT_IPV6 in the sources file */
+#ifndef DONT_IPV6
+#include <ws2tcpip.h>
+#endif
+#include <windows.h>
+
+#define sleep(x) Sleep((x)*1000)
+
+#define __func__ __FUNCTION__
+#endif /* WIN32 */
+
+/* We don't want to use bare constants in the shutdown() call. In the
+ extremely unlikely event that SHUT_WR isn't defined, we will define
+ it to the value we used to be passing to shutdown() anyway. raj
+ 2007-02-08 */
+#if !defined(SHUT_WR)
+#define SHUT_WR 1
+#endif
+
+#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
+# include "missing/getaddrinfo.h"
+#endif
+
+#include "netlib.h"
+#include "netsh.h"
+#include "nettest_bsd.h"
+
+#if defined(WANT_HISTOGRAM) || defined(WANT_DEMO)
+#include "hist.h"
+#endif /* WANT_HISTOGRAM */
+
+#define NETPERF_WAITALL 0x1
+#define NETPERF_XMIT 0x2
+#define NETPERF_RECV 0x4
+
+/* a boatload of globals while I settle things out */
+int socket_type;
+int protocol;
+int direction;
+int remote_send_size;
+int remote_recv_size;
+int remote_use_sendfile;
+int connect_test;
+int remote_send_dirty_count;
+int remote_recv_dirty_count;
+int remote_recv_clean_count;
+int remote_checksum_off;
+int connection_test;
+int need_to_connect;
+int need_connection;
+int bytes_to_send;
+int bytes_per_send;
+int failed_sends;
+int bytes_to_recv;
+int bytes_per_recv;
+int null_message_ok;
+uint64_t trans_completed;
+uint64_t units_remaining;
+uint64_t bytes_sent;
+uint64_t bytes_received;
+uint64_t send_calls;
+uint64_t receive_calls;
+uint64_t remote_bytes_sent;
+uint64_t remote_bytes_received;
+uint64_t remote_send_calls;
+uint64_t remote_receive_calls;
+
+/* make first_burst_size unconditional so we can use it easily enough
+ when calculating transaction latency for the TCP_RR test. raj
+ 2007-06-08 */
+int first_burst_size=0;
+
+#if defined(HAVE_SENDFILE) && (defined(__linux) || defined(__sun))
+#include <sys/sendfile.h>
+#endif /* HAVE_SENDFILE && (__linux || __sun) */
+
+static char local_cpu_method;
+static char remote_cpu_method;
+
+/* these will control the width of port numbers we try to use in the */
+/* TCP_CRR and/or TCP_TRR tests. raj 3/95 */
+static int client_port_min = 5000;
+static int client_port_max = 65535;
+
+ /* different options for the sockets */
+
+int
+ loc_nodelay, /* don't/do use NODELAY locally */
+ rem_nodelay, /* don't/do use NODELAY remotely */
+#ifdef TCP_CORK
+ loc_tcpcork=0, /* don't/do use TCP_CORK locally */
+ rem_tcpcork=0, /* don't/do use TCP_CORK remotely */
+#endif /* TCP_CORK */
+ loc_sndavoid, /* avoid send copies locally */
+ loc_rcvavoid, /* avoid recv copies locally */
+ rem_sndavoid, /* avoid send copies remotely */
+ rem_rcvavoid, /* avoid recv_copies remotely */
+ local_connected = 0, /* local socket type, connected/non-connected */
+ remote_connected = 0; /* remote socket type, connected/non-connected */
+
+
+void
+pick_next_port_number(struct addrinfo *local_res, struct addrinfo *remote_res) {
+
+ static int myport_init = 0;
+ static myport = 0;
+
+ if (0 == myport_init) {
+ /* pick a nice random spot between client_port_min and
+ client_port_max for our initial port number, but only for a
+ connection oriented test. otherwise, we will want to set myport
+ to a specific port provided by the user if they have so provided
+ a specific port :) raj 2008-01-08 */
+ srand(getpid());
+ if (client_port_max - client_port_min) {
+ myport = client_port_min +
+ (rand() % (client_port_max - client_port_min));
+ }
+ else {
+ myport = client_port_min;
+ }
+ /* there will be a ++ before the first call to bind, so subtract one */
+ myport--;
+ myport_init = 1;
+ }
+
+ newport:
+ /* pick a new port number */
+ myport++;
+
+ /* check to see if we are using the port number on which the
+ server is sitting _before_ we check against the boundaries lest
+ the server sits at the upper boundary. if this happens to be a
+ loopback test, trying to use the same portnumber would lead to
+ unsatisfying results and should be avoided. if this isn't a
+ loopback test, avoiding using the same port number doesn't
+ seriously affect anything anyway */
+
+ if (myport == get_port_number(remote_res)) myport++;
+
+ /* wrap the port number when we reach the upper bound. for
+ students of networking history, some ancient stacks (1980's and
+ early 1990's perhaps) mistakenly treated these port numbers as
+ signed 16 bit quantities. we make no effort here to support
+ such stacks. raj 2008-01-08 */
+ if (myport >= client_port_max) {
+ myport = client_port_min;
+ }
+
+ /* set up the data socket */
+ set_port_number(local_res, (unsigned short)myport);
+}
+
+/* for the next few routines (connect, accept, send, recv,
+ disconnect/close) we will use a return of -1 to mean times up, -2
+ to mean a transient error (eg ENOBUFS on a UDP send call) and -3 to
+ mean hard error. this means it is ok for the connect routine to
+ return a 0 (zero) if that happens to be the fd/SOCKET we get and in
+ theory we will be able to support zero-length messages on those
+ protocols which support it. all in theory of course. raj
+ 2008-01-09 */
+
+int
+connect_data_socket(SOCKET send_socket, struct addrinfo *remote_res)
+{
+ int ret;
+
+ /* Connect up to the remote port on the data socket */
+ if ((ret = connect(send_socket,
+ remote_res->ai_addr,
+ remote_res->ai_addrlen)) == INVALID_SOCKET) {
+ if (SOCKET_EINTR(ret)) {
+ /* we interpret this to mean that the test is supposed to be
+ over, so return a value of -1 to the caller */
+ return -1;
+ }
+ if ((SOCKET_EADDRINUSE(ret)) || SOCKET_EADDRNOTAVAIL(ret)) {
+ /* likely something our explicit bind() would have caught in
+ the past, so go get another port, via create_data_socket.
+ yes, this is a bit more overhead than before, but the
+ condition should be rather rare. we only get a new port if
+ this was a connection-including test like TCP_CRR or
+ TCP_CC. Otherwise we need to return an error. raj
+ 2008-01-08 */
+ return -2;
+ }
+ else
+ /* -3 means there was an error */
+ return -3;
+ }
+ return 0;
+}
+
+int
+send_data(SOCKET data_socket, struct ring_elt *send_ring, uint32_t bytes_to_send, uint32_t bytes_per_send, struct sockaddr *destination, int destlen) {
+
+ int len;
+
+ /* if the user has supplied a destination, we use sendto, otherwise
+ we use send. we ass-u-me blocking operations always, so no need
+ to check for eagain or the like. */
+
+ if (destination) {
+ len = sendto(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send,
+ 0,
+ destination,
+ destlen);
+ }
+ else {
+ len = send(data_socket,
+ send_ring->buffer_ptr,
+ bytes_to_send,
+ 0);
+ }
+ if(len != bytes_to_send) {
+ if (SOCKET_EINTR(len))
+ {
+ /* we hit the end of a timed test. */
+ return -1;
+ }
+ /* if this is UDP it is possible to receive an ENOBUFS on the send
+ call and it would not be a fatal error. of course if we were
+ to return 0 then it would make the test think it was over when
+ it really wasn't. the question becomes what to do. for the
+ time being, the answer will likely be to return something like
+ -2 to indicate a non-fatal error happened on the send and let
+ the caller figure it out :) we won't actually check to see if
+ this is UDP - it is the author's experience in many, Many, MANY
+ years that the only time an ENOBUFS has been returned in a
+ netperf test has been with UDP. famous last words :) */
+ if (errno == ENOBUFS)
+ return -2;
+ else {
+ fprintf(where,"send_data: data send error: errno %d",errno);
+ return -3;
+ }
+ }
+ return len;
+}
+
+int
+recv_data(SOCKET data_socket, struct ring_elt *recv_ring, uint32_t bytes_to_recv, struct sockaddr *source, int *sourcelen, uint32_t flags, uint32_t *num_receives) {
+
+ void * temp_message_ptr;
+ int bytes_left;
+ int bytes_recvd;
+ int my_recvs;
+
+ /* receive data off the data_socket, ass-u-me-ing a blocking socket
+ all the way!-) 2008-01-08 */
+ my_recvs = 0;
+ bytes_left = bytes_to_recv;
+ temp_message_ptr = recv_ring->buffer_ptr;
+
+ do {
+ if (source) {
+ /* call recvfrom it does look a little silly here inside the do
+ while, but I think it is ok - a UDP or other DGRAM or
+ SEQPACKET (?) socket, which should be the only time we
+ pass-in a source pointer will have a semantic that should get
+ us out of the dowhile on the first call anyway. if it
+ turns-out not to be the case, then we can hoist the if above
+ the do and put the dowhile in the else. */
+ bytes_recvd = recvfrom(data_socket,
+ temp_message_ptr,
+ bytes_left,
+ 0,
+ source,
+ sourcelen);
+ }
+ else {
+ /* just call recv */
+ bytes_recvd = recv(data_socket,
+ temp_message_ptr,
+ bytes_left,
+ 0);
+ }
+ if (bytes_recvd > 0) {
+ bytes_left -= bytes_recvd;
+ temp_message_ptr += bytes_recvd;
+ }
+ else {
+ break;
+ }
+ my_recvs++;
+ } while ((bytes_left > 0) && (flags & NETPERF_WAITALL));
+
+ *num_receives = my_recvs;
+
+ /* OK, we are out of the loop - now what? */
+ if (bytes_recvd < 0) {
+ /* did the timer hit, or was there an error? */
+ if (SOCKET_EINTR(bytes_recvd))
+ {
+ /* We hit the end of a timed test. */
+ return -1;
+ }
+ /* it was a hard error */
+ return -3;
+ }
+
+
+ /* this looks a little funny, but should be correct. if we had
+ NETPERF_WAITALL set and we got here, it means we got all the
+ bytes of the request/response. otherwise we would have hit the
+ error or end of test cases. if NETPERF_WAITALL isn't set, this
+ is a STREAM test, and we will have only made one call to recv, so
+ bytes_recvd will be accurate. */
+ if (bytes_left)
+ return bytes_recvd;
+ else
+ return bytes_to_recv;
+
+}
+
+
+int
+disconnect_data_socket(SOCKET data_socket, int initiate, int do_close)
+{
+
+ char buffer[4];
+ int bytes_recvd;
+
+ if (initiate)
+ shutdown(data_socket, SHUT_WR);
+
+ /* we are expecting to get either a return of zero indicating
+ connection close, or an error. */
+ bytes_recvd = recv(data_socket,
+ buffer,
+ 1,
+ 0);
+
+ if (bytes_recvd != 0) {
+ /* connection close, call close. we assume that the requisite */
+ /* number of bytes have been received */
+ if (SOCKET_EINTR(bytes_recvd))
+ {
+ /* We hit the end of a timed test. */
+ return 0;
+ }
+ return -1;
+ }
+
+ if (do_close)
+ close(data_socket);
+
+ return 1;
+}
+
+ /* this code is intended to be "the two routines to run them all" for
+ BSDish sockets. it comes about as part of a desire to shrink the
+ code footprint of netperf and to avoid having so many blessed
+ routines to alter as time goes by. the downside is there will be
+ more "ifs" than there were before. there may be some other
+ "complications" for things like demo mode or perhaps histograms if
+ we ever want to track individual RTTs when burst mode is in use
+ etc etc... raj 2008-01-07 */
+
+void
+send_omni(char remote_host[])
+{
+
+ char *tput_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans.\n\
+Send Recv Size Size Time Rate \n\
+bytes Bytes bytes bytes secs. per sec \n\n";
+
+ char *tput_fmt_0 =
+ "%7.2f\n";
+
+ char *tput_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %7.2f \n";
+ char *tput_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *cpu_title = "\
+Local /Remote\n\
+Socket Size Request Resp. Elapsed Trans. CPU CPU S.dem S.dem\n\
+Send Recv Size Size Time Rate local remote local remote\n\
+bytes bytes bytes bytes secs. per sec %% %% us/Tr us/Tr\n\n";
+
+ char *cpu_fmt_0 =
+ "%6.3f\n";
+
+ char *cpu_fmt_1_line_1 = "\
+%-6d %-6d %-6d %-6d %-6.2f %-6.2f %-6.2f %-6.2f %-6.3f %-6.3f\n";
+
+ char *cpu_fmt_1_line_2 = "\
+%-6d %-6d\n";
+
+ char *ksink_fmt = "\n\
+Alignment Offset\n\
+Local Remote Local Remote\n\
+Send Recv Send Recv\n\
+%5d %5d %5d %5d\n";
+
+
+ int timed_out = 0;
+ float elapsed_time;
+
+ int len;
+ int ret;
+ int connected;
+
+ struct ring_elt *send_ring;
+ struct ring_elt *recv_ring;
+
+ struct sockaddr_storage remote_addr;
+ int remote_addr_len = sizeof(remote_addr);
+
+ SOCKET data_socket;
+ int need_socket;
+
+ double bytes_xferd;
+
+ float local_cpu_utilization;
+ float local_service_demand;
+ float remote_cpu_utilization;
+ float remote_service_demand;
+ double thruput;
+
+ struct addrinfo *local_res;
+ struct addrinfo *remote_res;
+
+ struct omni_request_struct *omni_request;
+ struct omni_response_struct *omni_response;
+ struct omni_results_struct *omni_result;
+
+ omni_request =
+ (struct omni_request_struct *)netperf_request.content.test_specific_data;
+ omni_response =
+ (struct omni_response_struct *)netperf_response.content.test_specific_data;
+ omni_result =
+ (struct omni_results_struct *)netperf_response.content.test_specific_data;
+
+
+#ifdef WANT_HISTOGRAM
+ if (verbosity > 1) {
+ time_hist = HIST_new();
+ }
+#endif /* WANT_HISTOGRAM */
+
+ /* since we are now disconnected from the code that established the
+ control socket, and since we want to be able to use different
+ protocols and such, we are passed the name of the remote host and
+ must turn that into the test specific addressing information. */
+
+ complete_addrinfos(&remote_res,
+ &local_res,
+ remote_host,
+ socket_type,
+ protocol,
+ 0);
+
+ if ( print_headers ) {
+ print_top_test_header("OMNI TEST",local_res,remote_res);
+ }
+
+ /* initialize a few counters */
+
+ bytes_xferd = 0.0;
+ times_up = 0;
+ need_socket = 1;
+
+ /* we need to consider if this is a request/response test, if we are
+ receiving, if we are sending, etc, when setting-up our recv and
+ send buffer rings. raj 2008-01-07 */
+ if (direction & NETPERF_XMIT) {
+ if (req_size > 0) {
+ /* request/response test */
+ if (send_width == 0) send_width = 1;
+ }
+ else {
+ /* stream test */
+ if (send_width == 0)
+ send_width = (lss_size/send_size) + 1;
+ if (send_width == 1) send_width++;
+ }
+
+ send_ring = allocate_buffer_ring(send_width,
+ (req_size > 0) ? req_size : send_size,
+ local_send_align,
+ local_send_offset);
+ if (debug) {
+ fprintf(where,
+ "send_omni: %d entry send_ring obtained...\n",
+ send_width);
+ }
+ }
+
+ if (direction & NETPERF_RECV) {
+ if (rsp_size > 0) {
+ if (recv_width == 0) recv_width = 1;
+ }
+ else {
+ /* stream test */
+ if (recv_width == 0) {
+ recv_width = (lsr_size/recv_size) + 1;
+ if (recv_width == 1) recv_width++;
+ }
+ }
+
+ recv_ring = allocate_buffer_ring(recv_width,
+ (rsp_size > 0) ? rsp_size : send_size,
+ local_recv_align,
+ local_recv_offset);
+ if (debug) {
+ fprintf(where,
+ "send_omni: %d entry recv_ring obtained...\n",
+ recv_width);
+ }
+ }
+
+
+
+ /* If the user has requested cpu utilization measurements, we must */
+ /* calibrate the cpu(s). We will perform this task within the tests */
+ /* themselves. If the user has specified the cpu rate, then */
+ /* calibrate_local_cpu will return rather quickly as it will have */
+ /* nothing to do. If local_cpu_rate is zero, then we will go through */
+ /* all the "normal" calibration stuff and return the rate back.*/
+
+ if (local_cpu_usage) {
+ local_cpu_rate = calibrate_local_cpu(local_cpu_rate);
+ }
+
+ if (!no_control) {
+
+ /* Tell the remote end to do a listen or otherwise prepare for
+ what is to come. The server alters the socket paramters on the
+ other side at this point, hence the reason for all the values
+ being passed in the setup message. If the user did not specify
+ any of the parameters, they will be passed as values which will
+ indicate to the remote that no changes beyond the system's
+ default should be used. Alignment is the exception, it will
+ default to 8, which will probably be no alignment
+ alterations. */
+
+ netperf_request.content.request_type = DO_OMNI;
+ omni_request->send_buf_size = rss_size_req;
+ omni_request->send_size = remote_send_size;
+ omni_request->send_alignment = remote_send_align;
+ omni_request->send_offset = remote_send_offset;
+ omni_request->request_size = req_size;
+
+ omni_request->recv_buf_size = rsr_size_req;
+ omni_request->receive_size = remote_recv_size;
+ omni_request->recv_alignment = remote_recv_align;
+ omni_request->recv_offset = remote_recv_offset;
+ omni_request->response_size = rsp_size;
+
+ omni_request->no_delay = rem_nodelay;
+ omni_request->use_sendfile = remote_use_sendfile;
+ omni_request->connect_test = connect_test;
+
+ omni_request->measure_cpu = remote_cpu_usage;
+ omni_request->cpu_rate = remote_cpu_rate;
+ if (test_time) {
+ omni_request->test_length = test_time;
+ }
+ else {
+ omni_request->test_length = test_trans * -1;
+ }
+ omni_request->so_rcvavoid = rem_rcvavoid;
+ omni_request->so_sndavoid = rem_sndavoid;
+ omni_request->send_dirty_count = remote_send_dirty_count;
+ omni_request->recv_dirty_count = remote_recv_dirty_count;
+ omni_request->recv_clean_count = remote_recv_clean_count;
+
+ omni_request->checksum_off = remote_checksum_off;
+ omni_request->data_port = atoi(remote_data_port);
+ omni_request->ipfamily = af_to_nf(remote_res->ai_family);
+ omni_request->socket_type = socket_type;
+ omni_request->protocol = protocol;
+
+ omni_request->direction = 0;
+ /* yes, the sense here is correct - if we are transmitting, they
+ receive, if we are receiving, they are transmitting... */
+ if (direction & NETPERF_XMIT)
+ omni_request->direction |= NETPERF_RECV;
+ if (direction & NETPERF_RECV)
+ omni_request->direction |= NETPERF_XMIT;
+
+ /* some tests may require knowledge of our local addressing. such
+ tests will for the time being require that the user specify a
+ local IP/name and port number, so we can extract them from the
+ local_res addrinfo. we "know" that the ipaddr "array" has
+ enough space for a full ipv6 address */
+ extract_inet_address_and_port(local_res,
+ omni_request->ipaddr,
+ sizeof(omni_request->ipaddr),
+ &(omni_request->netperf_port));
+
+ if (debug > 1) {
+ fprintf(where,"netperf: send_omni: requesting OMNI test\n");
+ }
+
+ send_request();
+
+ /* The response from the remote will contain all of the relevant
+ socket parameters for this test type. We will put them back
+ into the variables here so they can be displayed if desired.
+ The remote will have calibrated CPU if necessary, and will have
+ done all the needed set-up we will have calibrated the cpu
+ locally before sending the request, and will grab the counter
+ value right after the connect returns. The remote will grab the
+ counter right after the accept call. This saves the hassle of
+ extra messages being sent for the TCP tests. */
+
+ recv_response();
+
+ if (!netperf_response.content.serv_errno) {
+ rsr_size = omni_response->recv_buf_size;
+ remote_recv_size = omni_response->receive_size;
+ rss_size = omni_response->send_buf_size;
+ remote_send_size = omni_response->send_size;
+ rem_nodelay = omni_response->no_delay;
+ remote_use_sendfile = omni_response->use_sendfile;
+ remote_cpu_usage = omni_response->measure_cpu;
+ remote_cpu_rate = omni_response->cpu_rate;
+ /* make sure that port numbers are in network order */
+ set_port_number(remote_res,
+ (unsigned short)omni_response->data_port);
+
+ if (debug) {
+ fprintf(where,"remote listen done.\n");
+ fprintf(where,"remote port is %u\n",get_port_number(remote_res));
+ fflush(where);
+ }
+ }
+ else {
+ Set_errno(netperf_response.content.serv_errno);
+ fprintf(where,
+ "netperf: remote error %d",
+ netperf_response.content.serv_errno);
+ perror("");
+ fflush(where);
+ exit(1);
+ }
+ }
+#ifdef WANT_DEMO
+ DEMO_RR_SETUP(100);
+#endif
+
+ /* Set-up the test end conditions. For tests over a
+ "reliable/connection-oriented" transport (eg TCP, SCTP, etc) this
+ can be either time or byte/transaction count based. for
+ unreliable transport or connection tests it can only be time
+ based. having said that, we rely entirely on other code to
+ enforce this before we even get here. raj 2008-01-08 */
+
+ if (test_time) {
+ /* The user wanted to end the test after a period of time. */
+ times_up = 0;
+ units_remaining = 0;
+ start_timer(test_time);
+ }
+ else {
+ /* The tester wanted to send a number of bytes or exchange a
+ number of transactions. */
+ if ((direction & NETPERF_XMIT) && (direction & NETPERF_RECV))
+ units_remaining = test_trans;
+ else
+ units_remaining = test_bytes;
+ times_up = 1;
+ }
+
+ /* grab the current time, and if necessary any starting information
+ for the gathering of CPU utilization at this end. */
+ cpu_start(local_cpu_usage);
+
+#ifdef WANT_DEMO
+ if (demo_mode) {
+ HIST_timestamp(demo_one_ptr);
+ }
+#endif
+
+ /* the "OR" here allows us to control test length by either
+ byte/transaction count or by timer. when the test is
+ byte/transaction count based the time test will always evaluate
+ false. when the test is controlled by time, the byte/transaction
+ count will always evaluate to false. when the test is finished
+ the whole expression will go false and we will stop sending
+ data. at least that is the plan :) raj 2008-01-08 */
+
+ while ((!times_up) || (units_remaining > 0)) {
+
+#ifdef WANT_HISTOGRAM
+ /* only pull the timestamp if we are actually going to use the
+ results of the work. we put the call here so it can work for
+ any sort of test - connection, request/response, or stream.
+ no, it isn't "perfect" for all of them - for some it will
+ include a few more "if's" than a purpose-written routine, but
+ it _should_ be the case that the time spent up here is epsilon
+ compared to time spent elsewhere in the stack so it should not
+ be a big deal. famous last words of raj 2008-01-08 */
+ if (verbosity > 1) {
+ HIST_timestamp(&time_one);
+ }
+#endif /* WANT_HISTOGRAM */
+
+again:
+
+ if (need_socket) {
+ if (connection_test)
+ pick_next_port_number(local_res,remote_res);
+
+ data_socket = create_data_socket(local_res);
+
+ if (data_socket == INVALID_SOCKET) {
+ perror("netperf: send_omni: unable to create data socket");
+ exit(1);
+ }
+ need_socket = 0;
+ }
+
+ /* only connect if and when we need to */
+ if (need_to_connect) {
+ /* assign to data_socket since connect_data_socket returns
+ SOCKET and not int thanks to Windows. */
+ ret = connect_data_socket(data_socket,remote_res);
+ if (ret == 0) {
+ connected = 1;
+ need_to_connect = 0;
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ break;
+ }
+ else if ((ret == -2) && connection_test) {
+ /* transient error on a connection test means go around and
+ try again with another local port number */
+ close(data_socket);
+ need_socket = 1;
+ /* this will stuff the next local port number within bounds
+ into our local res, and then when the goto has us
+ allocating a new socket it will do the right thing with the
+ bind() call */
+ pick_next_port_number(local_res,remote_res);
+ goto again;
+ }
+ else {
+ /* either this was a hard failure (-3) or a soft failure on
+ something other than a connection test */
+ perror("netperf: send_omni: connect_data_socket failed");
+ exit(1);
+ }
+ }
+
+
+ /* if we should try to send something, then by all means, let us
+ try to send something. */
+ if (direction & NETPERF_XMIT) {
+ ret = send_data(data_socket,
+ send_ring,
+ bytes_to_send,
+ bytes_per_send,
+ (connected) ? NULL : remote_res->ai_addr,
+ /* if the destination above is NULL, this is ignored */
+ remote_res->ai_addrlen);
+
+ /* the order of these if's will seem a triffle strange, but they
+ are my best guess as to order of probabilty and/or importance
+ to the overhead raj 2008-01-09*/
+ if (ret == bytes_to_send) {
+ /* if this is a send-only test controlled by byte count we
+ decrement units_remaining by the bytes sent */
+ if (!(direction & NETPERF_RECV) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_sent += ret;
+ send_ring = send_ring->next;
+ }
+ else if (ret == -2) {
+ /* what to do here -2 means a non-fatal error - probably
+ ENOBUFS and so our send didn't happen. in the old code for
+ UDP_STREAM we would just continue in the while loop. it
+ isn't clear that is what to do here, so we will simply
+ increment the failed_sends stat and fall-through. If this
+ is a UDP_STREAM style of test, the net effect should be the
+ same. if this is a UDP_RR with a really-big burst count, I
+ don't think we were checking for ENOBUFS there anyway and
+ so would have failed. Here we can just let things
+ slide. */
+ failed_sends++;
+ }
+ else if (ret == 0) {
+ /* was this a zero-byte send? if it was, then ostensibly we
+ would hit the ret == bytes_to_send case which means we'd
+ never get here as we are using blocking semantics */
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ break;
+ }
+ else {
+ perror("netperf: send_omni: send_data failed");
+ exit(1);
+ }
+
+ }
+
+
+ if (direction & NETPERF_RECV) {
+ ret = recv_data(data_socket,
+ recv_ring,
+ bytes_to_recv,
+ bytes_per_recv,
+ (connected) ? NULL : (struct sockaddr *)&remote_addr,
+ /* if remote_addr NULL this is ignored */
+ &remote_addr_len);
+ if (ret > 0) {
+ /* if this is a recv-only test controlled by byte count we
+ decrement the units_remaining by the bytes received */
+ if (!(direction & NETPERF_XMIT) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_received += ret;
+ }
+ else if (ret == 0) {
+ /* is this the end of a test, just a zero-byte recv, or
+ something else? that is an exceedingly good question and
+ one for which I don't presently have a good answer, but
+ that won't stop me from guessing :) raj 2008-01-09 */
+ if (!((connection_test) || (null_message_ok))) {
+ /* if it is neither a connection_test nor null_message_ok it
+ must be the end of the test */
+ times_up = 1;
+ break;
+ }
+ }
+ else if (ret == -1) {
+ /* test timed-out */
+ times_up = 1;
+ break;
+ }
+ else {
+ /* presently at least, -2 and -3 are equally bad on recv */
+ perror("netperf: send_omni: recv_data failed");
+ exit(1);
+ }
+ recv_ring = recv_ring->next;
+ }
+
+
+ /* if this is a connection test, we want to do some stuff about
+ connection close here in the test loop. raj 2008-01-08 */
+ if (connection_test) {
+ ret = disconnect_data_socket(data_socket,
+ (no_control) ? 1 : 0,
+ 1);
+ if (ret == 0) {
+ /* we will need a new connection to be established next time
+ around the loop */
+ need_connection = 1;
+ connected = 0;
+ need_socket;
+ pick_next_port_number(local_res,remote_res);
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ break;
+ }
+ else {
+ perror("netperf: send_omni: disconnect_data_socket failed");
+ exit(1);
+ }
+ }
+
+
+#ifdef WANT_HISTOGRAM
+ if (verbosity > 1) {
+ HIST_timestamp(&time_two);
+ HIST_add(time_hist,delta_micro(&time_one,&time_two));
+ }
+#endif /* WANT_HISTOGRAM */
+
+#ifdef WANT_DEMO
+ DEMO_RR_INTERVAL(1);
+#endif
+
+ /* was this a "transaction" test? don't for get that a TCP_CC
+ style test will have no xmit or recv :) so, we check for either
+ both XMIT and RECV set, or neither XMIT nor RECV set */
+ if (((direction & NETPERF_XMIT) && (direction & NETPERF_RECV)) ||
+ !((direction & NETPERF_XMIT) || (direction & NETPERF_RECV))) {
+ trans_completed++;
+ if (units_remaining) {
+ units_remaining--;
+ }
+ }
+
+
+ }
+
+ /* we are now, ostensibly, at the end of this iteration */
+
+ /* so, if we have/had a data connection, we will want to close it
+ now, and this will be independent of whether there is a control
+ connection. */
+ if (connected) {
+ /* before we do close the connection, we may want to retrieve some
+ of the socket parameters - Linux, thanks to its autotuning, can
+ have the final socket buffer sizes different from the initial
+ socket buffer sizes. isn't that nice. raj 2008-01-08 */
+ /* FILL THIS IN; */
+ /* CHECK PARMRS HERE; */
+ ret = disconnect_data_socket(data_socket,
+ (no_control) ? 1 : 0,
+ 1);
+ }
+
+ /* this call will always give us the elapsed time for the test, and
+ will also store-away the necessaries for cpu utilization */
+
+ cpu_stop(local_cpu_usage,&elapsed_time);
+
+ if (!no_control) {
+ /* Get the statistics from the remote end. The remote will have
+ calculated service demand and all those interesting things. If
+ it wasn't supposed to care, it will return obvious values. */
+
+ recv_response();
+ if (!netperf_response.content.serv_errno) {
+ if (debug)
+ fprintf(where,"remote results obtained\n");
+ }
+ else {
+ Set_errno(netperf_response.content.serv_errno);
+ fprintf(where,
+ "netperf: remote error %d",
+ netperf_response.content.serv_errno);
+ perror("");
+ fflush(where);
+
+ exit(1);
+ }
+ }
+
+ /* so, what was the end result? */
+
+ bytes_xferd = bytes_sent + bytes_received;
+ thruput = calc_thruput(bytes_xferd);
+
+ if (local_cpu_usage || remote_cpu_usage) {
+ /* We must now do a little math for service demand and cpu */
+ /* utilization for the system(s) */
+ /* Of course, some of the information might be bogus because */
+ /* there was no idle counter in the kernel(s). We need to make */
+ /* a note of this for the user's benefit...*/
+ if (local_cpu_usage) {
+ if (local_cpu_rate == 0.0) {
+ fprintf(where,
+ "WARNING WARNING WARNING WARNING WARNING WARNING WARNING!\n");
+ fprintf(where,
+ "Local CPU usage numbers based on process information only!\n");
+ fflush(where);
+ }
+ local_cpu_utilization = calc_cpu_util(0.0);
+ /* since calc_service demand is doing ms/Kunit we will */
+ /* multiply the number of transaction by 1024 to get */
+ /* "good" numbers */
+ local_service_demand = calc_service_demand((double) nummessages*1024,
+ 0.0,
+ 0.0,
+ 0);
+ }
+ else {
+ local_cpu_utilization = (float) -1.0;
+ local_service_demand = (float) -1.0;
+ }
+
+ if (remote_cpu_usage) {
+ if (remote_cpu_rate == 0.0) {
+ fprintf(where,
+ "DANGER DANGER DANGER DANGER DANGER DANGER DANGER!\n");
+ fprintf(where,
+ "Remote CPU usage numbers based on process information only!\n");
+ fflush(where);
+ }
+ remote_cpu_utilization = omni_result->cpu_util;
+ /* since calc_service demand is doing ms/Kunit we will */
+ /* multiply the number of transaction by 1024 to get */
+ /* "good" numbers */
+ remote_service_demand = calc_service_demand((double) nummessages*1024,
+ 0.0,
+ remote_cpu_utilization,
+ omni_result->num_cpus);
+ }
+ else {
+ remote_cpu_utilization = (float) -1.0;
+ remote_service_demand = (float) -1.0;
+ }
+
+ /* We are now ready to print all the information. If the user */
+ /* has specified zero-level verbosity, we will just print the */
+ /* local service demand, or the remote service demand. If the */
+ /* user has requested verbosity level 1, he will get the basic */
+ /* "streamperf" numbers. If the user has specified a verbosity */
+ /* of greater than 1, we will display a veritable plethora of */
+ /* background information from outside of this block as it it */
+ /* not cpu_measurement specific... */
+
+ switch (verbosity) {
+ case 0:
+ if (local_cpu_usage) {
+ fprintf(where,
+ cpu_fmt_0,
+ local_service_demand);
+ }
+ else {
+ fprintf(where,
+ cpu_fmt_0,
+ remote_service_demand);
+ }
+ break;
+ case 1:
+ case 2:
+
+ if (print_headers) {
+ fprintf(where,
+ cpu_title,
+ local_cpu_method,
+ remote_cpu_method);
+ }
+
+ fprintf(where,
+ cpu_fmt_1_line_1, /* the format string */
+ lss_size, /* local sendbuf size */
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* guess */
+ elapsed_time, /* how long was the test */
+ nummessages/elapsed_time,
+ local_cpu_utilization, /* local cpu */
+ remote_cpu_utilization, /* remote cpu */
+ local_service_demand, /* local service demand */
+ remote_service_demand); /* remote service demand */
+ fprintf(where,
+ cpu_fmt_1_line_2,
+ rss_size,
+ rsr_size);
+ break;
+ }
+ }
+ else {
+ /* The tester did not wish to measure service demand. */
+ switch (verbosity) {
+ case 0:
+ fprintf(where,
+ tput_fmt_0,
+ nummessages/elapsed_time);
+ break;
+ case 1:
+ case 2:
+ if (print_headers) {
+ fprintf(where,tput_title,format_units());
+ }
+
+ fprintf(where,
+ tput_fmt_1_line_1, /* the format string */
+ lss_size,
+ lsr_size,
+ req_size, /* how large were the requests */
+ rsp_size, /* how large were the responses */
+ elapsed_time, /* how long did it take */
+ nummessages/elapsed_time);
+ fprintf(where,
+ tput_fmt_1_line_2,
+ rss_size, /* remote recvbuf size */
+ rsr_size);
+
+ break;
+ }
+ }
+
+ /* it would be a good thing to include information about some of the */
+ /* other parameters that may have been set for this test, but at the */
+ /* moment, I do not wish to figure-out all the formatting, so I will */
+ /* just put this comment here to help remind me that it is something */
+ /* that should be done at a later time. */
+
+ if (verbosity > 1) {
+ /* The user wanted to know it all, so we will give it to him. */
+ /* This information will include as much as we can find about */
+ /* TCP statistics, the alignments of the sends and receives */
+ /* and all that sort of rot... */
+
+ fprintf(where,
+ ksink_fmt,
+ local_send_align,
+ remote_recv_offset,
+ local_send_offset,
+ remote_recv_offset);
+
+#ifdef WANT_HISTOGRAM
+ fprintf(where,"\nHistogram of request/response times\n");
+ fflush(where);
+ HIST_report(time_hist);
+#endif /* WANT_HISTOGRAM */
+
+ }
+
+}
+
+
+
+/* the name is something of a misnomer since this test could send, or
+ receive, or both, but it matches the historical netperf routine
+ naming. */
+void
+recv_omni()
+{
+
+ char *message;
+ struct addrinfo *local_res;
+ char local_name[BUFSIZ];
+ char port_buffer[PORTBUFSIZE];
+
+ struct sockaddr_storage myaddr_in, peeraddr_in;
+ SOCKET s_listen, data_socket;
+ netperf_socklen_t addrlen;
+
+ struct ring_elt *send_ring;
+ struct ring_elt *recv_ring;
+
+ int timed_out = 0;
+ int need_to_connect;
+ int need_to_accept;
+ int connected;
+ int ret;
+ float elapsed_time;
+
+ struct omni_request_struct *omni_request;
+ struct omni_response_struct *omni_response;
+ struct omni_results_struct *omni_results;
+
+ omni_request =
+ (struct omni_request_struct *)netperf_request.content.test_specific_data;
+ omni_response =
+ (struct omni_response_struct *)netperf_response.content.test_specific_data;
+ omni_results =
+ (struct omni_results_struct *)netperf_response.content.test_specific_data;
+
+ if (debug) {
+ fprintf(where,"netserver: recv_omni: entered...\n");
+ fflush(where);
+ }
+
+ /* based on what we have been told by the remote netperf, we want to
+ setup our endpoint for the "data connection" and let the remote
+ netperf know the situation. */
+
+ if (debug) {
+ fprintf(where,"recv_omni: setting the response type...\n");
+ fflush(where);
+ }
+
+ netperf_response.content.response_type = OMNI_RESPONSE;
+
+ if (debug) {
+ fprintf(where,"recv_omni: the response type is set...\n");
+ fflush(where);
+ }
+
+ /* We now alter the message_ptr variables to be at the desired */
+ /* alignments with the desired offsets. */
+
+ if (debug) {
+ fprintf(where,
+ "recv_omni: requested recv alignment of %d offset %d\n",
+ omni_request->recv_alignment,
+ omni_request->recv_offset);
+ fprintf(where,
+ "recv_omni: requested send alignment of %d offset %d\n",
+ omni_request->send_alignment,
+ omni_request->send_offset);
+ fflush(where);
+ }
+
+ if (omni_request->direction & NETPERF_XMIT) {
+ send_ring = allocate_buffer_ring(send_width,
+ (omni_request->response_size) ?
+omni_request->response_size : omni_request->send_size,
+ omni_request->send_alignment,
+ omni_request->send_offset);
+
+ }
+
+ if (omni_request->direction & NETPERF_RECV) {
+ recv_ring = allocate_buffer_ring(send_width,
+ (omni_request->request_size) ? omni_request->request_size : omni_request->receive_size,
+ omni_request->recv_alignment,
+ omni_request->recv_offset);
+
+ }
+
+ /* Grab a socket to listen on, and then listen on it. */
+
+ if (debug) {
+ fprintf(where,"recv_omni: grabbing a socket...\n");
+ fflush(where);
+ }
+
+ /* create_data_socket expects to find some things in the global
+ variables, so set the globals based on the values in the request.
+ once the socket has been created, we will set the response values
+ based on the updated value of those globals. raj 7/94 */
+ lss_size_req = omni_request->send_buf_size;
+ lsr_size_req = omni_request->recv_buf_size;
+ loc_nodelay = omni_request->no_delay;
+ loc_rcvavoid = omni_request->so_rcvavoid;
+ loc_sndavoid = omni_request->so_sndavoid;
+
+ set_hostname_and_port(local_name,
+ port_buffer,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->data_port);
+
+ local_res = complete_addrinfo(local_name,
+ local_name,
+ port_buffer,
+ nf_to_af(omni_request->ipfamily),
+ omni_request->socket_type,
+ omni_request->protocol,
+ 0);
+
+ s_listen = create_data_socket(local_res);
+
+ if (s_listen == INVALID_SOCKET) {
+ netperf_response.content.serv_errno = errno;
+ send_response();
+ if (debug) {
+ fprintf(where,"could not create data socket\n");
+ fflush(where);
+ }
+ exit(1);
+ }
+
+#ifdef WIN32
+ /* The test timer can fire during operations on the listening socket,
+ so to make the start_timer below work we have to move
+ it to close s_listen while we are blocked on accept. */
+ win_kludge_socket2 = s_listen;
+#endif
+
+ /* if this is an actual connection test, then we need to call
+ listen() on the socket. since we don't expect to have multple
+ connections outstanding on the endpoint, we can get-by with an
+ otherwise tiny backlog. raj 2008-01-11 */
+
+ if (omni_request->connect_test) {
+ if (listen(s_listen, 5) == SOCKET_ERROR) {
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,"could not listen\n");
+ fflush(where);
+ }
+ exit(1);
+ }
+ }
+
+ /* now get the port number assigned by the system */
+ addrlen = sizeof(myaddr_in);
+ if (getsockname(s_listen,
+ (struct sockaddr *)&myaddr_in,
+ &addrlen) == SOCKET_ERROR){
+ netperf_response.content.serv_errno = errno;
+ close(s_listen);
+ send_response();
+ if (debug) {
+ fprintf(where,"could not getsockname\n");
+ fflush(where);
+ }
+ exit(1);
+ }
+
+ /* Now myaddr_in contains the port and the internet address this is
+ returned to the sender also implicitly telling the sender that
+ the socket buffer sizing has been done. likely as not, the IP
+ address will be the wildcard - so we only really need to extract
+ the port number. since send_response is going to call htonl on
+ all the fields, we want to initially put the port number in there
+ in host order. */
+
+ omni_response->data_port =
+ (int) ntohs(((struct sockaddr_in *)&myaddr_in)->sin_port);
+ if (debug) {
+ fprintf(where,"telling the remote to call me at %d\n",
+ omni_response->data_port);
+ fflush(where);
+ }
+ netperf_response.content.serv_errno = 0;
+
+ /* But wait, there's more. If the initiator wanted cpu measurements, */
+ /* then we must call the calibrate routine, which will return the max */
+ /* rate back to the initiator. If the CPU was not to be measured, or */
+ /* something went wrong with the calibration, we will return a 0.0 to */
+ /* the initiator. */
+
+ omni_response->cpu_rate = (float)0.0; /* assume no cpu */
+ if (omni_request->measure_cpu) {
+ omni_response->measure_cpu = 1;
+ omni_response->cpu_rate =
+ calibrate_local_cpu(omni_request->cpu_rate);
+ }
+
+
+
+ /* before we send the response back to the initiator, pull some of */
+ /* the socket parms from the globals */
+ omni_response->send_buf_size = lss_size;
+ omni_response->recv_buf_size = lsr_size;
+ omni_response->no_delay = loc_nodelay;
+ omni_response->so_rcvavoid = loc_rcvavoid;
+ omni_response->so_sndavoid = loc_sndavoid;
+
+ send_response();
+
+ addrlen = sizeof(peeraddr_in);
+
+ /* Now it's time to start receiving data on the connection. We will */
+ /* first grab the apropriate counters and then start grabbing. */
+
+ cpu_start(omni_request->measure_cpu);
+
+ /* The loop will exit when the sender does a shutdown, which will */
+ /* return a length of zero */
+
+ if (omni_request->test_length > 0) {
+ times_up = 0;
+ units_remaining = 0;
+ start_timer(omni_request->test_length + PAD_TIME);
+ }
+ else {
+ times_up = 1;
+ units_remaining = omni_request->test_length * -1;
+ }
+
+ trans_completed = 0;
+
+ while ((!times_up) || (units_remaining > 0)) {
+
+ if (need_to_accept) {
+ /* accept a connection from the remote */
+#ifdef WIN32
+ /* The test timer will probably fire during this accept,
+ so to make the start_timer above work we have to move
+ it to close s_listen while we are blocked on accept. */
+ win_kludge_socket = s_listen;
+#endif
+ if ((data_socket=accept(s_listen,
+ (struct sockaddr *)&peeraddr_in,
+ &addrlen)) == INVALID_SOCKET) {
+ if (errno == EINTR) {
+ /* the timer popped */
+ timed_out = 1;
+ break;
+ }
+ fprintf(where,"recv_omni: accept: errno = %d\n",errno);
+ fflush(where);
+ close(s_listen);
+
+ exit(1);
+ }
+
+ if (debug) {
+ fprintf(where,"recv_omni: accepted data connection.\n");
+ fflush(where);
+ }
+ need_to_accept = 0;
+ connected = 1;
+
+#ifdef KLUDGE_SOCKET_OPTIONS
+ /* this is for those systems which *INCORRECTLY* fail to pass
+ attributes across an accept() call. Including this goes
+ against my better judgement :( raj 11/95 */
+
+ kludge_socket_options(data_socket);
+
+#endif /* KLUDGE_SOCKET_OPTIONS */
+
+ }
+
+ if (need_to_connect) {
+ /* initially this will only be used for UDP tests as a TCP or
+ other connection-oriented test will always have us making an
+ accept() call raj 2008-01-11 */
+ }
+
+#ifdef WIN32
+ /* this is used so the timer thread can close the socket out from
+ under us, which to date is the easiest/cleanest/least
+ Windows-specific way I can find to force the winsock calls to
+ return WSAEINTR with the test is over. anything that will run on
+ 95 and NT and is closer to what netperf expects from Unix signals
+ and such would be appreciated raj 1/96 */
+ win_kludge_socket = data_socket;
+#endif /* WIN32 */
+
+ /* in recv_omni, we check recv first, and _then_ send, otherwise,
+ a request/response test will be all messed-up :) and that then
+ is why there are two routines to rule them all rather than just
+ one :) */
+ if (direction & NETPERF_RECV) {
+ ret = recv_data(data_socket,
+ recv_ring,
+ bytes_to_recv,
+ bytes_per_recv);
+ if (ret > 0) {
+ /* if this is a recv-only test controlled by byte count we
+ decrement the units_remaining by the bytes received */
+ if (!(direction & NETPERF_XMIT) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_received += ret;
+ }
+ else if (ret == 0) {
+ /* is this the end of a test, just a zero-byte recv, or
+ something else? that is an exceedingly good question and
+ one for which I don't presently have a good answer, but
+ that won't stop me from guessing :) raj 2008-01-09 */
+ if (!((connection_test) || (null_message_ok))) {
+ /* if it is neither a connection_test nor null_message_ok it
+ must be the end of the test */
+ times_up = 1;
+ break;
+ }
+ }
+ else if (ret == -1) {
+ /* test timed-out */
+ times_up = 1;
+ break;
+ }
+ else {
+ /* presently at least, -2 and -3 are equally bad on recv */
+ /* we need a response message here for the control connection
+ before we exit! */
+ exit(1);
+ }
+ recv_ring = recv_ring->next;
+ }
+
+ /* if we should try to send something, then by all means, let us
+ try to send something. */
+ if (direction & NETPERF_XMIT) {
+ ret = send_data(data_socket,
+ send_ring,
+ bytes_to_send,
+ bytes_per_send);
+
+ /* the order of these if's will seem a triffle strange, but they
+ are my best guess as to order of probabilty and/or importance
+ to the overhead raj 2008-01-09*/
+ if (ret == bytes_to_send) {
+ /* if this is a send-only test controlled by byte count we
+ decrement units_remaining by the bytes sent */
+ if (!(direction & NETPERF_RECV) && (units_remaining > 0)) {
+ units_remaining -= ret;
+ }
+ bytes_sent += ret;
+ send_ring = send_ring->next;
+ }
+ else if (ret == -2) {
+ /* what to do here -2 means a non-fatal error - probably
+ ENOBUFS and so our send didn't happen. in the old code for
+ UDP_STREAM we would just continue in the while loop. it
+ isn't clear that is what to do here, so we will simply
+ increment the failed_sends stat and fall-through. If this
+ is a UDP_STREAM style of test, the net effect should be the
+ same. if this is a UDP_RR with a really-big burst count, I
+ don't think we were checking for ENOBUFS there anyway and
+ so would have failed. Here we can just let things
+ slide. */
+ failed_sends++;
+ }
+ else if (ret == 0) {
+ /* was this a zero-byte send? if it was, then ostensibly we
+ would hit the ret == bytes_to_send case which means we'd
+ never get here as we are using blocking semantics */
+ }
+ else if (ret == -1) {
+ times_up = 1;
+ break;
+ }
+ else {
+ /* we need a response message back to netperf here before we
+ exit */
+ /* NEED RESPONSE; */
+ exit(1);
+ }
+
+ }
+
+ if (connection_test) {
+ ret = close_data_socket(data_socket);
+ if (ret < 0) {
+ perror("netperf: send_omni: disconnect_data_socket failed");
+ exit(1);
+ }
+ else if (ret == 0) {
+ times_up = 1;
+ break;
+ }
+ /* we will need a new connection to be established */
+ need_connection = 1;
+ connected = 0;
+ }
+
+
+ /* was this a "transaction" test? don't for get that a TCP_CC
+ style test will have no xmit or recv :) so, we check for either
+ both XMIT and RECV set, or neither XMIT nor RECV set */
+ if (((direction & NETPERF_XMIT) && (direction & NETPERF_RECV)) ||
+ !((direction & NETPERF_XMIT) || (direction & NETPERF_RECV))) {
+ trans_completed++;
+ if (units_remaining) {
+ units_remaining--;
+ }
+ }
+ }
+
+ /* The current iteration loop now exits due to timeout or unit count
+ being reached */
+
+ cpu_stop(omni_request->measure_cpu,&elapsed_time);
+
+ if (timed_out) {
+ /* we ended the test by time, which was at least PAD_TIME seconds
+ longer than we wanted to run. so, we want to subtract PAD_TIME
+ from the elapsed_time. */
+ elapsed_time -= PAD_TIME;
+ }
+
+ /* send the results to the sender */
+
+ omni_results->bytes_received = bytes_received;
+ omni_results->bytes_sent = bytes_sent;
+ omni_results->trans_received = trans_completed;
+ omni_results->elapsed_time = elapsed_time;
+ if (omni_request->measure_cpu) {
+ omni_results->cpu_util = calc_cpu_util(elapsed_time);
+ }
+
+ if (debug) {
+ fprintf(where,
+ "recv_omni: test complete, sending results.\n");
+ fflush(where);
+ }
+
+ send_response();
+
+ /* when we implement this, it will look a little strange, but we do
+ it to avoid certain overheads when running aggregates and using
+ confidence intervals. we will post a recv_request() call to get
+ the next message or EOF on the control connection. either the
+ netperf will close the control connection, which will tell us we
+ are done, or the netperf will send us another "DO_OMNI" message,
+ which by definition should be identical to the first DO_OMNI
+ message we received.
+
+ in this way we can avoid overheads like allocating the buffer
+ rings and the listen socket and the like */
+
+}
+
+void
+scan_omni_args(int argc, char *argv[])
+
+{
+
+#define OMNI_ARGS "b:cCDnNhH:L:m:M:p:P:r:s:S:t:T:Vw:W:46"
+
+ extern char *optarg; /* pointer to option string */
+
+ int c;
+
+ char
+ arg1[BUFSIZ], /* argument holders */
+ arg2[BUFSIZ];
+
+ if (debug) {
+ int i;
+ printf("%s called with the following argument vector\n",
+ __func__);
+ for (i = 0; i< argc; i++) {
+ printf("%s ",argv[i]);
+ }
+ printf("\n");
+ }
+
+ strncpy(local_data_port,"0",sizeof(local_data_port));
+ strncpy(remote_data_port,"0",sizeof(remote_data_port));
+
+ /* Go through all the command line arguments and break them */
+ /* out. For those options that take two parms, specifying only */
+ /* the first will set both to that value. Specifying only the */
+ /* second will leave the first untouched. To change only the */
+ /* first, use the form "first," (see the routine break_args.. */
+
+ while ((c= getopt(argc, argv, OMNI_ARGS)) != EOF) {
+ switch (c) {
+ case '?':
+ case '4':
+ remote_data_family = AF_INET;
+ local_data_family = AF_INET;
+ break;
+ case '6':
+#if defined(AF_INET6)
+ remote_data_family = AF_INET6;
+ local_data_family = AF_INET6;
+#else
+ fprintf(stderr,
+ "This netperf was not compiled on an IPv6 capable host!\n");
+ fflush(stderr);
+ exit(-1);
+#endif
+ break;
+ case 'h':
+ print_sockets_usage();
+ exit(1);
+ case 'b':
+#ifdef WANT_FIRST_BURST
+ first_burst_size = atoi(optarg);
+#else /* WANT_FIRST_BURST */
+ printf("Initial request burst functionality not compiled-in!\n");
+#endif /* WANT_FIRST_BURST */
+ break;
+ case 'c':
+ /* this is a connection test */
+ connection_test = 1;
+ break;
+ case 'C':
+#ifdef TCP_CORK
+ /* set TCP_CORK */
+ loc_tcpcork = 1;
+ rem_tcpcork = 1; /* however, at first, we ony have cork affect loc */
+#else
+ printf("WARNING: TCP_CORK not available on this platform!\n");
+#endif /* TCP_CORK */
+ break;
+ case 'D':
+ /* set the TCP nodelay flag */
+ loc_nodelay = 1;
+ rem_nodelay = 1;
+ break;
+ case 'H':
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ /* make sure we leave room for the NULL termination boys and
+ girls. raj 2005-02-82 */
+ remote_data_address = malloc(strlen(arg1)+1);
+ strncpy(remote_data_address,arg1,strlen(arg1));
+ }
+ if (arg2[0])
+ remote_data_family = parse_address_family(arg2);
+ break;
+ case 'L':
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ /* make sure we leave room for the NULL termination boys and
+ girls. raj 2005-02-82 */
+ local_data_address = malloc(strlen(arg1)+1);
+ strncpy(local_data_address,arg1,strlen(arg1));
+ }
+ if (arg2[0])
+ local_data_family = parse_address_family(arg2);
+ break;
+ case 'm':
+ /* set the send size. if we set the local send size it will add
+ XMIT to direction. if we set the remote send size it will
+ add RECV to the direction */
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ send_size = convert(arg1);
+ direction != NETPERF_XMIT;
+ }
+ if (arg2[0]) {
+ remote_send_size = convert(arg2);
+ direction != NETPERF_RECV;
+ }
+ break;
+ case 'M':
+ /* set the recv sizes. if we set the local recv size it will
+ add RECV to direction. if we set the remote recv size it
+ will add XMIT to direction */
+ break_args_explicit(optarg,arg1,arg2);
+ if (arg1[0]) {
+ remote_recv_size = convert(arg1);
+ direction != NETPERF_XMIT;
+ }
+ if (arg2[0]) {
+ recv_size = convert(arg2);
+ direction != NETPERF_RECV;
+ }
+ break;
+ case 'n':
+ /* set the local socket type */
+ local_connected = 1;
+ break;
+ case 'N':
+ /* set the remote socket type */
+ remote_connected = 1;
+ break;
+ case 'p':
+ /* set the min and max port numbers for the TCP_CRR and TCP_TRR */
+ /* tests. */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ client_port_min = atoi(arg1);
+ if (arg2[0])
+ client_port_max = atoi(arg2);
+ break;
+ case 'P':
+ /* set the local and remote data port numbers for the tests to
+ allow them to run through those blankety blank end-to-end
+ breaking firewalls. raj 2004-06-15 */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ strncpy(local_data_port,arg1,sizeof(local_data_port));
+ if (arg2[0])
+ strncpy(remote_data_port,arg2,sizeof(remote_data_port));
+ break;
+ case 'r':
+ /* set the request/response sizes. setting request/response
+ sizes implicitly sets direction to XMIT and RECV */
+ direction != NETPERF_XMIT;
+ direction != NETPERF_RECV;
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ req_size = convert(arg1);
+ if (arg2[0])
+ rsp_size = convert(arg2);
+ break;
+ case 's':
+ /* set local socket sizes */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ lss_size_req = convert(arg1);
+ if (arg2[0])
+ lsr_size_req = convert(arg2);
+ break;
+ case 'S':
+ /* set remote socket sizes */
+ break_args(optarg,arg1,arg2);
+ if (arg1[0])
+ rss_size_req = convert(arg1);
+ if (arg2[0])
+ rsr_size_req = convert(arg2);
+ break;
+ case 't':
+ /* set the socket type */
+ socket_type = parse_socket_type(optarg);
+ break;
+ case 'T':
+ /* set the protocol - aka "Transport" */
+ protocol = parse_protocol(optarg);
+ break;
+ case 'W':
+ /* set the "width" of the user space data */
+ /* buffer. This will be the number of */
+ /* send_size buffers malloc'd in the */
+ /* *_STREAM test. It may be enhanced to set */
+ /* both send and receive "widths" but for now */
+ /* it is just the sending *_STREAM. */
+ send_width = convert(optarg);
+ break;
+ case 'V' :
+ /* we want to do copy avoidance and will set */
+ /* it for everything, everywhere, if we really */
+ /* can. of course, we don't know anything */
+ /* about the remote... */
+#ifdef SO_SND_COPYAVOID
+ loc_sndavoid = 1;
+#else
+ loc_sndavoid = 0;
+ printf("Local send copy avoidance not available.\n");
+#endif
+#ifdef SO_RCV_COPYAVOID
+ loc_rcvavoid = 1;
+#else
+ loc_rcvavoid = 0;
+ printf("Local recv copy avoidance not available.\n");
+#endif
+ rem_sndavoid = 1;
+ rem_rcvavoid = 1;
+ break;
+ };
+ }
+
+ /* some other sanity checks we need to make would include stuff when
+ the user has set -m and -M such that both XMIT and RECV are set
+ and has not set -r. initially we will not allow that. at some
+ point we might allow that if the user has also set -r, but until
+ then the code will simply ignore the values from -m and -M when
+ -r is set. */
+
+#if defined(WANT_FIRST_BURST)
+#if defined(WANT_HISTOGRAM)
+ /* if WANT_FIRST_BURST and WANT_HISTOGRAM are defined and the user
+ indeed wants a non-zero first burst size, and we would emit a
+ histogram, then we should emit a warning that the two are not
+ compatible. raj 2006-01-31 */
+ if ((first_burst_size > 0) && (verbosity >= 2)) {
+ fprintf(stderr,
+ "WARNING! Histograms and first bursts are incompatible!\n");
+ fflush(stderr);
+ }
+#endif
+#endif
+
+ /* we do not want to make remote_data_address non-NULL because if
+ the user has not specified a remote adata address, we want to
+ take it from the hostname in the -H global option. raj
+ 2005-02-08 */
+
+ /* so, if there is to be no control connection, we want to have some
+ different settings for a few things */
+
+ if (no_control) {
+
+ if (strcmp(remote_data_port,"0") == 0) {
+ /* we need to select either the discard port, echo port or
+ chargen port dedepending on the test name. raj 2007-02-08 */
+ if (strstr(test_name,"STREAM") ||
+ strstr(test_name,"SENDFILE")) {
+ strncpy(remote_data_port,"discard",sizeof(remote_data_port));
+ }
+ else if (strstr(test_name,"RR")) {
+ strncpy(remote_data_port,"echo",sizeof(remote_data_port));
+ }
+ else if (strstr(test_name,"MAERTS")) {
+ strncpy(remote_data_port,"chargen",sizeof(remote_data_port));
+ }
+ else {
+ printf("No default port known for the %s test, please set one yourself\n",test_name);
+ exit(-1);
+ }
+ }
+ remote_data_port[sizeof(remote_data_port) - 1] = '\0';
+
+ /* I go back and forth on whether these should become -1 or if
+ they should become 0 for a no_control test. what do you think?
+ raj 2006-02-08 */
+
+ rem_rcvavoid = -1;
+ rem_sndavoid = -1;
+ rss_size_req = -1;
+ rsr_size_req = -1;
+ rem_nodelay = -1;
+
+ if (strstr(test_name,"STREAM") ||
+ strstr(test_name,"SENDFILE")) {
+ recv_size = -1;
+ }
+ else if (strstr(test_name,"RR")) {
+ /* I am however _certain_ that for a no control RR test the
+ response size must equal the request size since 99 times out
+ of ten we will be speaking to the echo service somewhere */
+ rsp_size = req_size;
+ }
+ else if (strstr(test_name,"MAERTS")) {
+ send_size = -1;
+ }
+ else {
+ printf("No default port known for the %s test, please set one yourself\n",test_name);
+ exit(-1);
+ }
+ }
+}
+
+#endif /* WANT_OMNI */
More information about the netperf-dev
mailing list