diff options
author | Kinsey Moore <kinsey.moore@oarcorp.com> | 2022-07-12 09:00:59 -0500 |
---|---|---|
committer | Kinsey Moore <kinsey.moore@oarcorp.com> | 2022-09-09 13:10:48 -0500 |
commit | 07bd3cf92af62f66b0da93945a80ca37aa8e5c6a (patch) | |
tree | 2ec84b996740f105434c25a677ca79d10ccb504c | |
parent | testsuite: Add ntp01.exe test (diff) | |
download | rtems-net-services-07bd3cf92af62f66b0da93945a80ca37aa8e5c6a.tar.bz2 |
Add TTCP source and test
-rw-r--r-- | netservices.py | 30 | ||||
-rw-r--r-- | testsuites/ttcpshell01/test_main.c | 138 | ||||
-rw-r--r-- | ttcp/README | 21 | ||||
-rw-r--r-- | ttcp/include/ttcp.h | 1 | ||||
-rw-r--r-- | ttcp/ttcp.c | 1053 |
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); +} |