summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-30 14:42:29 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-30 14:42:29 +0000
commitc87143a1734b473b7c7e238660e2071d899bbe75 (patch)
treeef003634dbadbd829d8c1d49cb985bf45a641251
base from Eric Norum -- Demos.30May1998.tar.gzDemos-30May1998ERIC-NORUM
-rw-r--r--netdemo/Makefile59
-rw-r--r--netdemo/README27
-rw-r--r--netdemo/init.c185
-rw-r--r--netdemo/test.c313
-rw-r--r--tftpTest/Makefile60
-rw-r--r--tftpTest/init.c114
-rw-r--r--tftpTest/test.c159
-rw-r--r--ttcp/Makefile62
-rw-r--r--ttcp/README19
-rw-r--r--ttcp/include/arpa/inet.h0
-rw-r--r--ttcp/include/netdb.h0
-rw-r--r--ttcp/include/netinet/in.h0
-rw-r--r--ttcp/include/netinet/tcp.h0
-rw-r--r--ttcp/include/sys/socket.h0
-rw-r--r--ttcp/init.c173
-rw-r--r--ttcp/rtems_ttcp.c294
-rw-r--r--ttcp/ttcp_orig/README27
-rw-r--r--ttcp/ttcp_orig/ttcp.1144
-rw-r--r--ttcp/ttcp_orig/ttcp.c841
19 files changed, 2477 insertions, 0 deletions
diff --git a/netdemo/Makefile b/netdemo/Makefile
new file mode 100644
index 0000000..4894a7c
--- /dev/null
+++ b/netdemo/Makefile
@@ -0,0 +1,59 @@
+SAMPLE=netdemo
+PGM=${ARCH}/$(SAMPLE).exe
+
+MANAGERS=io message event semaphore timer rate_monotonic region
+
+# C source names, if any, go here -- minus the .c
+C_PIECES= init test
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+DOCTYPES=
+DOCS=$(DOCTYPES:%=$(SAMPLE).%)
+
+SRCS=$(DOCS) $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+PRINT_SRCS=$(DOCS)
+
+PGM=${ARCH}/$(SAMPLE).exe
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0xC0000 # KA9Q needs more space
+CFLAGS_OPTIMIZE_V +=
+CFLAGS_DEBUG_V += -v -qrtems_debug
+
+LD_PATHS +=
+LD_LIBS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(PGM)
+
+${PGM}: $(OBJS) $(LINK_FILES)
+ $(make-exe)
+
+# Install the program(s), appending _g or _p as appropriate.
+# for include files, just use $(INSTALL)
+install: all
+ $(INSTALL_VARIANT) -m 555 ${PGM} ${PROJECT_RELEASE}/tests
diff --git a/netdemo/README b/netdemo/README
new file mode 100644
index 0000000..5f9a303
--- /dev/null
+++ b/netdemo/README
@@ -0,0 +1,27 @@
+A simple application to test some of the KA9Q networking code.
+
+ **************************
+ * NOTES *
+ **************************
+
+1. Make sure you change the definition of MY_ETHERNET_ADDRESS in init.c
+ before you try to use this program.
+
+2. If you do not use BOOTP (i.e. the `#define USE_BOOTP 1' in init.c is
+ removed), make sure you change the definition of MY_INTERNET_ADDRESS
+ before you try to use the program.
+
+FAILURE TO FOLLOW THE ABOVE INSTRUCTIONS MAY PROVOKE YOUR NETWORK
+ADMINISTRATOR TO THE POINT WHERE VICIOUS ATTACKS WILL BE MADE UPON YOU.
+
+3. Once this program is running on the target machine, you can test
+ the network code by:
+ a) Typing commands at the target console:
+ s - show network statistics
+ t - transmit TCP packets
+ u - transmit UDP packets
+ b) Run `telnet target_machine 24742' on another machines.
+ Everything you type should be echoed back and noted on
+ the target console.
+ You can run more than one telnet session at once.
+ You can use port number 24743 as well.
diff --git a/netdemo/init.c b/netdemo/init.c
new file mode 100644
index 0000000..27b5889
--- /dev/null
+++ b/netdemo/init.c
@@ -0,0 +1,185 @@
+/*
+ * RTEMS configuration/initialization
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+/*#define TRACE_NETWORK_DRIVER 1 */
+#include <bsp.h>
+
+#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_TEST_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_EXECUTIVE_RAM_SIZE (512*1024)
+#define CONFIGURE_MAXIMUM_SEMAPHORES 20
+#define CONFIGURE_MAXIMUM_TASKS 20
+#define CONFIGURE_MAXIMUM_TIMERS 10
+#define CONFIGURE_MAXIMUM_PERIODS 1
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 10486
+
+#define CONFIGURE_INIT_TASK_STACK_SIZE (10*1024)
+#define CONFIGURE_INIT_TASK_PRIORITY 100
+#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
+ RTEMS_NO_TIMESLICE | \
+ RTEMS_NO_ASR | \
+ RTEMS_INTERRUPT_LEVEL(0))
+
+#define CONFIGURE_INIT
+rtems_task Init (rtems_task_argument argument);
+
+#include <confdefs.h>
+
+#include <stdio.h>
+#include <rtems_ka9q.h>
+
+/*
+ * Board ethernet address
+ * REPLACE THIS WITH YOUR OWN VALUE BEFORE TRYING TO USE THIS PROGRAM!
+ */
+#define MY_ETHERNET_ADDRESS "37:1D:3E:21:2B:A5"
+
+/*
+ * Some board support packages let the network driver
+ * get the Ethernet address from the bootstrap PROM.
+ */
+#define MY_ETHERNET_ADDRESS "prom"
+
+/*
+ * Use BOOTP to get information about me?
+ */
+#define USE_BOOTP 1
+
+#if (defined (USE_BOOTP))
+#include <bootp.h>
+#else
+/*
+ * Information about me if BOOTP isn't used
+ * CHOOSE A VALUE APPROPRIATE TO YOUR NETWORK!
+ */
+#define MY_IP_ADDRESS "128.233.14.68"
+#endif
+
+/*
+ * Suspend execution for the specified number of seconds
+ */
+static void
+delay_task (int seconds)
+{
+ rtems_interval ticksPerSecond;
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
+ rtems_task_wake_after (seconds * ticksPerSecond);
+}
+
+/*
+ * RTEMS Startup Task
+ */
+rtems_task
+Init (rtems_task_argument ignored)
+{
+ printf( "\n\n*** HELLO WORLD TEST ***\n" );
+ printf( "Hello World\n" );
+ printf( "*** END OF HELLO WORLD TEST ***\n" );
+
+ /*
+ * Start KA9Q
+ */
+ rtems_ka9q_start (50);
+
+ /*
+ * Hook up drivers
+ */
+#if (defined (USE_BOOTP))
+ if (rtems_ka9q_execute_command ("attach rtems broadcast y"
+ " ether " MY_ETHERNET_ADDRESS))
+#else
+ if (rtems_ka9q_execute_command ("attach rtems broadcast y"
+ " ip " MY_IP_ADDRESS
+ " ether " MY_ETHERNET_ADDRESS))
+#endif
+ rtems_panic ("Can't attach Ethernet driver.\n");
+
+#if (defined (TRACE_NETWORK_DRIVER))
+ /*
+ * Turn on debugging
+ */
+ if (rtems_ka9q_execute_command ("trace rtems input <stdout>")
+ || rtems_ka9q_execute_command ("trace rtems output <stdout>")
+ || rtems_ka9q_execute_command ("trace rtems ascii <stdout>"))
+ rtems_panic ("Can't set tracing for Ethernet driver.\n");
+#endif
+
+ /*
+ * Configure the driver
+ */
+ if (rtems_ka9q_execute_command ("ifconfig rtems broadcast 255.255.255.255"))
+ rtems_panic ("Can't configure Ethernet driver.\n");
+
+ /*
+ * Add the ethernet broadcast address to the ARP table.
+ */
+ if (rtems_ka9q_execute_command ("arp add 255.255.255.255 ether FF:FF:FF:FF:FF:FF"))
+ rtems_panic ("Can't add broadcast entry to ARP table.\n");
+
+#if (defined (USE_BOOTP))
+ {
+ int i;
+ /*
+ * Get BOOTP information
+ */
+ for (i = 0 ; ; ) {
+ if (rtems_ka9q_execute_command ("bootp") == 0)
+ break;
+ if (++i == 10)
+ rtems_panic ("Can't get information from BOOTP server.\n");
+ delay_task (i);
+ }
+ if (BootpFileName)
+ printf ("BOOTP filename: `%s'\n", BootpFileName);
+ else
+ printf ("BOOTP -- No filename!\n");
+ }
+#else
+ if (rtems_ka9q_execute_command ("ifconfig rtems netmask 255.255.255.0"))
+ rtems_panic ("Can't set netmask.\n");
+ if (rtems_ka9q_execute_command ("route add default rtems"))
+ rtems_panic ("Can't add default route.\n");
+ printf ("Routing table after adding default route\n");
+ rtems_ka9q_execute_command ("route");
+#endif
+
+ /*
+ * Issue a gratuitous ARP request to update tables in
+ * other hosts on this network.
+ */
+ if (rtems_ka9q_execute_command ("arp gratuitous rtems"))
+ rtems_panic ("Can't send gratuitous ARP.\n");
+
+ /*
+ * Everything is now running
+ */
+ printf ("NETWORK INITIALIZED!\n");
+
+ /*
+ * See if sockets work properly
+ */
+ doSocket ();
+
+ /*
+ * Wind things up
+ */
+ delay_task (2);
+ rtems_ka9q_execute_command ("detach rtems");
+ exit (0);
+}
diff --git a/netdemo/test.c b/netdemo/test.c
new file mode 100644
index 0000000..de0ee80
--- /dev/null
+++ b/netdemo/test.c
@@ -0,0 +1,313 @@
+/*
+ * Test KA9Q networking
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <socket.h>
+#include <sockaddr.h>
+#include <netuser.h>
+#include <rtems_ka9q.h>
+
+#define NSERVER 2
+#define BASE_PORT 24742
+
+#define DATA_SINK_HOST "128.233.14.1"
+
+/*
+ * Display the contents of several KA9Q tables
+ */
+static void
+show_ka9q_tables (void)
+{
+ printf ("\n****************** MALLOC Statistics ***************\n");
+ malloc_dump ();
+ printf ("\n****************** MBUF Statistics ***************\n");
+ mbufstat ();
+ mbufsizes ();
+ printf ("\n****************** Routing Table ***************\n");
+ rtems_ka9q_execute_command ("route");
+ printf ("\n****************** ARP Table ***************\n");
+ rtems_ka9q_execute_command ("arp");
+ printf ("\n****************** Driver Statistics ***************\n");
+ rtems_ka9q_execute_command ("ifconfig rtems");
+ printf ("\n****************** Ip Statistics ***************\n");
+ rtems_ka9q_execute_command ("ip status");
+ printf ("\n****************** ICMP Statistics ***************\n");
+ rtems_ka9q_execute_command ("icmp status");
+ printf ("\n****************** UDP Statistics ***************\n");
+ rtems_ka9q_execute_command ("udp status");
+ printf ("\n****************** TCP Statistics ***************\n");
+ rtems_ka9q_execute_command ("tcp status");
+}
+
+/*
+ * Stress the transmit queue -- send a large number of UDP packets
+ */
+static void
+transmitUdp (void)
+{
+ int s;
+ int i;
+ static struct sockaddr_in myAddr, farAddr;
+ static char cbuf[800];
+ static char bigbuf[20000];
+
+ printf ("Create socket.\n");
+ s = socket (AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ rtems_panic ("Can't create socket: %s", strerror (errno));
+ myAddr.sin_family = AF_INET;
+ myAddr.sin_port = 1234;
+ myAddr.sin_addr.s_addr = INADDR_ANY;
+ printf ("Bind socket.\n");
+ if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0)
+ rtems_panic ("Can't bind socket: %s", strerror (errno));
+ farAddr.sin_family = AF_INET;
+ farAddr.sin_port = 9; /* The `discard' port */
+ farAddr.sin_addr.s_addr = 0xFFFFFFFF;
+ for (i = 0 ; i < 5 ; i++) {
+ if (sendto (s, cbuf, sizeof cbuf, 0, (struct sockaddr *)&farAddr, sizeof farAddr) < 0)
+ rtems_panic ("Can't broadcast: %s", strerror (errno));
+ }
+ farAddr.sin_addr.s_addr = aton (DATA_SINK_HOST);
+ for (i = 0 ; i < 500 ; i++) {
+ if (sendto (s, cbuf, sizeof cbuf, 0, (struct sockaddr *)&farAddr, sizeof farAddr) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ if (sendto (s, cbuf, sizeof cbuf, 0, (struct sockaddr *)&farAddr, sizeof farAddr) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ }
+ for (i = 0 ; i < 2 ; i++) {
+ if (sendto (s, bigbuf, sizeof bigbuf, 0, (struct sockaddr *)&farAddr, sizeof farAddr) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ if (sendto (s, bigbuf, sizeof bigbuf, 0, (struct sockaddr *)&farAddr, sizeof farAddr) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ }
+ close (s);
+}
+
+/*
+ * Stress the transmit queue -- send a large number of TCP packets
+ */
+static void
+transmitTcp (void)
+{
+ int s;
+ int i;
+ static struct sockaddr_in myAddr, farAddr;
+ static char cbuf[800];
+ static char bigbuf[20000];
+
+ printf ("Create socket.\n");
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ rtems_panic ("Can't create socket: %s", strerror (errno));
+ myAddr.sin_family = AF_INET;
+ myAddr.sin_port = 1234;
+ myAddr.sin_addr.s_addr = INADDR_ANY;
+ printf ("Bind socket.\n");
+ if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0)
+ rtems_panic ("Can't bind socket: %s", strerror (errno));
+ farAddr.sin_family = AF_INET;
+ farAddr.sin_port = 9; /* The `discard' port */
+ farAddr.sin_addr.s_addr = aton (DATA_SINK_HOST);
+ if (connect (s, (struct sockaddr *)&farAddr, sizeof farAddr) < 0) {
+ printf ("Can't connect socket: %s\n", strerror (errno));
+ close (s);
+ return;
+ }
+ for (i = 0 ; i < 500 ; i++) {
+ if (write (s, cbuf, sizeof cbuf) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ }
+ for (i = 0 ; i < 2 ; i++) {
+ if (write (s, bigbuf, sizeof bigbuf) < 0)
+ rtems_panic ("Can't send: %s", strerror (errno));
+ }
+ close (s);
+}
+
+/*
+ * Echo characters back to a telnet session
+ *
+ * With this running on the test machine you can go to
+ * another machine on your network and run:
+ * telnet test_machine the_port_number_with_which_this_function_was_started
+ * Everything you type should be echoed back.
+ */
+static void
+echoTask (rtems_task_argument fd)
+{
+ char cbuf[512];
+ int n;
+ rtems_status_code sc;
+
+ for (;;) {
+#if 0
+ n = read (fd, cbuf, sizeof cbuf);
+#else
+ n = read (fd, cbuf, 1);
+#endif
+ if (n == 0) {
+ printf ("EOF\n");
+ break;
+ }
+ else if (n < 0) {
+ rtems_panic ("Error receiving message: %s", strerror (errno));
+ }
+ printf ("Received: %d\n", n);
+ if (send (fd, cbuf, n, 0) < 0)
+ rtems_panic ("Error sending message: %s", strerror (errno));
+ if (cbuf[0] == '\007')
+ show_ka9q_tables ();
+ if (cbuf[0] == 'Q')
+ break;
+ }
+ if (close (fd) < 0)
+ rtems_panic ("Can't close connection: %s", strerror (errno));
+ sc = rtems_task_delete (RTEMS_SELF);
+ rtems_panic ("Task deletion failed: %s", rtems_status_text (sc));
+}
+
+static void
+echoServer (unsigned short port)
+{
+ int s, s1;
+ struct sockaddr_in myAddr, farAddr;
+ int addrlen;
+ rtems_id tid;
+ rtems_task_priority my_priority;
+ rtems_status_code sc;
+ char c = 'a';
+
+ printf ("Create socket.\n");
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ rtems_panic ("Can't create socket: %s", strerror (errno));
+ myAddr.sin_family = AF_INET;
+ myAddr.sin_port = port;
+ myAddr.sin_addr.s_addr = INADDR_ANY;
+ memset (myAddr.sin_zero, '\0', sizeof myAddr.sin_zero);
+ printf ("Bind socket.\n");
+ if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0)
+ rtems_panic ("Can't bind socket: %s", strerror (errno));
+ printf ("Listen.\n");
+ if (listen (s, 2) < 0)
+ rtems_panic ("Can't listen on socket: %s", strerror (errno));
+ for (;;) {
+ printf ("Accept.\n");
+ addrlen = sizeof farAddr;
+ s1 = accept (s, (struct sockaddr *)&farAddr, &addrlen);
+ if (s1 < 0)
+ rtems_panic ("Can't accept connection: %s", strerror (errno));
+ else
+ printf ("ACCEPTED:%lX\n", farAddr.sin_addr.s_addr);
+
+ /*
+ * Start an echo task
+ */
+ rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &my_priority);
+ sc = rtems_task_create (rtems_build_name ('E', 'C', 'H', c),
+ my_priority,
+ 8*1024,
+ RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+ &tid);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't create echo task; %s\n", rtems_status_text (sc));
+ if (c == 'z')
+ c = 'a';
+ else
+ c++;
+ sc = rtems_task_start (tid, echoTask, s1);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't start echo task; %s\n", rtems_status_text (sc));
+ }
+}
+
+/*
+ * Run an echo server
+ */
+static void
+runEchoServer (rtems_task_argument arg)
+{
+ echoServer (arg);
+ rtems_task_delete (RTEMS_SELF);
+}
+
+/*
+ * Test some socket stuff
+ */
+void
+doSocket (void)
+{
+ int i;
+ rtems_status_code sc;
+ rtems_task_priority my_priority;
+
+ /*
+ * Spawn other servers
+ */
+ rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &my_priority);
+ for (i = 0 ; i < NSERVER ; i++) {
+ rtems_id tid;
+ sc = rtems_task_create (rtems_build_name ('S', 'R', 'V', 'A' + i),
+ my_priority - 1,
+ 8*1024,
+ RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+ &tid);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't create server; %s\n", rtems_status_text (sc));
+ return;
+ }
+ sc = rtems_task_start (tid, runEchoServer, BASE_PORT + i);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't start server; %s\n", rtems_status_text (sc));
+ return;
+ }
+ }
+
+ /*
+ * Wait for characters from console terminal
+ */
+ for (;;) {
+ switch (getchar ()) {
+ case '\004':
+ return;
+
+ case 't':
+ /*
+ * Test the transmit queues
+ */
+ transmitTcp ();
+ break;
+
+ case 'u':
+ /*
+ * Test the transmit queues
+ */
+ transmitUdp ();
+ break;
+
+ case 's':
+ /*
+ * Show what's been accomplished
+ */
+ show_ka9q_tables ();
+ break;
+ }
+ }
+}
diff --git a/tftpTest/Makefile b/tftpTest/Makefile
new file mode 100644
index 0000000..e9f7bdd
--- /dev/null
+++ b/tftpTest/Makefile
@@ -0,0 +1,60 @@
+SAMPLE=tftp
+PGM=${ARCH}/$(SAMPLE).exe
+
+MANAGERS=io event semaphore timer rate_monotonic
+
+# C source names, if any, go here -- minus the .c
+C_PIECES= init test
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+DOCTYPES=
+DOCS=$(DOCTYPES:%=$(SAMPLE).%)
+
+SRCS=$(DOCS) $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+PRINT_SRCS=$(DOCS)
+
+PGM=${ARCH}/$(SAMPLE).exe
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0x40000 # KA9Q needs more space
+CFLAGS_OPTIMIZE_V +=
+CFLAGS_DEBUG_V += -qrtems_debug # -v
+
+
+LD_PATHS +=
+LD_LIBS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(PGM)
+
+${PGM}: $(OBJS) $(LINK_FILES)
+ $(make-exe)
+
+# Install the program(s), appending _g or _p as appropriate.
+# for include files, just use $(INSTALL)
+install: all
+ $(INSTALL_VARIANT) -m 555 ${PGM} ${PROJECT_RELEASE}/tests
diff --git a/tftpTest/init.c b/tftpTest/init.c
new file mode 100644
index 0000000..d4b6100
--- /dev/null
+++ b/tftpTest/init.c
@@ -0,0 +1,114 @@
+/*
+ * Test RTEMS/KA9Q TFTP device driver
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+#include <bsp.h>
+#include <rtems/error.h>
+#include <tftp.h>
+#include <rtems_ka9q.h>
+#include <stdio.h>
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_EXECUTIVE_RAM_SIZE (128*1024)
+#define CONFIGURE_MAXIMUM_SEMAPHORES 10
+#define CONFIGURE_MAXIMUM_TIMERS 5
+#define CONFIGURE_MAXIMUM_PERIODS 1
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 10486
+
+#define CONFIGURE_INIT
+rtems_task Init (rtems_task_argument argument);
+
+#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE
+rtems_driver_address_table Device_drivers[] = {
+ CONSOLE_DRIVER_TABLE_ENTRY,
+ CLOCK_DRIVER_TABLE_ENTRY,
+ TFTP_DRIVER_TABLE_ENTRY,
+};
+
+#include <confdefs.h>
+
+/*
+ * Board ethernet address
+ * REPLACE THIS WITH YOUR OWN VALUE BEFORE TRYING TO USE THIS PROGRAM!
+ */
+#define MY_ETHERNET_ADDRESS "48:3E:3E:21:2E:D5"
+#define MY_ETHERNET_ADDRESS "prom"
+
+#include <bootp.h>
+extern void testTFTP (void);
+
+/*
+ * RTEMS Startup Task
+ */
+rtems_task
+Init (rtems_task_argument ignored)
+{
+ int i;
+ rtems_task_priority oldPri;
+ rtems_interval ticksPerSecond;
+
+ /*
+ * Get some timing information
+ */
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
+
+ /*
+ * Start KA9Q
+ */
+ rtems_task_set_priority (RTEMS_SELF, 30, &oldPri);
+ rtems_ka9q_start (20);
+
+ /*
+ * Hook up drivers
+ */
+ if (rtems_ka9q_execute_command ("attach rtems broadcast n ether " MY_ETHERNET_ADDRESS))
+ rtems_panic ("Can't attach Ethernet driver.\n");
+
+ /*
+ * Configure the driver
+ */
+ if (rtems_ka9q_execute_command ("ifconfig rtems broadcast 255.255.255.255"))
+ rtems_panic ("Can't configure Ethernet driver.\n");
+
+ /*
+ * Add the ethernet broadcast address to the ARP table.
+ */
+ if (rtems_ka9q_execute_command ("arp add 255.255.255.255 ether FF:FF:FF:FF:FF:FF"))
+ rtems_panic ("Can't add broadcast entry to ARP table.\n");
+
+ /*
+ * Get BOOTP information
+ */
+ for (i = 0 ; ; ) {
+ if (rtems_ka9q_execute_command ("bootp") == 0)
+ break;
+ if (++i == 10)
+ rtems_panic ("Can't get information from BOOTP server.\n");
+ rtems_task_wake_after (i * ticksPerSecond);
+ }
+
+ /*
+ * Test TFTP driver
+ */
+ testTFTP ();
+
+ /*
+ * Wind things up
+ */
+ rtems_task_wake_after (2 * ticksPerSecond);
+ rtems_ka9q_execute_command ("detach rtems");
+ exit (0);
+}
diff --git a/tftpTest/test.c b/tftpTest/test.c
new file mode 100644
index 0000000..b900030
--- /dev/null
+++ b/tftpTest/test.c
@@ -0,0 +1,159 @@
+/*
+ * Test RTEMS/KA9Q TFTP device driver
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+#include <stdio.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <bootp.h>
+#include <netuser.h>
+
+static char cbuf[1024];
+static char *fullname;
+static rtems_interval then, now;
+
+static void
+showRate (unsigned long totalRead)
+{
+ int elapsed;
+
+ printf ("Read %lu bytes", totalRead);
+ elapsed = now - then;
+ if (elapsed) {
+ rtems_interval ticksPerSecond;
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
+ printf (" (%ld bytes/sec)",
+ (long)(((long long)totalRead * ticksPerSecond)
+ / elapsed));
+ }
+ printf (".\n");
+rtems_ka9q_execute_command ("ifconfig rtems");
+}
+
+static void
+testRawRead (void)
+{
+ int fd;
+ int nread;
+ unsigned long totalRead = 0;
+
+ fd = open (fullname, O_RDONLY);
+ if (fd < 0) {
+ printf ("Open failed: %s\n", strerror (errno));
+ return;
+ }
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
+ for (;;) {
+ nread = read (fd, cbuf, sizeof cbuf);
+ if (nread < 0) {
+ printf ("Read failed: %s\n", strerror (errno));
+ close (fd);
+ return;
+ }
+ if (nread == 0)
+ break;
+ totalRead += nread;
+ }
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
+ close (fd);
+ showRate (totalRead);
+}
+
+static void
+testFread (void)
+{
+ FILE *fp;
+ int nread;
+ unsigned long totalRead = 0;
+
+ fp = fopen (fullname, "r");
+ if (fp == NULL) {
+ printf ("Open failed: %s\n", strerror (errno));
+ return;
+ }
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
+ for (;;) {
+ nread = fread (cbuf, sizeof cbuf[0], sizeof cbuf, fp);
+ if (nread < 0) {
+ printf ("Read failed: %s\n", strerror (errno));
+ fclose (fp);
+ return;
+ }
+ if (nread == 0)
+ break;
+ totalRead += nread;
+ }
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
+ fclose (fp);
+ showRate (totalRead);
+}
+
+static int
+makeFullname (rtems_unsigned32 host, const char *file)
+{
+ const char *hostname;
+
+ if (host) {
+ hostname = rtems_hostname_for_address (BootpHost.s_addr, 0);
+ if (hostname == NULL) {
+ printf ("No host to read from!\n");
+ return 0;
+ }
+ }
+ else {
+ hostname = "";
+ }
+ fullname = realloc (fullname, 8 + strlen (file) + strlen (hostname));
+ sprintf (fullname, "/TFTP/%s/%s", hostname, file);
+ printf ("Read `%s'.\n", fullname);
+ return 1;
+}
+
+void
+testTFTP (void)
+{
+ /*
+ * Check that invalid file names are reported as such
+ */
+ if (makeFullname (0, "")) {
+ testRawRead ();
+ testFread ();
+ }
+
+ /*
+ * Check that non-existent files are reported as such
+ */
+ if (makeFullname (0, "BAD-FILE-NAME")) {
+ testRawRead ();
+ testFread ();
+ }
+
+ /*
+ * Check read speed
+ */
+ if (BootpFileName == NULL) {
+ printf ("Nothing to read!\n");
+ return;
+ }
+ if (makeFullname (BootpHost.s_addr, BootpFileName)) {
+ testRawRead ();
+ testFread ();
+ }
+}
+ #include <limits.h>
+ int foo = INT_MAX;
diff --git a/ttcp/Makefile b/ttcp/Makefile
new file mode 100644
index 0000000..5b46a4b
--- /dev/null
+++ b/ttcp/Makefile
@@ -0,0 +1,62 @@
+#
+# $Revision$ $Date$ $Author$
+#
+
+SAMPLE=ttcp
+PGM=${ARCH}/$(SAMPLE).exe
+
+MANAGERS=io event message rate_monotonic semaphore timer
+
+# C source names, if any, go here -- minus the .c
+C_PIECES= init rtems_ttcp
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+DOCTYPES=
+DOCS=$(DOCTYPES:%=$(SAMPLE).%)
+
+SRCS=$(DOCS) $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
+
+PRINT_SRCS=$(DOCS)
+
+PGM=${ARCH}/$(SAMPLE).exe
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS += -I./include
+CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0x200000 # KA9Q needs more space
+CFLAGS_OPTIMIZE_V +=
+
+LD_PATHS +=
+LD_LIBS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(PGM)
+
+${PGM}: $(OBJS) $(LINK_FILES)
+ $(make-exe)
+
+install: $(INSTALL_TARGET)
+
+$(INSTALL_TARGET): all
+ cp ${PGM} $(INSTALL_TARGET)
diff --git a/ttcp/README b/ttcp/README
new file mode 100644
index 0000000..10940d0
--- /dev/null
+++ b/ttcp/README
@@ -0,0 +1,19 @@
+This directory contains an RTEMS application for measuring TCP/UDP
+network throughput. The ttcp_orig subdirectory contains the original
+UNIX program which can be compiled and run on your host machine.
+
+The RTEMS version of the test program is a little clumsy to use. You
+have to edit the rtems_ttcp.c source file and change the ttcp_argv
+array of strings to set the arguments you want passed to the ttcp
+task.
+
+It does work, though. The best throughputs I've seen so far are:
+ 68360 card can transmit a TCP stream at 198 kbytes/second.
+ 68360 card can receive a TCP stream at 119 kbytes/second.
+In both cases, the other end of the transfer was a 486DX2/66 running
+OPENSTEP/MACH 4.1.
+
+One noteworthy item is that I was able to get the UNIX test program
+running under RTEMS with no changes to the test program itself. The
+entire UNIX source file is included, without changes, into the RTEMS
+source file.
diff --git a/ttcp/include/arpa/inet.h b/ttcp/include/arpa/inet.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ttcp/include/arpa/inet.h
diff --git a/ttcp/include/netdb.h b/ttcp/include/netdb.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ttcp/include/netdb.h
diff --git a/ttcp/include/netinet/in.h b/ttcp/include/netinet/in.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ttcp/include/netinet/in.h
diff --git a/ttcp/include/netinet/tcp.h b/ttcp/include/netinet/tcp.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ttcp/include/netinet/tcp.h
diff --git a/ttcp/include/sys/socket.h b/ttcp/include/sys/socket.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ttcp/include/sys/socket.h
diff --git a/ttcp/init.c b/ttcp/init.c
new file mode 100644
index 0000000..7d19353
--- /dev/null
+++ b/ttcp/init.c
@@ -0,0 +1,173 @@
+/*
+ * RTEMS configuration/initialization
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+/*#define TRACE_SCC1 1 */
+#include <bsp.h>
+
+#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_TEST_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_EXECUTIVE_RAM_SIZE (512*1024)
+#define CONFIGURE_MAXIMUM_SEMAPHORES 20
+#define CONFIGURE_MAXIMUM_TASKS 20
+#define CONFIGURE_MAXIMUM_TIMERS 10
+#define CONFIGURE_MAXIMUM_PERIODS 1
+#define CONFIGURE_MICROSECONDS_PER_TICK 10486
+
+#define CONFIGURE_INIT
+rtems_task Init (rtems_task_argument argument);
+
+#include <confdefs.h>
+
+#include <stdio.h>
+#include <rtems_ka9q.h>
+
+/*
+ * Board ethernet address
+ * REPLACE THIS WITH YOUR OWN VALUE BEFORE TRYING TO USE THIS PROGRAM!
+ */
+#define MY_ETHERNET_ADDRESS "3B:1D:3E:21:E2:D5"
+#define MY_ETHERNET_ADDRESS "prom"
+
+/*
+ * Use BOOTP to get information about me?
+ */
+#define USE_BOOTP 1
+
+#if (defined (USE_BOOTP))
+#include <bootp.h>
+#else
+/*
+ * Information about me if BOOTP isn't used
+ * CHOOSE A VALUE APPROPRIATE TO YOUR NETWORK!
+ */
+#define MY_IP_ADDRESS "128.233.14.68"
+#endif
+
+/*
+ * Suspend execution for the specified number of seconds
+ */
+static void
+delay_task (int seconds)
+{
+ rtems_task_wake_after ((seconds * 1000000) / BSP_Configuration.microseconds_per_tick);
+}
+
+/*
+ * RTEMS Startup Task
+ */
+rtems_task
+Init (rtems_task_argument ignored)
+{
+ rtems_task_priority oldPri;
+ rtems_mode old_mode;
+
+#if (defined (m68040))
+ /*
+ * Hook up FPSP
+ */
+ M68kFPSPInstallExceptionHandlers ();
+
+ /*
+ * Turn on instruction cache
+ */
+ asm volatile ("cinva bc");
+ asm volatile ("movec %0,itt0" : : "d" (0x00ffc004));
+ asm volatile ("movec %0,dtt0" : : "d" (0x00ffc040));
+ asm volatile ("cinva bc\n\t"
+ "movec %0,cacr" : : "d" (0x80008000));
+#endif
+
+ /*
+ * Start KA9Q
+ */
+ rtems_task_set_priority (RTEMS_SELF, 30, &oldPri);
+ rtems_ka9q_start (30);
+
+ /*
+ * Hook up drivers
+ */
+#if (defined (USE_BOOTP))
+ if (rtems_ka9q_execute_command ("attach rtems"
+ " rbuf 24 tbuf 5"
+ " ether " MY_ETHERNET_ADDRESS))
+#else
+ if (rtems_ka9q_execute_command ("attach rtems"
+ " rbuf 24 tbuf 5"
+ " ip " MY_IP_ADDRESS
+ " ether " MY_ETHERNET_ADDRESS))
+#endif
+ rtems_panic ("Can't attach Ethernet driver.\n");
+
+ /*
+ * Configure the driver
+ */
+ if (rtems_ka9q_execute_command ("ifconfig rtems broadcast 255.255.255.255"))
+ rtems_panic ("Can't configure Ethernet driver.\n");
+
+ /*
+ * Add the ethernet broadcast address to the ARP table.
+ */
+ if (rtems_ka9q_execute_command ("arp add 255.255.255.255 ether FF:FF:FF:FF:FF:FF"))
+ rtems_panic ("Can't add broadcast entry to ARP table.\n");
+
+#if (defined (USE_BOOTP))
+ {
+ int i;
+ /*
+ * Get BOOTP information
+ */
+ for (i = 0 ; ; ) {
+ if (rtems_ka9q_execute_command ("bootp") == 0)
+ break;
+ if (++i == 10)
+ rtems_panic ("Can't get information from BOOTP server.\n");
+ delay_task (i);
+ }
+ if (BootpFileName)
+ printf ("BOOTP filename: `%s'\n", BootpFileName);
+ else
+ printf ("BOOTP -- No filename!\n");
+ }
+#else
+ if (rtems_ka9q_execute_command ("ifconfig rtems netmask 255.255.255.0"))
+ rtems_panic ("Can't set netmask.\n");
+ if (rtems_ka9q_execute_command ("route add default rtems"))
+ rtems_panic ("Can't add default route.\n");
+ printf ("Routing table after adding default route\n");
+ rtems_ka9q_execute_command ("route");
+#endif
+
+ rtems_ka9q_execute_command ("tcp window");
+ rtems_ka9q_execute_command ("tcp window 4096");
+ rtems_ka9q_execute_command ("tcp window");
+
+ /*
+ * Whew!
+ */
+ printf ("NETWORK INITIALIZED!\n");
+
+ /*
+ * Let other tasks preempt this one
+ */
+ rtems_task_mode (RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, &old_mode);
+
+ /*
+ * See if sockets work properly
+ */
+ test_network ();
+ exit (0);
+}
diff --git a/ttcp/rtems_ttcp.c b/ttcp/rtems_ttcp.c
new file mode 100644
index 0000000..d266b42
--- /dev/null
+++ b/ttcp/rtems_ttcp.c
@@ -0,0 +1,294 @@
+/*
+ * A collection of hacks, glue, and patches to
+ * provide a `UNIX-like' environment to ttcp.
+ *
+ * Some of the code here should migrate to the libc
+ * support routines some day. Some of the more sleazy
+ * hacks should never make it outside this file!
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+#include <stdio.h>
+#include <rtems.h>
+#include <rtems_ka9q.h>
+#include <rtems/error.h>
+#include <socket.h>
+#include <sockaddr.h>
+#include <netuser.h>
+#include <sys/time.h>
+
+/*
+ * Glue between UNIX-style ttcp code and RTEMS
+ */
+int rtems_ttcp_main (int argc, char **argv);
+
+#define ENOBUFS 2000
+
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+ #define h_addr h_addr_list[0] /* address, for backward compatiblity */
+};
+
+#define SOL_SOCKET 0
+#define SO_DEBUG 0
+
+static struct hostent *
+gethostbyname (const char *cp)
+{
+ rtems_panic ("gethostbyname()");
+}
+
+static int
+select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+ rtems_panic ("select()");
+}
+
+static void
+(*signal(int sig, void (*func)()))()
+{
+ return 0;;
+}
+
+static char *
+rtems_inet_ntoa (struct in_addr in)
+{
+ return inet_ntoa (in.s_addr);
+}
+#define inet_ntoa rtems_inet_ntoa
+#define inet_addr(cp) resolve(cp)
+
+int
+gettimeofday (struct timeval *tp, struct timezone *tzp)
+{
+ rtems_clock_time_value now;
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TIME_VALUE, &now);
+ tp->tv_sec = now.seconds;
+ tp->tv_usec = now.microseconds;
+ return 0;
+}
+
+#define _SYS_RESOURCE_H_
+#define RUSAGE_SELF 0 /* calling process */
+#define RUSAGE_CHILDREN -1 /* terminated child processes */
+struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ int ru_maxrss; /* maximum resident set size */
+ int ru_ixrss; /* currently 0 */
+ int ru_idrss; /* integral resident set size */
+ int ru_isrss; /* currently 0 */
+ int ru_minflt; /* page faults not requiring physical I/O */
+ int ru_majflt; /* page faults requiring physical I/O */
+ int ru_nswap; /* swaps */
+ int ru_inblock; /* block input operations */
+ int ru_oublock; /* block output operations */
+ int ru_msgsnd; /* messages sent */
+ int ru_msgrcv; /* messages received */
+ int ru_nsignals; /* signals received */
+ int ru_nvcsw; /* voluntary context switches */
+ int ru_nivcsw; /* involuntary context switches */
+};
+int
+getrusage(int ignored, struct rusage *ru)
+{
+ rtems_clock_time_value now;
+ static struct rusage nullUsage;
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TIME_VALUE, &now);
+ *ru = nullUsage;
+ ru->ru_stime.tv_sec = now.seconds;
+ ru->ru_stime.tv_usec = now.microseconds;
+ ru->ru_utime.tv_sec = 0;
+ ru->ru_utime.tv_usec = 0;
+ return 0;
+}
+
+/*
+ * Display the contents of several KA9Q tables
+ */
+static void
+show_ka9q_tables (void)
+{
+ printf ("\n****************** MBUF Statistics ***************\n");
+ mbufstat ();
+ mbufsizes ();
+ printf ("\n****************** Routing Table ***************\n");
+ rtems_ka9q_execute_command ("route");
+ printf ("\n****************** ARP Table ***************\n");
+ rtems_ka9q_execute_command ("arp");
+ printf ("\n****************** Driver Statistics ***************\n");
+ rtems_ka9q_execute_command ("ifconfig rtems");
+ printf ("\n****************** Ip Statistics ***************\n");
+ rtems_ka9q_execute_command ("ip status");
+ printf ("\n****************** ICMP Statistics ***************\n");
+ rtems_ka9q_execute_command ("icmp status");
+ printf ("\n****************** UDP Statistics ***************\n");
+ rtems_ka9q_execute_command ("udp status");
+ printf ("\n****************** TCP Statistics ***************\n");
+ rtems_ka9q_execute_command ("tcp status");
+}
+
+static void
+rtems_ttcp_exit (int code)
+{
+ rtems_interval ticksPerSecond;
+
+ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
+ rtems_task_wake_after (ticksPerSecond * 2);
+ show_ka9q_tables ();
+ exit (code);
+}
+
+/*
+ * Task to run UNIX ttcp command
+ */
+char *__progname;
+static void
+ttcpTask (rtems_task_argument arg)
+{
+ int code;
+ int argc;
+ char arg0[10];
+ char *argv[20];
+ char linebuf[200];
+
+ for (;;) {
+ char *cp;
+
+ /*
+ * Set up first argument
+ */
+ argc = 1;
+ strcpy (arg0, "ttcp");
+ argv[0] = __progname = arg0;
+
+ /*
+ * Read a line
+ */
+ printf (">>> %s ", argv[0]);
+ fflush (stdout);
+ fgets (linebuf, sizeof linebuf, stdin);
+
+ /*
+ * Break line into arguments
+ */
+ cp = linebuf;
+ for (;;) {
+ while (isspace (*cp))
+ *cp++ = '\0';
+ if (*cp == '\0')
+ break;
+ if (argc >= ((sizeof argv / sizeof argv[0]) - 1)) {
+ printf ("Too many arguments.\n");
+ argc = 0;
+ break;
+ }
+ argv[argc++] = cp;
+ while (!isspace (*cp)) {
+ if (*cp == '\0')
+ break;
+ cp++;
+ }
+ }
+ if (argc > 1) {
+ argv[argc] = NULL;
+ break;
+ }
+ printf ("You must give some arguments!\n");
+ printf ("At the very least, you must provide\n");
+ printf (" -r\n");
+ printf ("or\n");
+ printf (" -t destination.internet.address\n");
+ }
+ code = rtems_ttcp_main (argc, argv);
+ rtems_ttcp_exit (code);
+}
+
+static int
+rtems_ttcp_bind (int s, struct sockaddr *name, int namelen)
+{
+ struct sockaddr_in *in = (struct sockaddr_in *)name;
+ /*
+ * KA9Q doesn't like 0 port numbers
+ */
+ if (in->sin_port == 0)
+ in->sin_port = 2662;
+ return bind (s, name, namelen);
+}
+
+/*
+ * Test network throughput
+ */
+void
+test_network (void)
+{
+ rtems_id tid;
+ rtems_status_code sc;
+ rtems_time_of_day now;
+ rtems_task_priority my_priority;
+
+ /*
+ * Set up time-of-day clock
+ */
+ now.year = 1997;
+ now.month = 1;
+ now.day = 1;
+ now.hour = 0;
+ now.minute = 0;
+ now.second = 0;
+ now.ticks = 0;
+ sc = rtems_clock_set (&now);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't set date/time; %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ /*
+ * Spawn test task
+ */
+ rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &my_priority);
+ sc = rtems_task_create (rtems_build_name ('T', 'T', 'C', 'P'),
+ my_priority,
+ 32*1024,
+ RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+ RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+ &tid);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't create task; %s\n", rtems_status_text (sc));
+ return;
+ }
+ sc = rtems_task_start (tid, ttcpTask, 0);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printf ("Can't start task; %s\n", rtems_status_text (sc));
+ return;
+ }
+ rtems_task_suspend (RTEMS_SELF);
+}
+
+#define main rtems_ttcp_main
+#define exit(code) close(fd),rtems_ttcp_exit(code)
+#define bind rtems_ttcp_bind
+#define read_timer rtems_read_timer
+
+/*
+ * RTEMS/KA9Q code expects port numbers in host byte order!
+ */
+#define htons(x) (x)
+
+#include "ttcp_orig/ttcp.c"
diff --git a/ttcp/ttcp_orig/README b/ttcp/ttcp_orig/README
new file mode 100644
index 0000000..215ddac
--- /dev/null
+++ b/ttcp/ttcp_orig/README
@@ -0,0 +1,27 @@
+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
+ and BSD-based systems. This version also uses getopt(3)
+ and has 2 new options: -f and -T.
+
+ttcp.c-brl Original source from BRL.
+
+ttcp.1 Manual page (describes ttcp.c options, which are a
+ superset of the other version).
+
+
+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/ttcp_orig/ttcp.1 b/ttcp/ttcp_orig/ttcp.1
new file mode 100644
index 0000000..a45f8e6
--- /dev/null
+++ b/ttcp/ttcp_orig/ttcp.1
@@ -0,0 +1,144 @@
+'\"macro stdmacro
+.TH TTCP 1 local
+.SH NAME
+ttcp \- test TCP and UDP performance
+.SH SYNOPSIS
+.B ttcp \-t
+.RB [ \-u ]
+.RB [ \-s ]
+.RB [ \-p\0 \fIport\fP ]
+.RB [ \-l\0 \fIbuflen\fP ]
+.RB [ \-b\0 \fIsize\fP ]
+.RB [ \-n\0 \fInumbufs\fP ]
+.RB [ \-A\0 \fIalign\fP ]
+.RB [ \-O\0 \fIoffset\fP ]
+.RB [ \-f\0 \fIformat\fP ]
+.RB [ \-D ]
+.RB [ \-v]
+.RB host
+.RB [ < in ]
+.br
+.B ttcp \-r
+.RB [ \-u ]
+.RB [ \-s ]
+.RB [ \-p\0 \fIport\fP ]
+.RB [ \-l\0 \fIbuflen\fP ]
+.RB [ \-b\0 \fIsize\fP ]
+.RB [ \-A\0 \fIalign\fP ]
+.RB [ \-O\0 \fIoffset\fP ]
+.RB [ \-f\0 \fIformat\fP ]
+.RB [ \-B ]
+.RB [ \-T ]
+.RB [ \-v ]
+.RB [ > out ]
+.SH DESCRIPTION
+.I Ttcp
+times the transmission and reception of data between two systems using
+the UDP or TCP protocols.
+It differs from common ``blast'' tests, which tend to measure the remote
+.I inetd
+as much as the network performance, and which usually do not allow
+measurements at the remote end of a UDP transmission.
+.PP
+For testing, the transmitter should be started with \f3\-t\f1 and \f3\-s\f1
+after the receiver has been started with \f3\-r\f1 and \f3\-s\f1.
+Tests lasting at least tens of seconds should be used to obtain accurate
+measurements.
+Graphical presentations of throughput versus buffer size for
+buffers ranging from tens of bytes to several ``pages'' can illuminate
+bottlenecks.
+.PP
+.I Ttcp
+can also be used as a ``network pipe'' for moving directory hierarchies
+between systems when routing problems exist or when the use of other
+mechanisms is undesirable. For example, on the destination machine, use:
+.Ex
+ttcp \-r \-B | tar xvpf \-
+.Ee
+.PP
+and on the source machine:
+.Ex
+tar cf \- directory | ttcp \-t dest_machine
+.Ee
+.PP
+Additional intermediate machines can be included by:
+.Ex
+ttcp \-r | ttcp \-t next_machine
+.Ee
+.SH OPTIONS
+.TP 10
+\-t
+Transmit mode.
+.TP 10
+\-r
+Receive mode.
+.TP 10
+\-u
+Use UDP instead of TCP.
+.TP 10
+\-s
+If transmitting, source a data pattern to network;
+if receiving, sink (discard) the data.
+Without the \f3\-s\f1 option, the default is to transmit data from
+.I stdin
+or print the received data to
+.IR stdout .
+.TP 10
+\-l \fIlength\fP
+Length of buffers in bytes (default 8192).
+For UDP, this value is the number of data bytes in each packet.
+The system limits the maximum UDP packet length. This limit can be
+changed with the \f3\-b\f1 option.
+.TP 10
+\-b \fIsize\fP
+Set size of socket buffer. The default varies from system to system.
+This parameter affects the maximum UDP packet length.
+It may not be possible to set this parameter on some systems
+(for example, 4.2BSD).
+.TP 10
+\-n \fInumbufs\fP
+Number of source buffers transmitted (default 2048).
+.TP 10
+\-p \fIport\fP
+Port number to send to or listen on (default 2000).
+On some systems, this port may be allocated to another network daemon.
+.TP 10
+\-D
+If transmitting using TCP, do not buffer data when sending
+(sets the TCP_NODELAY socket option).
+It may not be possible to set this parameter on some systems
+(for example, 4.2BSD).
+.TP 10
+\-B
+When receiving data, output only full blocks,
+using the block size specified by \f3\-l\f1.
+This option is useful for programs, such as \f2tar\f1(1), that require
+complete blocks.
+.TP 10
+\-A \fIalign\fP
+Align the start of buffers to this modulus (default 16384).
+.TP 10
+\-O \fIoffset\fP
+Align the start of buffers to this offset (default 0).
+For example, ``\-A8192 \-O1'' causes buffers to start at the second byte
+of an 8192-byte page.
+.TP 10
+\-f \fIformat\fP
+Specify, using one of the following characters,
+the format of the throughput rates as
+kilobits/sec ('k'), kilobytes/sec ('K'),
+megabits/sec ('m'), megabytes/sec ('M'),
+gigabits/sec ('g'), or gigabytes/sec ('G').
+The default is 'K'.
+.TP 10
+\-T
+``Touch'' the data as they are read in order to measure cache effects.
+.TP 10
+\-v
+Verbose: print more statistics.
+.TP 10
+\-d
+Debug: set the SO_DEBUG socket option.
+.SH SEE ALSO
+ping(1M), traceroute(1M), netsnoop(1M)
+
diff --git a/ttcp/ttcp_orig/ttcp.c b/ttcp/ttcp_orig/ttcp.c
new file mode 100644
index 0000000..305a7c7
--- /dev/null
+++ b/ttcp/ttcp_orig/ttcp.c
@@ -0,0 +1,841 @@
+/*
+ * 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 */
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h> /* struct timeval */
+
+#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
+
+struct sockaddr_in sinme;
+struct sockaddr_in sinhim;
+struct sockaddr_in frominet;
+
+int domain, fromlen;
+int fd; /* fd of network socket */
+
+int buflen = 8 * 1024; /* length of buffer */
+char *buf; /* ptr to dynamic buffer */
+int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */
+
+int bufoffset = 0; /* align buffer to this */
+int bufalign = 16*1024; /* modulo this */
+
+int udp = 0; /* 0 = tcp, !0 = udp */
+int options = 0; /* socket options */
+int one = 1; /* for 4.3 BSD style setsockopt() */
+short port = 5001; /* TCP port number */
+char *host; /* ptr to name of host */
+int trans; /* 0=receive, !0=transmit mode */
+int sinkmode = 0; /* 0=normal I/O, !0=sink/source mode */
+int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc
+ * resource usage. */
+int nodelay = 0; /* set TCP_NODELAY socket option */
+int b_flag = 0; /* use mread() */
+int sockbufsize = 0; /* socket buffer size to use */
+char fmt = 'K'; /* output format: k = kilobits, K = kilobytes,
+ * m = megabits, M = megabytes,
+ * g = gigabits, G = gigabytes */
+int touchdata = 0; /* access data after reading */
+
+struct hostent *addr;
+extern int errno;
+extern int optind;
+extern char *optarg;
+
+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\
+";
+
+char stats[128];
+double nbytes; /* bytes on net */
+unsigned long numCalls; /* # of I/O system calls */
+double cput, realt; /* user, real time (seconds) */
+
+void err();
+void mes();
+int pattern();
+void prep_timer();
+double read_timer();
+int Nread();
+int Nwrite();
+void delay();
+int mread();
+char *outfmt();
+
+void
+sigpipe()
+{
+}
+
+main(argc,argv)
+int argc;
+char **argv;
+{
+ unsigned long addr_tmp;
+ int c;
+
+ if (argc < 2) goto usage;
+
+ while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) {
+ 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 '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];
+ 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");
+ 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_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");
+ if (bufalign != 0)
+ buf +=(bufalign - ((int)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");
+ mes("socket");
+
+ if (bind(fd, &sinme, sizeof(sinme)) < 0)
+ err("bind");
+
+#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");
+ mes("sndbuf");
+ } else {
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
+ sizeof sockbufsize) < 0)
+ err("setsockopt: rcvbuf");
+ mes("rcvbuf");
+ }
+ }
+#endif
+
+ if (!udp) {
+ signal(SIGPIPE, sigpipe);
+ 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 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");
+ mes("nodelay");
+ }
+#endif
+ if(connect(fd, &sinhim, sizeof(sinhim) ) < 0)
+ err("connect");
+ 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");
+ }
+ fromlen = sizeof(frominet);
+ domain = AF_INET;
+ if((fd=accept(fd, &frominet, &fromlen) ) < 0)
+ err("accept");
+ { struct sockaddr_in peer;
+ int peerlen = sizeof(peer);
+ if (getpeername(fd, (struct sockaddr_in *) &peer,
+ &peerlen) < 0) {
+ err("getpeername");
+ }
+ 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;
+ 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");
+ (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( 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: %d 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 %#x\n",
+ trans?"-t":"-r",
+ buf);
+ }
+ exit(0);
+
+usage:
+ fprintf(stderr,Usage);
+ exit(1);
+}
+
+void
+err(s)
+char *s;
+{
+ fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
+ perror(s);
+ fprintf(stderr,"errno=%d\n",errno);
+ exit(1);
+}
+
+void
+mes(s)
+char *s;
+{
+ fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
+}
+
+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 */
+
+static void prusage();
+static void tvadd();
+static void tvsub();
+static void psecs();
+
+#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;
+{
+ 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);
+ prusage(&ru0, &ru1, &timedol, &time0, line);
+ (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 );
+}
+
+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,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
+ END(outp);
+ break;
+
+ case 'S':
+ tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
+ sprintf(outp,"%d.%01d", 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,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
+ END(outp);
+ break;
+
+ case 'D':
+ sprintf(outp,"%d", t == 0 ? 0 :
+ (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
+ END(outp);
+ break;
+
+ case 'K':
+ sprintf(outp,"%d", 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';
+}
+
+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;
+}
+
+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);
+}
+
+/*
+ * N R E A D
+ */
+Nread( fd, buf, count )
+int fd;
+void *buf;
+int count;
+{
+ struct sockaddr_in from;
+ int len = sizeof(from);
+ register int cnt;
+ if( udp ) {
+ cnt = recvfrom( fd, buf, count, 0, &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
+ */
+Nwrite( fd, buf, count )
+int fd;
+void *buf;
+int count;
+{
+ register int cnt;
+ if( udp ) {
+again:
+ cnt = sendto( fd, buf, count, 0, &sinhim, sizeof(sinhim) );
+ numCalls++;
+ if( cnt<0 && errno == ENOBUFS ) {
+ delay(18000);
+ errno = 0;
+ goto again;
+ }
+ } else {
+ cnt = write( fd, buf, count );
+ numCalls++;
+ }
+ return(cnt);
+}
+
+void
+delay(us)
+{
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = us;
+ (void)select( 1, (char *)0, (char *)0, (char *)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);
+}