summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorJiaojinxing <jiaojinxing1987@gmail.com>2015-05-04 08:07:13 (GMT)
committer Jiaojinxing <jiaojinxing1987@gmail.com>2015-05-04 08:07:13 (GMT)
commit3f43705d78717c9f3af1f7a043c222045d2e350e (patch)
tree741472798d1171c5e82198096719719bae3f3892
parent57e8c5611542afdd35864c131f983890b9255fbc (diff)
downloadbspam335x-3f43705d78717c9f3af1f7a043c222045d2e350e.zip
bspam335x-3f43705d78717c9f3af1f7a043c222045d2e350e.tar.gz
bspam335x-3f43705d78717c9f3af1f7a043c222045d2e350e.tar.bz2
Added NETIO(Network Throughput Benchmark).
-rw-r--r--Makefile3
-rw-r--r--SylixOS/bsp/config.h5
-rw-r--r--SylixOS/driver/netif/am335x_cpsw.c2
-rw-r--r--SylixOS/driver/netif/cpswif.c64
-rw-r--r--SylixOS/driver/netif/netio/FILE_ID.DIZ8
-rw-r--r--SylixOS/driver/netif/netio/Makefile108
-rw-r--r--SylixOS/driver/netif/netio/bin/aix-ppc64bin0 -> 52326 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/freebsd-i386bin0 -> 18424 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/linux-i386bin0 -> 18388 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/linux-x86_64bin0 -> 19104 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/mac-osx-10.5.tar.gzbin0 -> 43510 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/os2-i386.exebin0 -> 63778 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/sol10-i386bin0 -> 17436 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/sol9-sparcbin0 -> 23040 bytes
-rw-r--r--SylixOS/driver/netif/netio/bin/win32-i386.exebin0 -> 19968 bytes
-rw-r--r--SylixOS/driver/netif/netio/getopt.c92
-rw-r--r--SylixOS/driver/netif/netio/getopt.h9
-rw-r--r--SylixOS/driver/netif/netio/netio.c1537
-rw-r--r--SylixOS/driver/netif/netio/netio.doc48
-rw-r--r--SylixOS/user/main.c3
20 files changed, 1854 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index d7f8bab..cfe46b8 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
# target -> bspam335x.elf
# bspam335x.bin
#*********************************************************************************************************
-SYLIXOS_BASE_PATH = D:\workspace_bsp\base_a8
+SYLIXOS_BASE_PATH = D:/workspace_bsp/base_a8
TOOLCHAIN_PREFIX = arm-sylixos-eabi-
#*********************************************************************************************************
@@ -127,6 +127,7 @@ SylixOS/driver/sdi/am335x_sdi.c \
SylixOS/driver/sdi/am335x_sdi_init.c \
SylixOS/driver/netif/cpswif.c \
SylixOS/driver/netif/am335x_cpsw.c \
+SylixOS/driver/netif/netio/netio.c \
SylixOS/driver/watchdog/am335x_watchdog.c \
SylixOS/driver/memory/memory_port.c \
SylixOS/driver/memory/elm/elm.c \
diff --git a/SylixOS/bsp/config.h b/SylixOS/bsp/config.h
index f96d19f..fa7f7b8 100644
--- a/SylixOS/bsp/config.h
+++ b/SylixOS/bsp/config.h
@@ -82,8 +82,11 @@
#define BSP_CFG_EN2_GATEWAY "192.168.2.1"
/*********************************************************************************************************
CPSW 驱动配置
+
+ 如果您的项目使用以太网极频繁地发送小包, 建议配置 BSP_CFG_CPSW_TX_DMA_PBUF 为 1, 否则建议配置为 0
*********************************************************************************************************/
-#define BSP_CFG_CPSW_TX_DMA_PBUF 1
+#define BSP_CFG_CPSW_TX_DMA_PBUF 0
+#define BSP_CFG_CPSW_CPPI_RAM_SIZE (80 * 1024)
/*********************************************************************************************************
开发板相关配置
*********************************************************************************************************/
diff --git a/SylixOS/driver/netif/am335x_cpsw.c b/SylixOS/driver/netif/am335x_cpsw.c
index 62a5c67..89a03a6 100644
--- a/SylixOS/driver/netif/am335x_cpsw.c
+++ b/SylixOS/driver/netif/am335x_cpsw.c
@@ -579,7 +579,7 @@ INT arm335xCpswInit (VOID)
goto __error_handle;
}
#else
- pCpswControler->CPSWC_stCpswCppiRamPhyAddrSize = 20 * 1024;
+ pCpswControler->CPSWC_stCpswCppiRamPhyAddrSize = BSP_CFG_CPSW_CPPI_RAM_SIZE;
pCpswControler->CPSWC_ulCpswCppiRamPhyAddrBase = (addr_t)
API_VmmDmaAllocAlign(pCpswControler->CPSWC_stCpswCppiRamPhyAddrSize, 8);
if (!pCpswControler->CPSWC_ulCpswCppiRamPhyAddrBase) {
diff --git a/SylixOS/driver/netif/cpswif.c b/SylixOS/driver/netif/cpswif.c
index b8aaeb5..7d685cc 100644
--- a/SylixOS/driver/netif/cpswif.c
+++ b/SylixOS/driver/netif/cpswif.c
@@ -238,6 +238,9 @@ struct rxch {
/* The number of free bd's, which can be allocated for reception */
volatile u32_t free_num;
+
+ volatile struct cpdma_rx_bd *first_rxbd;
+ volatile struct cpdma_rx_bd *end_rxbd;
}rxch;
/**
@@ -256,6 +259,9 @@ struct txch {
/* The number of free bd's, which can be sent */
volatile u32_t free_num;
+
+ volatile struct cpdma_tx_bd *first_txbd;
+ volatile struct cpdma_tx_bd *end_txbd;
}txch;
volatile struct cpdma_tx_bd *free_head;
@@ -1620,7 +1626,7 @@ static void
cpswif_rxbd_alloc(struct cpswinst *cpswinst) {
struct rxch *rxch = &(cpswinst->rxch);
struct pbuf *p;
- volatile struct cpdma_rx_bd *curr_bd, *last_bd, *recv_tail, *recv_head;
+ volatile struct cpdma_rx_bd *curr_bd, *last_bd = NULL, *recv_tail, *recv_head;
u32_t saved_free_num;
/* Start from the free head of the chain */
@@ -1630,7 +1636,6 @@ cpswif_rxbd_alloc(struct cpswinst *cpswinst) {
recv_head = rxch->free_head;
recv_tail = rxch->recv_tail;
saved_free_num = rxch->free_num;
- last_bd = rxch->recv_tail;
while(rxch->free_num) {
/**
@@ -1681,13 +1686,10 @@ cpswif_rxbd_alloc(struct cpswinst *cpswinst) {
* If the entire ring is traversed, curr_bd will be NULL. In that case,
* write the Rx HDP in order to continue reception
*/
- if(NULL != curr_bd) {
- rxch->free_head = curr_bd;
- } else {
- CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(recv_head), 0);
- }
+ rxch->free_head = curr_bd;
- recv_tail->next = recv_head;
+ if (recv_tail)
+ recv_tail->next = recv_head;
/* Close the ring to prevent overwriting of pbuf data */
last_bd->next = NULL;
@@ -1697,7 +1699,7 @@ cpswif_rxbd_alloc(struct cpswinst *cpswinst) {
* Pointer is already taken by the DMA engine. So we need to write the
* RX HDP with the next descriptor.
*/
- if(recv_tail->flags_pktlen & CPDMA_BUF_DESC_EOQ) {
+ if(recv_tail && (recv_tail->flags_pktlen & CPDMA_BUF_DESC_EOQ)) {
CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(recv_head), 0);
}
}
@@ -1762,7 +1764,7 @@ cpswif_transmit(struct netif *netif, struct pbuf *pbuf) {
* Make sure that the payload is written to memory. Clean
* the portion of cache to make it coherent with the memory.
*/
-#if defined(SYLIXOS) && (BSP_CFG_CPSW_TX_DMA_PBUF == 0)
+#if (BSP_CFG_CPSW_TX_DMA_PBUF == 0)
CacheDataCleanBuff((u32_t)(q->payload), (u32_t)(q->len));
#endif
#endif
@@ -2063,8 +2065,8 @@ cpswif_port_init(struct netif *netif) {
static void
cpswif_cpdma_init(struct cpswinst *cpswinst) {
u32_t num_bd;
- volatile struct cpdma_tx_bd *curr_txbd, *last_txbd;
- volatile struct cpdma_rx_bd *curr_rxbd, *last_rxbd;
+ volatile struct cpdma_tx_bd *curr_txbd, *last_txbd = NULL;
+ volatile struct cpdma_rx_bd *curr_rxbd, *last_rxbd = NULL;
struct txch *txch;
struct rxch *rxch;
@@ -2083,6 +2085,8 @@ cpswif_cpdma_init(struct cpswinst *cpswinst) {
curr_txbd = txch->free_head;
+ txch->first_txbd = txch->free_head;
+
/* Initialize all the TX buffer descriptors ring */
while(num_bd) {
curr_txbd->next = curr_txbd + 1;
@@ -2091,6 +2095,9 @@ cpswif_cpdma_init(struct cpswinst *cpswinst) {
curr_txbd = curr_txbd->next;
num_bd--;
}
+
+ txch->end_txbd = last_txbd->next;
+
last_txbd->next = txch->free_head;
/* Initialize the descriptors for the RX channel */
@@ -2104,6 +2111,8 @@ cpswif_cpdma_init(struct cpswinst *cpswinst) {
curr_rxbd = rxch->free_head;
+ rxch->first_rxbd = rxch->free_head;
+
/* Create the rx ring of buffer descriptors */
while(num_bd) {
curr_rxbd->next = curr_rxbd + 1;
@@ -2113,16 +2122,15 @@ cpswif_cpdma_init(struct cpswinst *cpswinst) {
num_bd--;
}
+ rxch->end_rxbd = last_rxbd->next;
+
last_rxbd->next = rxch->free_head;
/* We are going to receive starting from the free head */
rxch->recv_head = rxch->free_head;
- rxch->recv_tail = last_rxbd;
+ rxch->recv_tail = NULL;
cpswif_rxbd_alloc(cpswinst);
- /* close the ring */
- last_rxbd->next = NULL;
-
CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, (u32_t)(rxch->recv_head), 0);
}
@@ -2385,8 +2393,6 @@ cpswif_rx_inthandler(u32_t inst_num, struct netif * netif_arr) {
/* Acknowledge that this packet is processed */
CPSWCPDMARxCPWrite(cpswinst->cpdma_base, 0, (unsigned int)curr_bd);
- curr_bd = curr_bd->next;
-
/* One more buffer descriptor is free now */
rxch->free_num++;
@@ -2394,10 +2400,19 @@ cpswif_rx_inthandler(u32_t inst_num, struct netif * netif_arr) {
* If the DMA engine took the NULL pointer, we dont have any bd to
* process until new bd's are allocated.
*/
- if(curr_bd == NULL) {
+ if(curr_bd->next == NULL) {
+ curr_bd->next = curr_bd + 1;
+ if (curr_bd->next == rxch->end_rxbd) {
+ curr_bd->next = rxch->first_rxbd;
+ }
+
+ rxch->free_head = rxch->first_rxbd;
rxch->recv_head = rxch->free_head;
+ rxch->recv_tail = NULL;
break;
}
+
+ curr_bd = curr_bd->next;
rxch->recv_head = curr_bd;
}
@@ -2494,19 +2509,24 @@ cpswif_tx_inthandler(u32_t inst_num, struct netif * netif_arr) {
send_head->flags_pktlen &= ~(CPDMA_BUF_DESC_SOP);
curr_bd->flags_pktlen &= ~(CPDMA_BUF_DESC_EOP);
+ /* Acknowledge CPSW and free the corresponding pbuf */
+ CPSWCPDMATxCPWrite(cpswinst->cpdma_base, 0, (u32_t)curr_bd);
+
/**
* If there are no more data transmitted, the next interrupt
* shall happen with the pbuf associated with the free_head
*/
if(curr_bd->next == NULL) {
+ curr_bd->next = curr_bd + 1;
+ if (curr_bd->next == txch->end_txbd) {
+ curr_bd->next = txch->first_txbd;
+ }
+ txch->send_tail = NULL;
txch->send_head = txch->free_head;
} else {
txch->send_head = curr_bd->next;
}
- /* Acknowledge CPSW and free the corresponding pbuf */
- CPSWCPDMATxCPWrite(cpswinst->cpdma_base, 0, (u32_t)curr_bd);
-
#ifdef SYLIXOS
#ifdef CPSW_DUAL_MAC_MODE
if_num = (inst_num * MAX_SLAVEPORT_PER_INST) + to_port - 1;
diff --git a/SylixOS/driver/netif/netio/FILE_ID.DIZ b/SylixOS/driver/netif/netio/FILE_ID.DIZ
new file mode 100644
index 0000000..ca2143b
--- /dev/null
+++ b/SylixOS/driver/netif/netio/FILE_ID.DIZ
@@ -0,0 +1,8 @@
+NETIO - Network Benchmark, Version 1.32
+(C) 1997-2012 Kai Uwe Rommel
+
+This is a network benchmark for
+DOS, OS/2, Windows, Linux and Unix that
+measures net througput of a network
+with TCP and UDP protocols.
+
diff --git a/SylixOS/driver/netif/netio/Makefile b/SylixOS/driver/netif/netio/Makefile
new file mode 100644
index 0000000..ae79480
--- /dev/null
+++ b/SylixOS/driver/netif/netio/Makefile
@@ -0,0 +1,108 @@
+# Makefile for NETIO
+#
+# Author: Kai Uwe Rommel <rommel@ars.de>
+# Created: Wed Sep 25 1996
+#
+# $Id: Makefile,v 1.10 2010/10/14 13:03:35 Rommel Exp Rommel $
+# $Revision: 1.10 $
+#
+# $Log: Makefile,v $
+# Revision 1.10 2010/10/14 13:03:35 Rommel
+# removed NetBIOS code
+#
+# Revision 1.9 2005/08/30 14:45:58 Rommel
+# targets updated
+#
+# Revision 1.8 2003/08/17 16:59:22 Rommel
+# separated Unix and Linux targets
+#
+# Revision 1.7 2003/07/12 17:28:31 Rommel
+# switched to gcc for Win32
+#
+# Revision 1.6 2001/04/19 12:21:14 Rommel
+# added fixes for Unix systems
+#
+# Revision 1.5 1999/10/24 19:08:49 rommel
+# imported DOS support from G. Vanem <giva@bgnett.no>
+#
+# Revision: 1.5 1999/10/12 11:02:00 giva
+# added Watt-32 + djgpp support
+#
+# $Log: Makefile,v $
+# Revision 1.10 2010/10/14 13:03:35 Rommel
+# removed NetBIOS code
+#
+# Revision 1.9 2005/08/30 14:45:58 Rommel
+# targets updated
+#
+# Revision 1.8 2003/08/17 16:59:22 Rommel
+# separated Unix and Linux targets
+#
+# Revision 1.1 2003/08/17 16:58:28 Rommel
+# Initial revision
+#
+# Revision 1.7 2003/07/12 17:28:31 Rommel
+# switched to gcc for Win32
+#
+# Revision 1.6 2001/04/19 12:21:14 Rommel
+# added fixes for Unix systems
+#
+# Revision 1.5 1999/10/24 19:08:49 rommel
+# imported DOS support from G. Vanem <giva@bgnett.no>
+#
+# Revision 1.4 1999/06/13 18:53:42 rommel
+# added Linux port
+#
+# Revision 1.3 1998/10/12 11:14:58 rommel
+# change to malloc'ed (and tiled) memory for transfer buffers
+# (hint from Guenter Kukkukk <kukuk@berlin.snafu.de>)
+# for increased performance
+#
+# Revision 1.2 1998/07/31 14:16:06 rommel
+# *** empty log message ***
+#
+# Revision 1.1 1998/01/03 17:30:01 rommel
+# Initial revision
+#
+
+win32:
+ $(MAKE) all CC="gcc -O -s" O=.o X=.exe \
+ CFLAGS="-DWIN32" LFLAGS="" \
+ LIBS="-lwsock32 -lnetapi32" OUT=-o
+win32-debug:
+ $(MAKE) all CC="gcc -g" O=.o X=.exe \
+ CFLAGS="-DWIN32" LFLAGS="" \
+ LIBS="-lwsock32 -lnetapi32" OUT=-o
+os2:
+ $(MAKE) all CC="icc -q -Gm -Gt -O" O=.obj X=.exe \
+ CFLAGS="-DOS2 -Ic:/os2tk45/h/stack16" \
+ LFLAGS="/B/ST:0x100000" LIBS="tcp32dll.lib so32dll.lib" OUT=-Fe
+unix:
+ $(MAKE) all CC="gcc -O -s" O=.o X= \
+ CFLAGS="-DUNIX" LFLAGS="" LIBS="-lsocket -lpthread" OUT=-o
+solaris:
+ $(MAKE) all CC="gcc -O -s" O=.o X= \
+ CFLAGS="-DUNIX" LFLAGS="" LIBS="-lsocket -lpthread -lnsl" OUT=-o
+linux:
+ $(MAKE) all CC="gcc -O -s" O=.o X= \
+ CFLAGS="-DUNIX" LFLAGS="" LIBS="-lpthread" OUT=-o
+macosx:
+ $(MAKE) all CC="gcc -O" O=.o X= \
+ CFLAGS="-DUNIX -DSOCKLEN_T" LFLAGS="" LIBS="-lpthread" OUT=-o
+freebsd:
+ $(MAKE) all CC="gcc -O -s" O=.o X= \
+ CFLAGS="-DUNIX" LFLAGS="-L/usr/local/lib" LIBS="-lpthread" OUT=-o
+
+INC = -I.
+
+all: netio$X
+
+netio$X: netio$O getopt$O
+ $(CC) $(OUT) $@ netio$O getopt$O $(LFLAGS) $(LIBS)
+
+.SUFFIXES: .c $O
+.c$O:
+ $(CC) $(CFLAGS) $(INC) -c $*.c
+
+netio$O: netio.c getopt.h
+getopt$O: getopt.c getopt.h
diff --git a/SylixOS/driver/netif/netio/bin/aix-ppc64 b/SylixOS/driver/netif/netio/bin/aix-ppc64
new file mode 100644
index 0000000..cbf91eb
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/aix-ppc64
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/freebsd-i386 b/SylixOS/driver/netif/netio/bin/freebsd-i386
new file mode 100644
index 0000000..5362f25
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/freebsd-i386
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/linux-i386 b/SylixOS/driver/netif/netio/bin/linux-i386
new file mode 100644
index 0000000..dc241c1
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/linux-i386
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/linux-x86_64 b/SylixOS/driver/netif/netio/bin/linux-x86_64
new file mode 100644
index 0000000..e6d8e2a
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/linux-x86_64
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/mac-osx-10.5.tar.gz b/SylixOS/driver/netif/netio/bin/mac-osx-10.5.tar.gz
new file mode 100644
index 0000000..4fa7a83
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/mac-osx-10.5.tar.gz
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/os2-i386.exe b/SylixOS/driver/netif/netio/bin/os2-i386.exe
new file mode 100644
index 0000000..83c26dd
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/os2-i386.exe
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/sol10-i386 b/SylixOS/driver/netif/netio/bin/sol10-i386
new file mode 100644
index 0000000..9d5d34e
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/sol10-i386
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/sol9-sparc b/SylixOS/driver/netif/netio/bin/sol9-sparc
new file mode 100644
index 0000000..3c6cd3d
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/sol9-sparc
Binary files differ
diff --git a/SylixOS/driver/netif/netio/bin/win32-i386.exe b/SylixOS/driver/netif/netio/bin/win32-i386.exe
new file mode 100644
index 0000000..967a8a1
--- /dev/null
+++ b/SylixOS/driver/netif/netio/bin/win32-i386.exe
Binary files differ
diff --git a/SylixOS/driver/netif/netio/getopt.c b/SylixOS/driver/netif/netio/getopt.c
new file mode 100644
index 0000000..a24e116
--- /dev/null
+++ b/SylixOS/driver/netif/netio/getopt.c
@@ -0,0 +1,92 @@
+/*
+** @(#)getopt.c 2.5 (smail) 9/15/87
+*/
+
+#if !defined(UNIX) && !defined(DJGPP)
+
+#include <stdio.h>
+#include <io.h>
+#include <string.h>
+
+/*
+ * Here's something you've all been waiting for: the AT&T public domain
+ * source for getopt(3). It is the code which was given out at the 1985
+ * UNIFORUM conference in Dallas. I obtained it by electronic mail
+ * directly from AT&T. The people there assure me that it is indeed
+ * in the public domain.
+ *
+ * There is no manual page. That is because the one they gave out at
+ * UNIFORUM was slightly different from the current System V Release 2
+ * manual page. The difference apparently involved a note about the
+ * famous rules 5 and 6, recommending using white space between an option
+ * and its first argument, and not grouping options that have arguments.
+ * Getopt itself is currently lenient about both of these things. White
+ * space is allowed, but not mandatory, and the last option in a group can
+ * have an argument. That particular version of the man page evidently
+ * has no official existence, and my source at AT&T did not send a copy.
+ * The current SVR2 man page reflects the actual behavor of this getopt.
+ * However, I am not about to post a copy of anything licensed by AT&T.
+ */
+
+#define ERR(s, c)\
+ if(opterr){\
+ char errbuf[2];\
+ errbuf[0] = (char)c; errbuf[1] = '\n';\
+ (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
+ (void) write(2, s, (unsigned)strlen(s));\
+ (void) write(2, errbuf, 2);\
+ }
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+int
+getopt(argc, argv, opts)
+int argc;
+char **argv, *opts;
+{
+ static int sp = 1;
+ register int c;
+ register char *cp;
+
+ if(sp == 1)
+ if(optind >= argc ||
+ argv[optind][0] != '-' /* && argv[optind][0] != '/' */ ||
+ argv[optind][1] == '\0')
+ return(EOF);
+ else if(strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return(EOF);
+ }
+ optopt = c = argv[optind][sp];
+ if(c == ':' || (cp=strchr(opts, c)) == 0) {
+ ERR(": illegal option -- ", c);
+ if(argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return('?');
+ }
+ if(*++cp == ':') {
+ if(argv[optind][sp+1] != '\0')
+ optarg = &argv[optind++][sp+1];
+ else if(++optind >= argc) {
+ ERR(": option requires an argument -- ", c);
+ sp = 1;
+ return('?');
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if(argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return(c);
+}
+
+#endif /* !UNIX && !DJGPP */
diff --git a/SylixOS/driver/netif/netio/getopt.h b/SylixOS/driver/netif/netio/getopt.h
new file mode 100644
index 0000000..1358e9b
--- /dev/null
+++ b/SylixOS/driver/netif/netio/getopt.h
@@ -0,0 +1,9 @@
+/* declarations for getopt and envargs */
+
+extern int opterr;
+extern int optind;
+extern int optopt;
+extern char *optarg;
+
+extern int getopt(int argc, char **argv, char *opts);
+extern void envargs(int *pargc, char ***pargv, char *envstr);
diff --git a/SylixOS/driver/netif/netio/netio.c b/SylixOS/driver/netif/netio/netio.c
new file mode 100644
index 0000000..b55cc9b
--- /dev/null
+++ b/SylixOS/driver/netif/netio/netio.c
@@ -0,0 +1,1537 @@
+/* netio.c
+ *
+ * Author: Kai-Uwe Rommel <rommel@ars.de>
+ * Created: Wed Sep 25 1996
+ */
+
+#ifdef SYLIXOS
+#define UNIX
+#define StartTimer __StartTimer
+#define StopTimer __StopTimer
+#define main netio_main
+
+/*
+ * Usage:
+ *
+ * sylixos: netio -s &
+ *
+ * pc: win32-i386.exe -t 192.168.1.11
+ * win32-i386.exe -u 192.168.1.11
+ */
+#endif
+
+static char *rcsid =
+"$Id: netio.c,v 1.32 2012/11/22 16:47:24 Rommel Exp Rommel $";
+static char *rcsrev = "$Revision: 1.32 $";
+
+/*
+ * $Log: netio.c,v $
+ * Revision 1.32 2012/11/22 16:47:24 Rommel
+ * added binding to client sockets, too
+ *
+ * Revision 1.31 2010/10/14 16:44:38 Rommel
+ * fixed sleep calls
+ *
+ * Revision 1.30 2010/10/14 14:32:41 Rommel
+ * removed NetBIOS code
+ * added server side result printing
+ * fixed packet loss calculation (data type bug)
+ *
+ * Revision 1.29 2010/10/14 11:28:19 Rommel
+ * central printing routine
+ *
+ * Revision 1.28 2009/09/07 14:09:39 Rommel
+ * changed number output from bytes/KB to bytes/KB/MB
+ *
+ * Revision 1.27 2008/02/11 09:00:22 Rommel
+ * re-randomize buffer data for each loop run
+ *
+ * Revision 1.26 2005/08/30 14:45:51 Rommel
+ * minor fixes
+ *
+ * Revision 1.25 2004/05/26 07:23:04 Rommel
+ * some more corrections from Oliver Lau and Frank Schnell
+ *
+ * Revision 1.24 2004/05/17 16:01:03 Rommel
+ * fix for _send/_recv from Thomas Jahns
+ *
+ * Revision 1.23 2003/09/30 09:32:22 Rommel
+ * corrections from Matthias Scheler for error handling
+ * added socket buffer size setting
+ * added htonl/ntohl code (hint from Oliver Lau)
+ * restructured send/recv error/result checking
+ * more verbose server side messages
+ * other minor changes
+ *
+ * Revision 1.22 2003/09/22 14:58:33 Rommel
+ * added server side progress messages
+ *
+ * Revision 1.21 2003/08/28 12:44:11 Rommel
+ * fixed display of non-k-multiple packet sizes
+ *
+ * Revision 1.20 2003/08/27 11:05:48 Rommel
+ * allow block size specifikation in bytes or k bytes
+ *
+ * Revision 1.19 2003/08/17 16:53:45 Rommel
+ * added Unix/Linux pthreads support (required for UDP)
+ *
+ * Revision 1.18 2003/08/17 14:46:17 Rommel
+ * added UDP benchmark
+ * several minor changes (cleanup)
+ * configurable binding address
+ *
+ * Revision 1.17 2003/07/12 17:25:00 Rommel
+ * made block size selectable
+ *
+ * Revision 1.16 2003/02/10 09:06:59 Rommel
+ * fixed sender algorithm
+ *
+ * Revision 1.15 2001/09/17 13:56:40 Rommel
+ * changed to perform bidirectional benchmarks
+ *
+ * Revision 1.14 2001/04/19 12:20:55 Rommel
+ * added fixes for Unix systems
+ *
+ * Revision 1.13 2001/03/26 11:37:41 Rommel
+ * avoid integer overflows during throughput calculation
+ *
+ * Revision 1.12 2000/12/01 15:57:57 Rommel
+ * *** empty log message ***
+ *
+ * Revision 1.11 2000/03/01 12:21:47 rommel
+ * fixed _INTEGRAL_MAX_BITS problem for WIN32
+ *
+ * Revision 1.10 1999/10/28 17:36:57 rommel
+ * fixed OS/2 timer code
+ *
+ * Revision 1.9 1999/10/28 17:04:12 rommel
+ * fixed timer code
+ *
+ * Revision 1.8 1999/10/24 19:08:20 rommel
+ * imported DOS support from G. Vanem <giva@bgnett.no>
+ *
+ *
+ * Revision 1.8 1999/10/12 11:02:00 giva
+ * added Watt-32 with djgpp support. Added debug mode.
+ * G. Vanem <giva@bgnett.no>
+ *
+ * Revision 1.7 1999/06/13 18:42:25 rommel
+ * added Linux port with patches from Detlef Plotzky <plo@bvu.de>
+ *
+ * Revision 1.6 1998/10/12 11:14:58 rommel
+ * change to malloc'ed (and tiled) memory for transfer buffers
+ * (hint from Guenter Kukkukk <kukuk@berlin.snafu.de>)
+ * for increased performance
+ *
+ * Revision 1.5 1998/07/31 14:15:03 rommel
+ * added random buffer data
+ * fixed bugs
+ *
+ * Revision 1.4 1997/09/12 17:35:04 rommel
+ * termination bug fixes
+ *
+ * Revision 1.3 1997/09/12 12:00:15 rommel
+ * added Win32 port
+ * (tested for Windows NT only)
+ *
+ * Revision 1.2 1997/09/12 10:44:22 rommel
+ * added TCP/IP and a command line interface
+ *
+ * Revision 1.1 1996/09/25 08:42:29 rommel
+ * Initial revision
+ *
+ */
+
+#ifdef WIN32
+#define _INTEGRAL_MAX_BITS 64
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#if defined(UNIX) || defined(DJGPP)
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+#else
+#include <process.h>
+#include "getopt.h"
+#endif
+
+#define DEFAULTPORT 0x494F /* "IO" */
+#define DEFAULTNBSRV "NETIOSRV"
+#define DEFAULTNBCLT "NETIOCLT"
+#define THREADSTACK 65536
+
+/* TCP/IP system specific details */
+
+#ifdef OS2
+
+#define BSD_SELECT
+#include <types.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#ifdef __IBMC__
+#define newthread(entry) (_beginthread(entry, 0, THREADSTACK, 0) == -1)
+#else
+#define newthread(entry) (_beginthread(entry, THREADSTACK, 0) == -1)
+#endif
+#define THREAD void
+#define THREADRESULT
+
+#endif /* OS2 */
+
+#ifdef WATT32
+
+#include <tcp.h> /* sock_init() etc. */
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#define soclose close_s
+#define select select_s
+#define psock_errno perror
+
+#endif /* WATT32 */
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <winsock.h>
+#define soclose closesocket
+
+int sock_init(void)
+{
+ WSADATA wsaData;
+ return WSAStartup(MAKEWORD(1, 1), &wsaData);
+}
+
+void psock_errno(char *text)
+{
+ int rc = WSAGetLastError();
+ printf("%s: error code %d\n", text, rc);
+}
+
+#ifdef __IBMC__
+#define newthread(entry) (_beginthread(entry, 0, THREADSTACK, 0) == -1)
+#else
+#define newthread(entry) (_beginthread(entry, THREADSTACK, 0) == -1)
+#endif
+#define THREAD void
+#define THREADRESULT
+
+#endif /* WIN32 */
+
+#ifdef UNIX
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#define psock_errno(x) perror(x)
+#define soclose(x) close(x)
+
+int sock_init(void)
+{
+ return 0;
+}
+
+#include <pthread.h>
+pthread_t thread;
+#define newthread(entry) (pthread_create(&thread, 0, entry, 0) != 0)
+#define THREAD void*
+#define THREADRESULT ((void*)0)
+
+#endif /* UNIX */
+
+#ifdef SOCKLEN_T
+typedef socklen_t socklen_type;
+#else
+typedef size_t socklen_type;
+#endif
+
+/* global data */
+
+#ifndef max
+#define max(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#ifndef min
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef EINTR
+#define EINTR 0
+#endif
+
+int nSizes[] = {1024, 2048, 4096, 8192, 16384, 32768};
+size_t nnSizes = sizeof(nSizes) / sizeof(int);
+#define NMAXSIZE 65536
+
+int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767};
+size_t ntSizes = sizeof(tSizes) / sizeof(int);
+#define TMAXSIZE 65536
+
+#define INTERVAL 6
+
+/* you may need to adapt this to your platform/compiler */
+typedef unsigned int uint32;
+
+typedef struct
+{
+ uint32 cmd;
+ uint32 data;
+}
+CONTROL;
+
+#define CMD_QUIT 0
+#define CMD_C2S 1
+#define CMD_S2C 2
+#define CMD_RES 3
+
+#define CTLSIZE sizeof(CONTROL)
+
+/* timer code */
+
+int bTimeOver;
+
+#ifdef OS2
+
+#define INCL_DOS
+#define INCL_NOPM
+#include <os2.h>
+
+typedef QWORD TIMER;
+
+void APIENTRY TimerThread(ULONG nSeconds)
+{
+ HEV hSem;
+ HTIMER hTimer;
+
+ DosCreateEventSem(0, &hSem, DC_SEM_SHARED, 0);
+
+ DosAsyncTimer(nSeconds * 1000, (HSEM) hSem, &hTimer);
+ DosWaitEventSem(hSem, SEM_INDEFINITE_WAIT);
+ DosStopTimer(hTimer);
+
+ DosCloseEventSem(hSem);
+
+ bTimeOver = 1;
+
+ DosExit(EXIT_THREAD, 0);
+}
+
+int StartAlarm(long nSeconds)
+{
+ TID ttid;
+
+ bTimeOver = 0;
+
+ if (DosCreateThread(&ttid, TimerThread, nSeconds, 0, THREADSTACK))
+ return printf("Cannot create timer thread.\n"), -1;
+
+ return 0;
+}
+
+int StartTimer(TIMER *nStart)
+{
+ if (DosTmrQueryTime(nStart))
+ return printf("Timer error.\n"), -1;
+
+ return 0;
+}
+
+long StopTimer(TIMER *nStart, int nAccuracy)
+{
+ TIMER nStop;
+ ULONG nFreq;
+
+ if (DosTmrQueryTime(&nStop))
+ return printf("Timer error.\n"), -1;
+ if (DosTmrQueryFreq(&nFreq))
+ return printf("Timer error.\n"), -1;
+
+ nFreq = (nFreq + nAccuracy / 2) / nAccuracy;
+
+ return (* (long long *) &nStop - * (long long *) nStart) / nFreq;
+}
+
+#endif /* OS2 */
+
+#ifdef WIN32
+
+typedef LARGE_INTEGER TIMER;
+
+#define sleep(x) Sleep((x) * 1000);
+
+DWORD CALLBACK TimerThread(void *pArg)
+{
+ long nSeconds = * (long *) pArg;
+
+ Sleep(nSeconds * 1000);
+ bTimeOver = 1;
+
+ return 0;
+}
+
+int StartAlarm(long nSeconds)
+{
+ static long sSeconds;
+ DWORD ttid;
+
+ sSeconds = nSeconds;
+
+ bTimeOver = 0;
+
+ if (CreateThread(0, THREADSTACK, TimerThread, (void *) &sSeconds, 0, &ttid) == NULL)
+ return printf("Cannot create timer thread.\n"), -1;
+
+ return 0;
+}
+
+int StartTimer(TIMER *nStart)
+{
+ if (!QueryPerformanceCounter(nStart))
+ return printf("Timer error.\n"), -1;
+
+ return 0;
+}
+
+long StopTimer(TIMER *nStart, int nAccuracy)
+{
+ TIMER nStop, nFreq;
+
+ if (!QueryPerformanceCounter(&nStop))
+ return printf("Timer error.\n"), -1;
+ if (!QueryPerformanceFrequency(&nFreq))
+ return printf("Timer error.\n"), -1;
+
+ nFreq.QuadPart = (nFreq.QuadPart + nAccuracy / 2) / nAccuracy;
+
+ return (nStop.QuadPart - nStart->QuadPart) / nFreq.QuadPart;
+}
+
+#endif /* WIN32 */
+
+#if defined(UNIX) || defined(DJGPP)
+
+typedef struct timeval TIMER;
+
+void on_alarm(int signum)
+{
+ alarm(0);
+ bTimeOver = 1;
+}
+
+#if defined(SYLIXOS)
+static pthread_t alarm_thread;
+
+static void *alarm_thread_func(void *arg)
+{
+ sleep((long)arg);
+ bTimeOver = 1;
+
+ return NULL;
+}
+#endif
+
+int StartAlarm(long nSeconds)
+{
+ bTimeOver = 0;
+#if defined(SYLIXOS)
+ pthread_create(&alarm_thread, 0, alarm_thread_func, (void *)nSeconds);
+#else
+ signal(SIGALRM, on_alarm);
+ alarm(nSeconds);
+#endif
+ return 0;
+}
+
+int StartTimer(TIMER *nStart)
+{
+ struct timezone tz = {0, 0};
+
+ gettimeofday(nStart, &tz);
+
+ return 0;
+}
+
+long StopTimer(TIMER *nStart, int nAccuracy)
+{
+ struct timezone tz = {0, 0};
+ TIMER nStop;
+
+ gettimeofday(&nStop, &tz);
+
+ return (nStop.tv_sec - nStart->tv_sec) * nAccuracy
+ + (nStop.tv_usec - nStart->tv_usec) * nAccuracy / 1000000;
+}
+
+#endif /* UNIX || DJGPP */
+
+/* initialize data to transfer */
+
+void GenerateRandomData(char *cBuffer, size_t nSize)
+{
+ if (cBuffer != NULL)
+ {
+ size_t i;
+
+ cBuffer[0] = 0;
+ srand(time(NULL));
+
+ for (i = 1; i < nSize; i++)
+ cBuffer[i] = (char) rand();
+ }
+}
+
+char *InitBuffer(size_t nSize)
+{
+ char *cBuffer = malloc(nSize);
+ GenerateRandomData(cBuffer, nSize);
+ return cBuffer;
+}
+
+char *PacketSize(int nSize)
+{
+ static char szBuffer[64];
+
+ if ((nSize % 1024) == 0 || (nSize % 1024) == 1023)
+ sprintf(szBuffer, "%2dk", (nSize + 512) / 1024);
+ else
+ sprintf(szBuffer, "%d", nSize);
+
+ return szBuffer;
+}
+
+/* print results */
+
+typedef enum {nf_auto, nf_bytes, nf_kbytes, nf_mbytes, nf_gbytes} numberformat;
+numberformat nFormat = nf_auto;
+
+void print_result(long long nData, long nTime)
+{
+ numberformat nThisFormat = nFormat;
+ double nResult;
+
+ if (nThisFormat == nf_auto)
+ {
+ if (nData < 10 * 1024 * INTERVAL)
+ nThisFormat = nf_bytes;
+ else if (nData < 10 * 1024 * 1024 * INTERVAL)
+ nThisFormat = nf_kbytes;
+ else if (nData < (long long) 1024 * 1024 * 1024 * INTERVAL)
+ nThisFormat = nf_mbytes;
+ else
+ nThisFormat = nf_gbytes;
+ }
+
+ switch(nThisFormat)
+ {
+ case nf_bytes:
+ nResult = (double) nData * 1024 / nTime;
+ printf(" %0.0f Byte/s", nResult);
+ break;
+
+ case nf_kbytes:
+ nResult = (double) nData / nTime;
+ printf(" %0.2f KByte/s", nResult);
+ break;
+
+ case nf_mbytes:
+ nResult = (double) nData / nTime / 1024;
+ printf(" %0.2f MByte/s", nResult);
+ break;
+
+ case nf_gbytes:
+ nResult = (double) nData / nTime / 1024 / 1024;
+ printf(" %0.3f GByte/s", nResult);
+ break;
+ }
+}
+
+/* TCP/IP code */
+
+int send_data(int socket, void *buffer, size_t size, int flags)
+{
+ int rc = send(socket, buffer, size, flags);
+
+ if (rc < 0)
+ {
+ psock_errno("send()");
+ return -1;
+ }
+
+ if (rc != size)
+ return 1;
+
+ return 0;
+}
+
+int recv_data(int socket, void *buffer, size_t size, int flags)
+{
+ size_t rc = recv(socket, buffer, size, flags);
+
+ if (rc < 0)
+ {
+ psock_errno("recv()");
+ return -1;
+ }
+
+ if (rc != size)
+ return 1;
+
+ return 0;
+}
+
+const int sobufsize = 131072;
+int nPort = DEFAULTPORT;
+int nAuxPort = DEFAULTPORT + 1;
+struct in_addr addr_server;
+struct in_addr addr_local;
+
+int udpsocket, udpd;
+unsigned long nUDPCount;
+long long nUDPData;
+
+THREAD TCP_Server(void *arg)
+{
+ char *cBuffer;
+ CONTROL ctl;
+ TIMER nTimer;
+ long nTime;
+ long long nData;
+ struct sockaddr_in sa_server, sa_client;
+ int server, client;
+ socklen_type length;
+ struct timeval tv;
+ fd_set fds;
+ int rc;
+ int nByte;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return THREADRESULT;
+ }
+
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ psock_errno("socket()");
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nPort);
+ sa_server.sin_addr = addr_local;
+
+ if (bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
+ {
+ psock_errno("bind()");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ if (listen(server, 2) != 0)
+ {
+ psock_errno("listen()");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ for (;;)
+ {
+ printf("TCP server listening.\n");
+
+ FD_ZERO(&fds);
+ FD_SET(server, &fds);
+ tv.tv_sec = 3600;
+ tv.tv_usec = 0;
+
+ if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
+ {
+ psock_errno("select()");
+ break;
+ }
+
+ if (rc == 0 || FD_ISSET(server, &fds) == 0)
+ continue;
+
+ length = sizeof(sa_client);
+ if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) == -1)
+ continue;
+
+ setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ printf("TCP connection established ... ");
+ fflush(stdout);
+
+ for (;;)
+ {
+ if (recv_data(client, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ ctl.cmd = ntohl(ctl.cmd);
+ ctl.data = ntohl(ctl.data);
+
+ if (ctl.cmd == CMD_C2S)
+ {
+ StartTimer(&nTimer);
+
+ printf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data));
+ nData = 0;
+
+ do
+ {
+ for (nByte = 0; nByte < ctl.data; )
+ {
+ rc = recv(client, cBuffer + nByte, ctl.data - nByte, 0);
+
+ if (rc < 0 && errno != EINTR)
+ {
+ psock_errno("recv()");
+ break;
+ }
+
+ if (rc > 0)
+ nByte += rc;
+ }
+
+ nData += ctl.data;
+ }
+ while (cBuffer[0] == 0 && rc > 0);
+
+ if ((nTime = StopTimer(&nTimer, 1024)) != -1)
+ print_result(nData, nTime);
+ }
+ else if (ctl.cmd == CMD_S2C)
+ {
+ if (StartAlarm(INTERVAL) == 0)
+ {
+ StartTimer(&nTimer);
+
+ printf("\nSending to client, packet size %s ... ", PacketSize(ctl.data));
+ cBuffer[0] = 0;
+ nData = 0;
+
+ while (!bTimeOver)
+ {
+ //GenerateRandomData(cBuffer, ctl.data);
+
+ for (nByte = 0; nByte < ctl.data; )
+ {
+ rc = send(client, cBuffer + nByte, ctl.data - nByte, 0);
+
+ if (rc < 0 && errno != EINTR)
+ {
+ psock_errno("send()");
+ break;
+ }
+
+ if (rc > 0)
+ nByte += rc;
+ }
+
+ nData += ctl.data;
+ }
+
+ cBuffer[0] = 1;
+
+ if (send_data(client, cBuffer, ctl.data, 0))
+ break;
+
+ if ((nTime = StopTimer(&nTimer, 1024)) != -1)
+ print_result(nData, nTime);
+ }
+ }
+ else /* quit */
+ break;
+ }
+
+ printf("\nDone.\n");
+
+ soclose(client);
+
+ if (rc < 0)
+ break;
+ }
+
+ soclose(server);
+ free(cBuffer);
+
+ return THREADRESULT;
+}
+
+void TCP_Bench(void *arg)
+{
+ char *cBuffer;
+ CONTROL ctl;
+ TIMER nTimer;
+ long nTime;
+ long long nData;
+ int i;
+ struct sockaddr_in sa_server, sa_client;
+ int server;
+ int rc;
+ int nByte;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return;
+ }
+
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ psock_errno("socket()");
+ free(cBuffer);
+ return;
+ }
+
+ setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ sa_client.sin_family = AF_INET;
+ sa_client.sin_port = htons(0);
+ sa_client.sin_addr = addr_local;
+
+ if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
+ {
+ psock_errno("bind()");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nPort);
+ sa_server.sin_addr = addr_server;
+
+ if (connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
+ {
+ psock_errno("connect()");
+ soclose(server);
+ free(cBuffer);
+ return;
+ }
+
+ printf("\nTCP connection established.\n");
+
+ for (i = 0; i < ntSizes; i++)
+ {
+ printf("Packet size %s bytes: ", PacketSize(tSizes[i]));
+ fflush(stdout);
+
+ /* tell the server we will send it data now */
+
+ ctl.cmd = htonl(CMD_C2S);
+ ctl.data = htonl(tSizes[i]);
+
+ if (send_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ /* 1 - Tx test */
+
+ if (StartAlarm(INTERVAL) == 0)
+ {
+ StartTimer(&nTimer);
+ nData = 0;
+ cBuffer[0] = 0;
+
+ while (!bTimeOver)
+ {
+ //GenerateRandomData(cBuffer, tSizes[i]);
+
+ for (nByte = 0; nByte < tSizes[i]; )
+ {
+ rc = send(server, cBuffer + nByte, tSizes[i] - nByte, 0);
+
+ if (rc < 0 && errno != EINTR)
+ {
+ psock_errno("send()");
+ break;
+ }
+
+ if (rc > 0)
+ nByte += rc;
+ }
+
+ nData += tSizes[i];
+ }
+
+ if ((nTime = StopTimer(&nTimer, 1024)) == -1)
+ printf(" (failed)");
+ else
+ print_result(nData, nTime);
+
+ printf(" Tx, ");
+ fflush(stdout);
+
+ cBuffer[0] = 1;
+
+ if (send_data(server, cBuffer, tSizes[i], 0))
+ break;
+ }
+
+ /* tell the server we expect him to send us data now */
+
+ ctl.cmd = htonl(CMD_S2C);
+ ctl.data = htonl(tSizes[i]);
+
+ if (send_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ /* 2 - Rx test */
+
+ StartTimer(&nTimer);
+ nData = 0;
+
+ do
+ {
+ for (nByte = 0; nByte < tSizes[i]; )
+ {
+ rc = recv(server, cBuffer + nByte, tSizes[i] - nByte, 0);
+
+ if (rc < 0 && errno != EINTR)
+ {
+ psock_errno("recv()");
+ break;
+ }
+
+ if (rc > 0)
+ nByte += rc;
+ }
+
+ nData += tSizes[i];
+ }
+ while (cBuffer[0] == 0 && rc > 0);
+
+ if ((nTime = StopTimer(&nTimer, 1024)) == -1)
+ printf(" (failed)");
+ else
+ print_result(nData, nTime);
+
+ printf(" Rx.\n");
+ }
+
+ ctl.cmd = htonl(CMD_QUIT);
+ ctl.data = 0;
+
+ send_data(server, (void *) &ctl, CTLSIZE, 0);
+
+ printf("Done.\n");
+
+ soclose(server);
+ free(cBuffer);
+}
+
+THREAD UDP_Receiver(void *arg)
+{
+ char *cBuffer;
+ struct sockaddr_in sa_server, sa_client;
+ int rc;
+ socklen_type nBytes;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return THREADRESULT;
+ }
+
+ if ((udpsocket = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ psock_errno("socket(DGRAM)");
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ setsockopt(udpsocket, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(udpsocket, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_local;
+
+ if (bind(udpsocket, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
+ {
+ psock_errno("bind(DGRAM)");
+ soclose(udpsocket);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ udpd = 1;
+
+ for (;;)
+ {
+ nBytes = sizeof(sa_client);
+ rc = recvfrom(udpsocket, cBuffer, TMAXSIZE, 0, (struct sockaddr *) &sa_client, &nBytes);
+
+ if (rc < 0 && errno != EINTR)
+ psock_errno("recvfrom()");
+
+ if (rc > 0)
+ {
+ nUDPCount++;
+ nUDPData += rc;
+ }
+ }
+
+ soclose(udpsocket);
+ free(cBuffer);
+
+ return THREADRESULT;
+}
+
+THREAD UDP_Server(void *arg)
+{
+ char *cBuffer;
+ CONTROL ctl;
+ TIMER nTimer;
+ long nTime;
+ long long nData;
+ struct sockaddr_in sa_server, sa_client;
+ int server, client;
+ struct timeval tv;
+ fd_set fds;
+ int rc, nByte;
+ socklen_type nLength;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return THREADRESULT;
+ }
+
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ psock_errno("socket(STREAM)");
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_local;
+
+ if (bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
+ {
+ psock_errno("bind(STREAM)");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ if (listen(server, 2) != 0)
+ {
+ psock_errno("listen()");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ for (;;)
+ {
+ printf("UDP server listening.\n");
+
+ FD_ZERO(&fds);
+ FD_SET(server, &fds);
+ tv.tv_sec = 3600;
+ tv.tv_usec = 0;
+
+ if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
+ {
+ psock_errno("select()");
+ break;
+ }
+
+ if (rc == 0 || FD_ISSET(server, &fds) == 0)
+ continue;
+
+ nLength = sizeof(sa_client);
+ if ((client = accept(server, (struct sockaddr *) &sa_client, &nLength)) == -1)
+ continue;
+
+ setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ printf("UDP connection established ... ");
+ fflush(stdout);
+
+ sa_client.sin_port = htons(nAuxPort);
+
+ for (;;)
+ {
+ if (recv_data(client, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ ctl.cmd = ntohl(ctl.cmd);
+ ctl.data = ntohl(ctl.data);
+
+ if (ctl.cmd == CMD_C2S)
+ {
+ StartTimer(&nTimer);
+ nUDPCount = 0;
+ nUDPData = 0;
+
+ printf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data));
+
+ ctl.cmd = htonl(ctl.cmd);
+ ctl.data = htonl(ctl.data);
+
+ if (send_data(client, (void *) &ctl, CTLSIZE, 0))
+ break;
+ }
+ else if (ctl.cmd == CMD_RES)
+ {
+ ctl.cmd = htonl(ctl.cmd);
+ ctl.data = htonl(nUDPCount);
+
+ if (send_data(client, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ if ((nTime = StopTimer(&nTimer, 1024)) != -1)
+ print_result(nUDPData, nTime);
+ }
+ else if (ctl.cmd == CMD_S2C)
+ {
+ if (StartAlarm(INTERVAL) == 0)
+ {
+ StartTimer(&nTimer);
+ nData = 0;
+
+ printf("\nSending to client, packet size %s ... ", PacketSize(ctl.data));
+ cBuffer[0] = 0;
+ nLength = ctl.data;
+
+ ctl.cmd = htonl(CMD_RES);
+ ctl.data = 0;
+
+ while (!bTimeOver)
+ {
+ //GenerateRandomData(cBuffer, nLength);
+
+ for (nByte = 0; nByte < nLength; )
+ {
+ do
+ {
+ rc = sendto(udpsocket, cBuffer + nByte, nLength - nByte, 0,
+ (struct sockaddr *) &sa_client, sizeof(sa_client));
+ }
+#ifdef ENOBUFS
+ while (rc < 0 && errno == ENOBUFS);
+#else
+ while (0);
+#endif
+
+ if (rc < 0 && errno != EINTR)
+ {
+ psock_errno("sendto()");
+ break;
+ }
+
+ if (rc > 0)
+ nByte += rc;
+ }
+
+ ctl.data++;
+ nData += nLength;
+ }
+
+ ctl.data = htonl(ctl.data);
+
+ if (send_data(client, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ if ((nTime = StopTimer(&nTimer, 1024)) != -1)
+ print_result(nData, nTime);
+ }
+ }
+ else /* quit */
+ break;
+ }
+
+ printf("\nDone.\n");
+
+ soclose(client);
+
+ if (rc < 0)
+ break;
+ }
+
+ soclose(server);
+ free(cBuffer);
+
+ return THREADRESULT;
+}
+
+void UDP_Bench(void *arg)
+{
+ char *cBuffer;
+ CONTROL ctl;
+ TIMER nTimer;
+ long nTime, nCount;
+ long nResult;
+ long long nData;
+ int i;
+ struct sockaddr_in sa_server, sa_client;
+ int server;
+ int rc, nByte;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return;
+ }
+
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ psock_errno("socket()");
+ free(cBuffer);
+ return;
+ }
+
+ setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
+ setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
+
+ sa_client.sin_family = AF_INET;
+ sa_client.sin_port = htons(0);
+ sa_client.sin_addr = addr_local;
+
+ if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
+ {
+ psock_errno("bind(STREAM)");
+ soclose(server);
+ free(cBuffer);
+ return THREADRESULT;
+ }
+
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_server;
+
+ if (connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
+ {
+ psock_errno("connect()");
+ soclose(server);
+ free(cBuffer);
+ return;
+ }
+
+ printf("\nUDP connection established.\n");
+
+ for (i = 0; i < ntSizes; i++)
+ {
+ printf("Packet size %s bytes: ", PacketSize(tSizes[i]));
+ fflush(stdout);
+
+ /* tell the server we will send it data now */
+
+ ctl.cmd = htonl(CMD_C2S);
+ ctl.data = htonl(tSizes[i]);
+
+ if (send_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ /* 1 - Tx test */
+
+ if (StartAlarm(INTERVAL) == 0)
+ {
+ StartTimer(&nTimer);
+ nData = 0;
+ nCount = 0;
+ cBuffer[0] = 0;
+
+ while (!bTimeOver)
+ {
+ //GenerateRandomData(cBuffer, tSizes[i]);
+
+ for (nByte = 0; nByte < tSizes[i]; )
+ {
+ rc = sendto(udpsocket, cBuffer + nByte, tSizes[i] - nByte, 0,
+ (struct sockaddr *) &sa_server, sizeof(sa_server));
+
+ if (rc < 0)
+ {
+ if (errno != EINTR)
+ {
+ psock_errno("sendto()");
+ break;
+ }
+ }
+ else
+ nByte += rc;
+ }
+
+ nData += tSizes[i];
+ nCount++;
+ }
+
+ if ((nTime = StopTimer(&nTimer, 1024)) == -1)
+ printf(" (failed)");
+
+ ctl.cmd = htonl(CMD_RES);
+
+ if (send_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ ctl.data = ntohl(ctl.data);
+ nData = (long long) tSizes[i] * ctl.data;
+
+ print_result(nData, nTime);
+ nResult = (nCount - ctl.data) * 100 / nCount;
+ printf(" (%ld%%) Tx, ", nResult);
+ fflush(stdout);
+ }
+
+ /* tell the server we expect him to send us data now */
+
+ ctl.cmd = htonl(CMD_S2C);
+ ctl.data = htonl(tSizes[i]);
+
+ if (send_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ /* 2 - Rx test */
+
+ StartTimer(&nTimer);
+ nUDPCount = 0;
+ nUDPData = 0;
+
+ if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
+ break;
+
+ if ((nTime = StopTimer(&nTimer, 1024)) == -1)
+ printf(" (failed)");
+
+ ctl.data = ntohl(ctl.data);
+
+ print_result(nUDPData, nTime);
+ nResult = (ctl.data - nUDPCount) * 100 / ctl.data;
+ printf(" (%ld%%) Rx.\n", nResult);
+ }
+
+ ctl.cmd = htonl(CMD_QUIT);
+ ctl.data = 0;
+
+ send_data(server, (void *) &ctl, CTLSIZE, 0);
+
+ printf("Done.\n");
+
+ soclose(server);
+ free(cBuffer);
+}
+
+/* main / user interface */
+
+int bSRV, bTCP, bUDP;
+
+void handler(int sig)
+{
+ _exit(0);
+}
+
+void usage(void)
+{
+ printf(
+ "\nUsage: netio [options] [<server>]\n"
+ "\n -s run server side of benchmark (otherwise run client)"
+ "\n -b <size>[k] use this block size (otherwise run with 1,2,4,8,16 and 32k)"
+ "\n -B -K -M -G force number formatting to Bytes, K, M or G Bytes\n"
+
+ "\n -t use TCP protocol for benchmark"
+ "\n -u use UDP protocol for benchmark"
+ "\n -h <addr/name> bind TCP and UDP sockets to this local host address/name"
+ "\n defaults to all (server) or unspecified (client)"
+ "\n -p <port> bind TCP and UDP servers to this port (default is %d)\n"
+
+ "\n <server> If the client side of the benchmark is running,"
+ "\n a server name or address is required.\n"
+
+ "\nThe server side can run either TCP (-t) or UDP (-u) protocol or both"
+ "\n(default, if neither -t or -u is specified). The client runs one of"
+ "\nthese protocols only (must specify -t or -u).\n"
+ "\n", nPort);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ char szVersion[32], *szName = 0, *szLocal = 0, *szEnd;
+ int option;
+ struct hostent *host;
+ long nSize;
+
+ strcpy(szVersion, rcsrev + sizeof("$Revision: ") - 1);
+ *strchr(szVersion, ' ') = 0;
+
+ printf("\nNETIO - Network Throughput Benchmark, Version %s"
+ "\n(C) 1997-2012 Kai Uwe Rommel\n", szVersion);
+
+ if (argc == 1)
+ usage();
+
+ /* check arguments */
+
+ while ((option = getopt(argc, argv, "?stup:h:b:dBKMG")) != -1)
+ switch (option)
+ {
+ case 's':
+ bSRV = 1;
+ break;
+ case 't':
+ bTCP = 1;
+ break;
+ case 'u':
+ bUDP = 1;
+ break;
+ case 'p':
+ nPort = atoi(optarg);
+ nAuxPort = nPort + 1;
+ break;
+ case 'h':
+ szLocal = optarg;
+ break;
+ case 'b':
+ nSize = strtol(optarg, &szEnd, 10);
+ if (*szEnd == 'k')
+ nSize *= 1024;
+ nSizes[0] = min(max(nSize, 1), NMAXSIZE);
+ tSizes[0] = min(max(nSize, 1), TMAXSIZE);
+ nnSizes = ntSizes = 1;
+ break;
+#ifdef WATT32
+ case 'd':
+ dbug_init();
+ break;
+#endif
+ case 'B':
+ nFormat = nf_bytes;
+ break;
+ case 'K':
+ nFormat = nf_kbytes;
+ break;
+ case 'M':
+ nFormat = nf_mbytes;
+ break;
+ case 'G':
+ nFormat = nf_gbytes;
+ break;
+ default:
+ usage();
+ break;
+ }
+
+ if (bSRV == 1 && bTCP == 0 && bUDP == 0)
+ bTCP = bUDP = 1;
+
+ /* initialize TCP/IP */
+
+ if (bTCP || bUDP)
+ {
+ if (sock_init())
+ return psock_errno("sock_init()"), 1;
+
+ if (szLocal == 0)
+ addr_local.s_addr = INADDR_ANY;
+ else
+ {
+ if (isdigit(*szLocal))
+ addr_local.s_addr = inet_addr(szLocal);
+ else
+ {
+ if ((host = gethostbyname(szLocal)) == NULL)
+ return psock_errno("gethostbyname()"), 1;
+
+ addr_local = * (struct in_addr *) (host->h_addr);
+ }
+ }
+
+ if (!bSRV)
+ {
+ if (optind == argc)
+ usage();
+
+ if (isdigit(*argv[optind]))
+ addr_server.s_addr = inet_addr(argv[optind]);
+ else
+ {
+ if ((host = gethostbyname(argv[optind])) == NULL)
+ return psock_errno("gethostbyname()"), 1;
+
+ addr_server = * (struct in_addr *) (host->h_addr);
+ }
+ }
+ }
+
+ /* do work */
+
+ signal(SIGINT, handler);
+
+ if (bSRV)
+ {
+ printf("\n");
+
+ if (bTCP)
+ {
+ if (newthread(TCP_Server))
+ return printf("Cannot create additional thread.\n"), 2;
+ }
+ if (bUDP)
+ {
+ if (newthread(UDP_Receiver))
+ return printf("Cannot create additional thread.\n"), 2;
+ if (newthread(UDP_Server))
+ return printf("Cannot create additional thread.\n"), 2;
+ }
+
+ for (;;) sleep(86400);
+ }
+ else
+ {
+ if (bTCP + bUDP > 1) /* exactly one only */
+ usage();
+
+ if (bTCP)
+ TCP_Bench(0);
+ else if (bUDP)
+ {
+ if (newthread(UDP_Receiver))
+ return printf("Cannot create additional thread.\n"), 2;
+ while (udpd == 0) sleep(1);
+ UDP_Bench(0);
+ }
+ }
+
+ /* terminate */
+
+ printf("\n");
+
+ return 0;
+}
+
+/* end of netio.c */
diff --git a/SylixOS/driver/netif/netio/netio.doc b/SylixOS/driver/netif/netio/netio.doc
new file mode 100644
index 0000000..c711371
--- /dev/null
+++ b/SylixOS/driver/netif/netio/netio.doc
@@ -0,0 +1,48 @@
+NETIO - Network Benchmark, Version 1.32
+(C) 1997-2012 Kai Uwe Rommel
+
+This is a network benchmark for OS/2 2.x, Windows, Linux and Unix.
+It measures the net throughput of a network via TCP and UDP
+protocols using various different packet sizes.
+
+One instance has to run on one machine as a server process, another
+instance is used on another machine to perform the benchmark. When
+executed without arguments, the program will explain its usage.
+
+Full source code is included. For compilation, IBM C/C++ for OS/2
+or gcc (mingw) for Windows is required, gcc can be used under Unix.
+
+Starting with version 1.20, multi threading support is required.
+Under Unix this has to be pthreads (tested with Linux). Therefore,
+DOS is no longer supported beginning with version 1.20.
+
+A few executable files are included. The author can only build for OS/2,
+Windows, Linux and AIX. The other executable files (if any) are
+contributions from other people who ported the benchmark to their
+platform. However, those executables may be out of date now (based
+on earlier versions). Especially, executables of version 1.16 and
+newer will not communicate with versions below 1.16.
+
+This program/these programs can be used freely for private or
+educational purposes. If you want to use them for commercial purposes,
+please contact the author. You may redistribute this software only if
+all files from my original distribution are included unchanged. You may
+only add readable documentation files, such as a BBS signature, and only
+if they are marked prominently as additions. If you want to include any
+part of the orignal distribution with other software, please contact the
+author before.
+
+There is no warranty. Use this software on your own risk. Due to the
+complexity and variety of today's hardware and software which may be
+used to run these programs, I am not responsible for any damage or loss
+of data or hardware failures or other damage caused by correct or
+incorrect use of this software. It was tested very well and is expected
+to work correctly, but nobody can actually guarantee this under any
+circumstances. And because this software is essentially free (even if
+you register, you don't pay for using this software but for the service
+of getting upgrades), you get what you pay for ...
+
+Author: Kai Uwe Rommel
+ Muenchen, Germany
+
+E-mail: rommel@ars.de
diff --git a/SylixOS/user/main.c b/SylixOS/user/main.c
index 3785eeb..e3c5c59 100644
--- a/SylixOS/user/main.c
+++ b/SylixOS/user/main.c
@@ -34,5 +34,8 @@ int t_main (void)
//canTestStart();
+ extern int netio_main(int argc, char **argv);
+ API_TShellKeywordAdd("netio", netio_main);
+
return (0);
}