summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKinsey Moore <kinsey.moore@oarcorp.com>2022-07-12 09:00:59 -0500
committerKinsey Moore <kinsey.moore@oarcorp.com>2022-09-09 13:10:48 -0500
commit07bd3cf92af62f66b0da93945a80ca37aa8e5c6a (patch)
tree2ec84b996740f105434c25a677ca79d10ccb504c
parenttestsuite: Add ntp01.exe test (diff)
downloadrtems-net-services-07bd3cf92af62f66b0da93945a80ca37aa8e5c6a.tar.bz2
Add TTCP source and test
-rw-r--r--netservices.py30
-rw-r--r--testsuites/ttcpshell01/test_main.c138
-rw-r--r--ttcp/README21
-rw-r--r--ttcp/include/ttcp.h1
-rw-r--r--ttcp/ttcp.c1053
5 files changed, 1243 insertions, 0 deletions
diff --git a/netservices.py b/netservices.py
index f086415..99a0efa 100644
--- a/netservices.py
+++ b/netservices.py
@@ -65,6 +65,25 @@ def build(bld):
use=['ntp_obj'])
bld.install_files("${PREFIX}/" + arch_lib_path, ["libntp.a"])
+ ttcp_incl = ['ttcp/include']
+ ttcp_obj_incl = []
+ ttcp_obj_incl.extend(ttcp_incl)
+
+ ttcp_source_files = ['ttcp/ttcp.c']
+
+ bld(features='c',
+ target='ttcp_obj',
+ cflags='-g -Wall -O0',
+ includes=' '.join(ttcp_obj_incl),
+ source=ttcp_source_files,
+ )
+
+ bld(features='c cstlib',
+ target='ttcp',
+ cflags='-g -Wall -O0',
+ use=['ttcp_obj'])
+ bld.install_files("${PREFIX}/" + arch_lib_path, ["libttcp.a"])
+
def install_headers(root_path):
for root, dirs, files in os.walk(root_path):
for name in files:
@@ -98,6 +117,17 @@ def build(bld):
cflags='-g -Wall -O0',
includes=' '.join(ntp_test_incl))
+ ttcp_test_incl = []
+ ttcp_test_incl.extend(ttcp_incl)
+ ttcp_test_incl.append('testsuites/')
+
+ bld.program(features='c',
+ target='ttcpshell01.exe',
+ source='testsuites/ttcpshell01/test_main.c',
+ use='ttcp lwip rtemstest',
+ cflags='-g -Wall -O0',
+ includes=' '.join(ttcp_test_incl))
+
def add_flags(flags, new_flags):
for flag in new_flags:
diff --git a/testsuites/ttcpshell01/test_main.c b/testsuites/ttcpshell01/test_main.c
new file mode 100644
index 0000000..164bee4
--- /dev/null
+++ b/testsuites/ttcpshell01/test_main.c
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @brief RTEMS shell is started with DHCP client. It is possible to run TTCP.
+ */
+
+/*
+ * COPYRIGHT (c) 2021. On-Line Applications Research Corporation (OAR).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <rtems.h>
+#include <rtems/shell.h>
+#include <rtems/console.h>
+#include <ttcp.h>
+#include <lwip/dhcp.h>
+#include <arch/sys_arch.h>
+
+#include <tmacros.h>
+
+#include <netstart.h>
+
+
+const char rtems_test_name[] = "lwIP TTCP 1";
+
+struct netif net_interface;
+
+rtems_shell_cmd_t shell_TTCP_Command = {
+ "ttcp", /* name */
+ "ttcp -h # to get help", /* usage */
+ "net", /* topic */
+ rtems_shell_main_ttcp, /* command */
+ NULL, /* alias */
+ NULL /* next */
+};
+
+static rtems_task Init( rtems_task_argument argument )
+{
+ rtems_status_code sc;
+ int ret;
+
+ TEST_BEGIN();
+
+ ip_addr_t ipaddr, netmask, gw;
+
+ IP_ADDR4( &ipaddr, 10, 0, 2, 14 );
+ IP_ADDR4( &netmask, 255, 255, 255, 0 );
+ IP_ADDR4( &gw, 10, 0, 2, 3 );
+ unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 };
+
+ ret = start_networking(
+ &net_interface,
+ &ipaddr,
+ &netmask,
+ &gw,
+ mac_ethernet_address
+ );
+
+ if ( ret != 0 ) {
+ return;
+ }
+
+ rtems_shell_init_environment();
+
+ dhcp_start( &net_interface );
+
+ sc = rtems_shell_init(
+ "SHLL", /* task name */
+ RTEMS_MINIMUM_STACK_SIZE * 4, /* task stack size */
+ 100, /* task priority */
+ "/dev/console", /* device name */
+ false, /* run forever */
+ true, /* wait for shell to terminate */
+ NULL /* login check function,
+ use NULL to disable a login check */
+ );
+ rtems_test_assert( sc == RTEMS_SUCCESSFUL );
+ sys_arch_delay( 300000 );
+
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+#define CONFIGURE_INIT
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 10000
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+
+#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 32
+
+#define CONFIGURE_SHELL_COMMANDS_INIT
+#define CONFIGURE_SHELL_COMMANDS_ALL
+#define CONFIGURE_SHELL_USER_COMMANDS &shell_TTCP_Command
+
+#define CONFIGURE_MAXIMUM_TASKS 12
+
+#define CONFIGURE_MAXIMUM_POSIX_KEYS 1
+#define CONFIGURE_MAXIMUM_SEMAPHORES 20
+#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 10
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_UNLIMITED_OBJECTS
+#define CONFIGURE_UNIFIED_WORK_AREAS
+
+#include <rtems/shellconfig.h>
+
+#include <rtems/confdefs.h>
diff --git a/ttcp/README b/ttcp/README
new file mode 100644
index 0000000..35db389
--- /dev/null
+++ b/ttcp/README
@@ -0,0 +1,21 @@
+TTCP is a benchmarking tool for determining TCP and UDP performance
+between 2 systems.
+
+The program was created at the US Army Ballistics Research Lab (BRL)
+and is in the public domain. Feel free to distribute this program
+but please do leave the credit notices in the source and man page intact.
+
+Contents of this directory:
+
+ttcp.c Source that runs on IRIX 3.3.x and 4.0.x systems,
+ BSD-based systems, and RTEMS. This version also
+ uses getopt(3) and has 2 new options: -f and -T.
+
+
+How to get TCP performance numbers:
+
+ receiver sender
+
+host1% ttcp -r -s host2% ttcp -t -s host1
+
+-n and -l options change the number and size of the buffers.
diff --git a/ttcp/include/ttcp.h b/ttcp/include/ttcp.h
new file mode 100644
index 0000000..979bb94
--- /dev/null
+++ b/ttcp/include/ttcp.h
@@ -0,0 +1 @@
+int rtems_shell_main_ttcp(int argc, char **argv);
diff --git a/ttcp/ttcp.c b/ttcp/ttcp.c
new file mode 100644
index 0000000..73ac2a6
--- /dev/null
+++ b/ttcp/ttcp.c
@@ -0,0 +1,1053 @@
+/*
+ * T T C P . C
+ *
+ * Test TCP connection. Makes a connection on port 5001
+ * and transfers fabricated buffers or data copied from stdin.
+ *
+ * Usable on 4.2, 4.3, and 4.1a systems by defining one of
+ * BSD42 BSD43 (BSD41a)
+ * Machines using System V with BSD sockets should define SYSV.
+ *
+ * Modified for operation under 4.2BSD, 18 Dec 84
+ * T.C. Slattery, USNA
+ * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
+ * Modified in 1989 at Silicon Graphics, Inc.
+ * catch SIGPIPE to be able to print stats when receiver has died
+ * for tcp, don't look for sentinel during reads to allow small transfers
+ * increased default buffer size to 8K, nbuf to 2K to transfer 16MB
+ * moved default port to 5001, beyond IPPORT_USERRESERVED
+ * make sinkmode default because it is more popular,
+ * -s now means don't sink/source
+ * count number of read/write system calls to see effects of
+ * blocking from full socket buffers
+ * for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
+ * buffer alignment options, -A and -O
+ * print stats in a format that's a bit easier to use with grep & awk
+ * for SYSV, mimic BSD routines to use most of the existing timing code
+ * Modified by Steve Miller of the University of Maryland, College Park
+ * -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
+ * Modified Sept. 1989 at Silicon Graphics, Inc.
+ * restored -s sense at request of tcs@brl
+ * Modified Oct. 1991 at Silicon Graphics, Inc.
+ * use getopt(3) for option processing, add -f and -T options.
+ * SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
+ *
+ * Distribution Status -
+ * Public Domain. Distribution Unlimited.
+ */
+
+#ifndef lint
+/* static char RCSid[] = "ttcp.c $Revision$"; */
+#endif
+
+#define BSD43
+/* #define BSD42 */
+/* #define BSD41a */
+/* #define SYSV */ /* required on SGI IRIX releases before 3.3 */
+
+//The millisecond delay should work on a modern OS but can be disabled if not
+#define ENABLE_NANOSLEEP_DELAY
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifndef __rtems__
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+#include <string.h>
+#include <sys/time.h> /* struct timeval */
+
+#if defined(__rtems__)
+#define __need_getopt_newlib
+#include <getopt.h>
+#include <rtems/shell.h>
+#include <lwip/inet.h>
+#include <lwip/netdb.h>
+#undef TCP_NODELAY
+#define select lwip_select
+#endif
+
+#if defined(ENABLE_NANOSLEEP_DELAY)
+#include <time.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#if defined(SYSV)
+#include <sys/times.h>
+#include <sys/param.h>
+struct rusage {
+ struct timeval ru_utime, ru_stime;
+};
+#define RUSAGE_SELF 0
+#else
+#include <sys/resource.h>
+#endif
+
+
+static struct sockaddr_in sinme;
+static struct sockaddr_in sinhim;
+static struct sockaddr_in frominet;
+
+/* these make it easier to avoid warnings */
+static struct sockaddr *sinhim_p = (struct sockaddr *) &sinhim;
+static struct sockaddr *sinme_p = (struct sockaddr *) &sinme;
+static struct sockaddr *frominet_p = (struct sockaddr *) &frominet;
+
+static int domain;
+static socklen_t fromlen;
+static int fd; /* fd of network socket */
+
+static int buflen = 8 * 1024; /* length of buffer */
+static char *buf; /* ptr to dynamic buffer */
+static char *alloc_buf; /* ptr to beginning of memory allocated for buf */
+static int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */
+
+static int bufoffset = 0; /* align buffer to this */
+static int bufalign = 16*1024; /* modulo this */
+
+static int udp = 0; /* 0 = tcp, !0 = udp */
+static int options = 0; /* socket options */
+static int one = 1; /* for 4.3 BSD style setsockopt() */
+static short port = 5001; /* TCP port number */
+static char *host; /* ptr to name of host */
+static int trans; /* 0=receive, !0=transmit mode */
+static int sinkmode = 0; /* 0=normal I/O, !0=sink/source mode */
+static int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc
+ * resource usage. */
+static int nodelay = 0; /* set TCP_NODELAY socket option */
+static int b_flag = 0; /* use mread() */
+static int sockbufsize = 0; /* socket buffer size to use */
+static char fmt = 'K'; /* output format: k = kilobits, K = kilobytes,
+ * m = megabits, M = megabytes,
+ * g = gigabits, G = gigabytes */
+static int touchdata = 0; /* access data after reading */
+static long milliseconds = 0; /* delay in milliseconds */
+
+static struct hostent *addr;
+static void initialize_vars(void)
+{
+ memset(&sinme, 0, sizeof(sinme));
+ memset(&sinhim, 0, sizeof(sinhim));
+ memset(&frominet, 0, sizeof(frominet));
+
+ /* these make it easier to avoid warnings */
+ sinhim_p = (struct sockaddr *) &sinhim;
+ sinme_p = (struct sockaddr *) &sinme;
+ frominet_p = (struct sockaddr *) &frominet;
+
+ domain = 0;
+ fromlen = 0;
+ fd = 0; /* fd of network socket */
+
+ buflen = 8 * 1024; /* length of buffer */
+ buf = NULL; /* ptr to dynamic buffer */
+ alloc_buf = NULL; /* ptr to beginning of memory allocated for buf */
+ nbuf = 2 * 1024; /* number of buffers to send in sinkmode */
+
+ bufoffset = 0; /* align buffer to this */
+ bufalign = 16*1024; /* modulo this */
+
+ udp = 0; /* 0 = tcp, !0 = udp */
+ options = 0; /* socket options */
+ one = 1; /* for 4.3 BSD style setsockopt() */
+ port = 5001; /* TCP port number */
+ host = NULL; /* ptr to name of host */
+ trans = 0; /* 0=receive, !0=transmit mode */
+ sinkmode = 0; /* 0=normal I/O, !0=sink/source mode */
+ verbose = 0; /* 0=print basic info, 1=print cpu rate, proc
+ * resource usage. */
+ nodelay = 0; /* set TCP_NODELAY socket option */
+ b_flag = 0; /* use mread() */
+ sockbufsize = 0; /* socket buffer size to use */
+ fmt = 'K'; /* output format: k = kilobits, K = kilobytes,
+ * m = megabits, M = megabytes,
+ * g = gigabits, G = gigabytes */
+ touchdata = 0; /* access data after reading */
+ milliseconds = 0; /* delay in milliseconds */
+
+ addr = NULL;
+}
+
+static const char Usage[] = "\
+Usage: ttcp -t [-options] host [ < in ]\n\
+ ttcp -r [-options > out]\n\
+Common options:\n\
+ -l ## length of bufs read from or written to network (default 8192)\n\
+ -u use UDP instead of TCP\n\
+ -p ## port number to send to or listen at (default 5001)\n\
+ -s -t: source a pattern to network\n\
+ -r: sink (discard) all data from network\n\
+ -A align the start of buffers to this modulus (default 16384)\n\
+ -O start buffers at this offset from the modulus (default 0)\n\
+ -v verbose: print more statistics\n\
+ -d set SO_DEBUG socket option\n\
+ -b ## set socket buffer size (if supported)\n\
+ -f X format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
+Options specific to -t:\n\
+ -n## number of source bufs written to network (default 2048)\n\
+ -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
+Options specific to -r:\n\
+ -B for -s, only output full blocks as specified by -l (for TAR)\n\
+ -T \"touch\": access each byte as it's read\n\
+ -m ## delay for specified milliseconds between each write\n\
+";
+
+static char stats[128];
+static double nbytes; /* bytes on net */
+static unsigned long numCalls; /* # of I/O system calls */
+static double cput, realt; /* user, real time (seconds) */
+
+static void err();
+static void mes();
+static void pattern();
+static void prep_timer();
+static double read_timer();
+static int Nread();
+static int Nwrite();
+static void delay();
+static int mread();
+static char *outfmt();
+
+static void millisleep(long msec)
+{
+#if defined(ENABLE_NANOSLEEP_DELAY)
+ struct timespec req;
+
+ req.tv_sec = msec / 1000;
+ req.tv_nsec = (msec % 1000) * 1000000;
+
+ nanosleep( &req, NULL );
+#endif
+}
+
+#if (defined (__rtems__))
+int rtems_shell_main_ttcp(argc,argv)
+#else
+int main(argc,argv)
+#endif
+int argc;
+char **argv;
+{
+ initialize_vars();
+ unsigned long addr_tmp;
+ int c;
+
+ if (argc < 2) goto usage;
+
+#ifdef __rtems__
+ struct getopt_data getopt_reent;
+#define optarg getopt_reent.optarg
+#define optind getopt_reent.optind
+#define opterr getopt.reent.opterr
+#define optopt getopt.reent.optopt
+ memset(&getopt_reent, 0, sizeof(getopt_data));
+ while ((c = getopt_r(argc, argv,
+ "drstuvBDTb:f:l:m:n:p:A:O:",
+ &getopt_reent)) != -1) {
+#else
+ while ((c = getopt(argc, argv, "drstuvBDTb:f:l:m:n:p:A:O:")) != -1) {
+#endif
+ switch (c) {
+
+ case 'B':
+ b_flag = 1;
+ break;
+ case 't':
+ trans = 1;
+ break;
+ case 'r':
+ trans = 0;
+ break;
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'D':
+#ifdef TCP_NODELAY
+ nodelay = 1;
+#else
+ fprintf(stderr,
+ "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
+#endif
+ break;
+ case 'm':
+ milliseconds = atoi(optarg);
+ #if !defined(ENABLE_NANOSLEEP_DELAY)
+ fprintf(stderr, "millisecond delay disabled\n");
+ #endif
+ break;
+ case 'n':
+ nbuf = atoi(optarg);
+ break;
+ case 'l':
+ buflen = atoi(optarg);
+ break;
+ case 's':
+ sinkmode = !sinkmode;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'u':
+ udp = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'A':
+ bufalign = atoi(optarg);
+ break;
+ case 'O':
+ bufoffset = atoi(optarg);
+ break;
+ case 'b':
+#if defined(SO_SNDBUF) || defined(SO_RCVBUF)
+ sockbufsize = atoi(optarg);
+#else
+ fprintf(stderr,
+"ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
+#endif
+ break;
+ case 'f':
+ fmt = *optarg;
+ break;
+ case 'T':
+ touchdata = 1;
+ break;
+
+ default:
+ goto usage;
+ }
+ }
+ if(trans) {
+ /* xmitr */
+ if (optind == argc)
+ goto usage;
+ bzero((char *)&sinhim, sizeof(sinhim));
+ host = argv[optind];
+ sinme.sin_family = AF_INET;
+ if (atoi(host) > 0 ) {
+ /* Numeric */
+ sinhim.sin_family = AF_INET;
+#if defined(cray)
+ addr_tmp = inet_addr(host);
+ sinhim.sin_addr = addr_tmp;
+#else
+ sinhim.sin_addr.s_addr = inet_addr(host);
+#endif
+ } else {
+ if ((addr=gethostbyname(host)) == NULL) {
+ err("bad hostname");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ sinhim.sin_family = addr->h_addrtype;
+ bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
+#if defined(cray)
+ sinhim.sin_addr = addr_tmp;
+#else
+ sinhim.sin_addr.s_addr = addr_tmp;
+#endif /* cray */
+ }
+ sinhim.sin_port = htons(port);
+ sinme.sin_port = 0; /* free choice */
+ } else {
+ /* rcvr */
+ sinme.sin_family = AF_INET;
+ sinme.sin_port = htons(port);
+ }
+
+
+ if (udp && buflen < 5) {
+ buflen = 5; /* send more than the sentinel size */
+ }
+
+ if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL) {
+ err("malloc");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ alloc_buf = buf;
+ if (bufalign != 0)
+ buf +=(bufalign - ((intptr_t)buf % bufalign) + bufoffset) % bufalign;
+
+ if (trans) {
+ fprintf(stdout,
+ "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
+ buflen, nbuf, bufalign, bufoffset, port);
+ if (sockbufsize)
+ fprintf(stdout, ", sockbufsize=%d", sockbufsize);
+ fprintf(stdout, " %s -> %s\n", udp?"udp":"tcp", host);
+ } else {
+ fprintf(stdout,
+ "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
+ buflen, nbuf, bufalign, bufoffset, port);
+ if (sockbufsize)
+ fprintf(stdout, ", sockbufsize=%d", sockbufsize);
+ fprintf(stdout, " %s\n", udp?"udp":"tcp");
+ }
+
+ if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0) {
+ err("socket");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ mes("socket");
+
+ if (bind(fd, sinme_p, sizeof(sinme)) < 0) {
+ err("bind");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+
+#if defined(SO_SNDBUF) || defined(SO_RCVBUF)
+ if (sockbufsize) {
+ if (trans) {
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
+ sizeof sockbufsize) < 0) {
+ err("setsockopt: sndbuf");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ mes("sndbuf");
+ } else {
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
+ sizeof sockbufsize) < 0) {
+ err("setsockopt: rcvbuf");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ mes("rcvbuf");
+ }
+ }
+#endif
+
+ if (!udp) {
+#if 0
+ signal(SIGPIPE, sigpipe);
+#endif
+ if (trans) {
+ /* We are the client if transmitting */
+ if (options) {
+#if defined(BSD42)
+ if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0) {
+#else /* BSD43 */
+ if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0) {
+#endif
+ err("setsockopt");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ }
+#ifdef TCP_NODELAY
+ if (nodelay) {
+ struct protoent *p;
+ p = getprotobyname("tcp");
+ if( p && setsockopt(fd, p->p_proto, TCP_NODELAY,
+ &one, sizeof(one)) < 0) {
+ err("setsockopt: nodelay");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ mes("nodelay");
+ }
+#endif
+ if(connect(fd, sinhim_p, sizeof(sinhim) ) < 0) {
+ err("connect");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ mes("connect");
+ } else {
+ /* otherwise, we are the server and
+ * should listen for the connections
+ */
+#if defined(ultrix) || defined(sgi)
+ listen(fd,1); /* workaround for alleged u4.2 bug */
+#else
+ listen(fd,0); /* allow a queue of 0 */
+#endif
+ if(options) {
+#if defined(BSD42)
+ if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0) {
+#else /* BSD43 */
+ if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0) {
+#endif
+ err("setsockopt");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ }
+ fromlen = sizeof(frominet);
+ domain = AF_INET;
+ int fd_list = fd;
+ if((fd=accept(fd_list, frominet_p, &fromlen) ) < 0) {
+ err("accept");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+
+ if(close(fd_list) < 0) {
+ err("close");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+
+ { struct sockaddr_in peer;
+ socklen_t peerlen = sizeof(peer);
+ if (getpeername(fd, (struct sockaddr *) &peer,
+ &peerlen) < 0) {
+ err("getpeername");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ fprintf(stderr,"ttcp-r: accept from %s\n",
+ inet_ntoa(peer.sin_addr));
+ }
+ }
+ }
+ prep_timer();
+ errno = 0;
+ if (sinkmode) {
+ register int cnt;
+ if (trans) {
+ pattern( buf, buflen );
+ if(udp) (void)Nwrite( fd, buf, 4 ); /* rcvr start */
+ while (nbuf-- && Nwrite(fd,buf,buflen) == buflen) {
+ nbytes += buflen;
+ millisleep( milliseconds );
+ }
+ if(udp) (void)Nwrite( fd, buf, 4 ); /* rcvr end */
+ } else {
+ if (udp) {
+ while ((cnt=Nread(fd,buf,buflen)) > 0) {
+ static int going = 0;
+ if( cnt <= 4 ) {
+ if( going )
+ break; /* "EOF" */
+ going = 1;
+ prep_timer();
+ } else {
+ nbytes += cnt;
+ }
+ }
+ } else {
+ while ((cnt=Nread(fd,buf,buflen)) > 0) {
+ nbytes += cnt;
+ }
+ }
+ }
+ } else {
+ register int cnt;
+ if (trans) {
+ while((cnt=read(0,buf,buflen)) > 0 &&
+ Nwrite(fd,buf,cnt) == cnt)
+ nbytes += cnt;
+ } else {
+ while((cnt=Nread(fd,buf,buflen)) > 0 &&
+ write(1,buf,cnt) == cnt)
+ nbytes += cnt;
+ }
+ }
+ if(errno) {
+ err("IO");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+ (void)read_timer(stats,sizeof(stats));
+ if(udp&&trans) {
+ (void)Nwrite( fd, buf, 4 ); /* rcvr end */
+ (void)Nwrite( fd, buf, 4 ); /* rcvr end */
+ (void)Nwrite( fd, buf, 4 ); /* rcvr end */
+ (void)Nwrite( fd, buf, 4 ); /* rcvr end */
+ }
+
+ if(close(fd) < 0) {
+ err("close");
+#ifdef __rtems__
+ return 1;
+#endif
+ }
+
+ if( cput <= 0.0 ) cput = 0.001;
+ if( realt <= 0.0 ) realt = 0.001;
+ fprintf(stdout,
+ "ttcp%s: %.0f bytes in %.2f real seconds = %s/sec +++\n",
+ trans?"-t":"-r",
+ nbytes, realt, outfmt(nbytes/realt));
+ if (verbose) {
+ fprintf(stdout,
+ "ttcp%s: %.0f bytes in %.2f CPU seconds = %s/cpu sec\n",
+ trans?"-t":"-r",
+ nbytes, cput, outfmt(nbytes/cput));
+ }
+ fprintf(stdout,
+ "ttcp%s: %ld I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
+ trans?"-t":"-r",
+ numCalls,
+ 1024.0 * realt/((double)numCalls),
+ ((double)numCalls)/realt);
+ fprintf(stdout,"ttcp%s: %s\n", trans?"-t":"-r", stats);
+ if (verbose) {
+ fprintf(stdout,
+ "ttcp%s: buffer address %p\n",
+ trans?"-t":"-r",
+ buf);
+ }
+ free(alloc_buf);
+#ifdef __rtems__
+ return 0;
+#else
+ exit(0);
+#endif
+
+usage:
+ fprintf(stderr,Usage);
+ free(alloc_buf);
+#ifdef __rtems__
+ return 1;
+#else
+ exit(1);
+ return 1;
+#endif
+}
+
+void
+err(s)
+char *s;
+{
+ fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
+ perror(s);
+ fprintf(stderr,"errno=%d\n",errno);
+ free(alloc_buf);
+ if (fd != 0)
+ {
+ close(fd);
+ }
+#ifdef __rtems__
+ return;
+#else
+ exit(1);
+#endif
+}
+
+void
+mes(s)
+char *s;
+{
+ fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
+}
+
+void pattern( cp, cnt )
+register char *cp;
+register int cnt;
+{
+ register char c;
+ c = 0;
+ while( cnt-- > 0 ) {
+ while( !isprint((c&0x7F)) ) c++;
+ *cp++ = (c++&0x7F);
+ }
+}
+
+char *
+outfmt(b)
+double b;
+{
+ static char obuf[50];
+ switch (fmt) {
+ case 'G':
+ sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0);
+ break;
+ default:
+ case 'K':
+ sprintf(obuf, "%.2f KB", b / 1024.0);
+ break;
+ case 'M':
+ sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0);
+ break;
+ case 'g':
+ sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0);
+ break;
+ case 'k':
+ sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0);
+ break;
+ case 'm':
+ sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0);
+ break;
+ }
+ return obuf;
+}
+
+static struct timeval time0; /* Time at which timing started */
+static struct rusage ru0; /* Resource utilization at the start */
+
+#ifndef __rtems__
+static void prusage();
+static void psecs();
+#endif
+static void tvadd();
+static void tvsub();
+
+#if defined(SYSV)
+/*ARGSUSED*/
+static
+getrusage(ignored, ru)
+ int ignored;
+ register struct rusage *ru;
+{
+ struct tms buf;
+
+ times(&buf);
+
+ /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
+ ru->ru_stime.tv_sec = buf.tms_stime / HZ;
+ ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
+ ru->ru_utime.tv_sec = buf.tms_utime / HZ;
+ ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
+}
+
+/*ARGSUSED*/
+static
+gettimeofday(tp, zp)
+ struct timeval *tp;
+ struct timezone *zp;
+{
+ tp->tv_sec = time(0);
+ tp->tv_usec = 0;
+}
+#endif /* SYSV */
+
+/*
+ * P R E P _ T I M E R
+ */
+void
+prep_timer()
+{
+ gettimeofday(&time0, (struct timezone *)0);
+ getrusage(RUSAGE_SELF, &ru0);
+}
+
+/*
+ * R E A D _ T I M E R
+ *
+ */
+double
+read_timer(str,len)
+char *str;
+int len;
+{
+ struct timeval timedol;
+ struct rusage ru1;
+ struct timeval td;
+ struct timeval tend, tstart;
+ char line[132];
+
+ getrusage(RUSAGE_SELF, &ru1);
+ gettimeofday(&timedol, (struct timezone *)0);
+#ifndef __rtems__
+ prusage(&ru0, &ru1, &timedol, &time0, line);
+#else
+ line[0] = '\0';
+#endif
+ (void)strncpy( str, line, len );
+
+ /* Get real time */
+ tvsub( &td, &timedol, &time0 );
+ realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
+
+ /* Get CPU time (user+sys) */
+ tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
+ tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
+ tvsub( &td, &tend, &tstart );
+ cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
+ if( cput < 0.00001 ) cput = 0.00001;
+ return( cput );
+}
+
+#ifndef __rtems__
+static void
+prusage(r0, r1, e, b, outp)
+ register struct rusage *r0, *r1;
+ struct timeval *e, *b;
+ char *outp;
+{
+ struct timeval tdiff;
+ register time_t t;
+ register char *cp;
+ register int i;
+ int ms;
+
+ t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
+ (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
+ (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
+ (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
+ ms = (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
+
+#define END(x) {while(*x) x++;}
+#if defined(SYSV)
+ cp = "%Uuser %Ssys %Ereal %P";
+#else
+#if defined(sgi) /* IRIX 3.3 will show 0 for %M,%F,%R,%C */
+ cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw";
+#else
+ cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
+#endif
+#endif
+ for (; *cp; cp++) {
+ if (*cp != '%')
+ *outp++ = *cp;
+ else if (cp[1]) switch(*++cp) {
+
+ case 'U':
+ tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
+ sprintf(outp,"%ld.%01ld", tdiff.tv_sec, tdiff.tv_usec/100000);
+ END(outp);
+ break;
+
+ case 'S':
+ tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
+ sprintf(outp,"%ld.%01ld", tdiff.tv_sec, tdiff.tv_usec/100000);
+ END(outp);
+ break;
+
+ case 'E':
+ psecs(ms / 100, outp);
+ END(outp);
+ break;
+
+ case 'P':
+ sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
+ END(outp);
+ break;
+
+#if !defined(SYSV)
+ case 'W':
+ i = r1->ru_nswap - r0->ru_nswap;
+ sprintf(outp,"%d", i);
+ END(outp);
+ break;
+
+ case 'X':
+ sprintf(outp,"%ld", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
+ END(outp);
+ break;
+
+ case 'D':
+ sprintf(outp,"%ld", t == 0 ? 0 :
+ (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
+ END(outp);
+ break;
+
+ case 'K':
+ sprintf(outp,"%ld", t == 0 ? 0 :
+ ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
+ (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
+ END(outp);
+ break;
+
+ case 'M':
+ sprintf(outp,"%d", r1->ru_maxrss/2);
+ END(outp);
+ break;
+
+ case 'F':
+ sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt);
+ END(outp);
+ break;
+
+ case 'R':
+ sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt);
+ END(outp);
+ break;
+
+ case 'I':
+ sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock);
+ END(outp);
+ break;
+
+ case 'O':
+ sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock);
+ END(outp);
+ break;
+ case 'C':
+ sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw,
+ r1->ru_nivcsw-r0->ru_nivcsw );
+ END(outp);
+ break;
+#endif /* !SYSV */
+ }
+ }
+ *outp = '\0';
+}
+#endif
+
+static void
+tvadd(tsum, t0, t1)
+ struct timeval *tsum, *t0, *t1;
+{
+
+ tsum->tv_sec = t0->tv_sec + t1->tv_sec;
+ tsum->tv_usec = t0->tv_usec + t1->tv_usec;
+ if (tsum->tv_usec > 1000000)
+ tsum->tv_sec++, tsum->tv_usec -= 1000000;
+}
+
+static void
+tvsub(tdiff, t1, t0)
+ struct timeval *tdiff, *t1, *t0;
+{
+
+ tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
+ tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
+ if (tdiff->tv_usec < 0)
+ tdiff->tv_sec--, tdiff->tv_usec += 1000000;
+}
+
+#ifndef __rtems__
+static void
+psecs(l,cp)
+long l;
+register char *cp;
+{
+ register int i;
+
+ i = l / 3600;
+ if (i) {
+ sprintf(cp,"%d:", i);
+ END(cp);
+ i = l % 3600;
+ sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
+ END(cp);
+ } else {
+ i = l;
+ sprintf(cp,"%d", i / 60);
+ END(cp);
+ }
+ i %= 60;
+ *cp++ = ':';
+ sprintf(cp,"%d%d", i / 10, i % 10);
+}
+#endif //!__rtems__
+
+/*
+ * N R E A D
+ */
+int Nread( fd, buf, count )
+int fd;
+void *buf;
+int count;
+{
+ struct sockaddr_in from;
+ socklen_t len = sizeof(from);
+ register int cnt;
+ if( udp ) {
+ cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, &len );
+ numCalls++;
+ } else {
+ if( b_flag )
+ cnt = mread( fd, buf, count ); /* fill buf */
+ else {
+ cnt = read( fd, buf, count );
+ numCalls++;
+ }
+ if (touchdata && cnt > 0) {
+ register int c = cnt, sum;
+ register char *b = buf;
+ while (c--)
+ sum += *b++;
+ }
+ }
+ return(cnt);
+}
+
+/*
+ * N W R I T E
+ */
+int Nwrite( fd, buf, count )
+int fd;
+void *buf;
+int count;
+{
+ register int cnt;
+ if( udp ) {
+again:
+ cnt = sendto( fd, buf, count, 0, sinhim_p, sizeof(sinhim) );
+ numCalls++;
+ if( cnt<0 && errno == ENOBUFS ) {
+ printf("ttcp: out of buffers -- delaying\n"); /*JRS*/
+ delay(18000);
+ errno = 0;
+ goto again;
+ }
+ } else {
+ cnt = write( fd, buf, count );
+ numCalls++;
+ }
+ return(cnt);
+}
+
+void
+delay(int us)
+{
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = us;
+ (void)select( 1, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
+}
+
+/*
+ * M R E A D
+ *
+ * This function performs the function of a read(II) but will
+ * call read(II) multiple times in order to get the requested
+ * number of characters. This can be necessary because
+ * network connections don't deliver data with the same
+ * grouping as it is written with. Written by Robert S. Miles, BRL.
+ */
+int
+mread(fd, bufp, n)
+int fd;
+register char *bufp;
+unsigned n;
+{
+ register unsigned count = 0;
+ register int nread;
+
+ do {
+ nread = read(fd, bufp, n-count);
+ numCalls++;
+ if(nread < 0) {
+ perror("ttcp_mread");
+ return(-1);
+ }
+ if(nread == 0)
+ return((int)count);
+ count += (unsigned)nread;
+ bufp += nread;
+ } while(count < n);
+
+ return((int)count);
+}