From c87143a1734b473b7c7e238660e2071d899bbe75 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 30 Jul 1998 14:42:29 +0000 Subject: base from Eric Norum -- Demos.30May1998.tar.gz --- netdemo/Makefile | 59 ++++ netdemo/README | 27 ++ netdemo/init.c | 185 ++++++++++ netdemo/test.c | 313 +++++++++++++++++ tftpTest/Makefile | 60 ++++ tftpTest/init.c | 114 ++++++ tftpTest/test.c | 159 +++++++++ ttcp/Makefile | 62 ++++ ttcp/README | 19 + ttcp/include/arpa/inet.h | 0 ttcp/include/netdb.h | 0 ttcp/include/netinet/in.h | 0 ttcp/include/netinet/tcp.h | 0 ttcp/include/sys/socket.h | 0 ttcp/init.c | 173 ++++++++++ ttcp/rtems_ttcp.c | 294 ++++++++++++++++ ttcp/ttcp_orig/README | 27 ++ ttcp/ttcp_orig/ttcp.1 | 144 ++++++++ ttcp/ttcp_orig/ttcp.c | 841 +++++++++++++++++++++++++++++++++++++++++++++ 19 files changed, 2477 insertions(+) create mode 100644 netdemo/Makefile create mode 100644 netdemo/README create mode 100644 netdemo/init.c create mode 100644 netdemo/test.c create mode 100644 tftpTest/Makefile create mode 100644 tftpTest/init.c create mode 100644 tftpTest/test.c create mode 100644 ttcp/Makefile create mode 100644 ttcp/README create mode 100644 ttcp/include/arpa/inet.h create mode 100644 ttcp/include/netdb.h create mode 100644 ttcp/include/netinet/in.h create mode 100644 ttcp/include/netinet/tcp.h create mode 100644 ttcp/include/sys/socket.h create mode 100644 ttcp/init.c create mode 100644 ttcp/rtems_ttcp.c create mode 100644 ttcp/ttcp_orig/README create mode 100644 ttcp/ttcp_orig/ttcp.1 create mode 100644 ttcp/ttcp_orig/ttcp.c 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 + +#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 + +#include +#include + +/* + * 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 +#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 ") + || rtems_ka9q_execute_command ("trace rtems output ") + || rtems_ka9q_execute_command ("trace rtems ascii ")) + 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 + +/* + * 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 +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 +#include +#include +#include +#include +#include +#include + +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 + 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 diff --git a/ttcp/include/netdb.h b/ttcp/include/netdb.h new file mode 100644 index 0000000..e69de29 diff --git a/ttcp/include/netinet/in.h b/ttcp/include/netinet/in.h new file mode 100644 index 0000000..e69de29 diff --git a/ttcp/include/netinet/tcp.h b/ttcp/include/netinet/tcp.h new file mode 100644 index 0000000..e69de29 diff --git a/ttcp/include/sys/socket.h b/ttcp/include/sys/socket.h new file mode 100644 index 0000000..e69de29 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 + +#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 + +#include +#include + +/* + * 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 +#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 +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* struct timeval */ + +#if defined(SYSV) +#include +#include +struct rusage { + struct timeval ru_utime, ru_stime; +}; +#define RUSAGE_SELF 0 +#else +#include +#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); +} -- cgit v1.2.3