ports/benchmarks/netio/files/patch-netio.c
Bartek Rutkowski 902e1e1c72 benchmarks/netio: update 1.26 -> 1.32
- Fix clang build issues
- Maintainer's timeout (arved@FreeBSD.org)

PR:		181789
Submitted by:	Pawel Biernacki <pawel.biernacki@gmail.com>
2015-03-22 17:28:27 +00:00

3126 lines
66 KiB
C

--- netio.c.orig 2015-03-22 18:03:25.739744000 +0100
+++ netio.c 2015-03-22 18:03:36.459543000 +0100
@@ -1,1505 +1,1618 @@
-/* netio.c
- *
- * Author: Kai-Uwe Rommel <rommel@ars.de>
- * Created: Wed Sep 25 1996
- */
-
-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;
-}
-
-int StartAlarm(long nSeconds)
-{
- bTimeOver = 0;
- signal(SIGALRM, on_alarm);
- alarm(nSeconds);
- 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 */
+/* netio.c
+ *
+ * Author: Kai-Uwe Rommel <rommel@ars.de>
+ * Created: Wed Sep 25 1996
+ */
+
+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 <arpa/inet.h>
+#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;
+}
+
+int StartAlarm(long nSeconds)
+{
+ bTimeOver = 0;
+ signal(SIGALRM, on_alarm);
+ alarm(nSeconds);
+ 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)
+{
+ ssize_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;
+#ifdef USE_IPV6
+struct in6_addr addr_server;
+struct in6_addr addr_local;
+#else
+struct in_addr addr_server;
+struct in_addr addr_local;
+#endif
+
+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;
+#ifdef USE_IPV6
+ struct sockaddr_in6 sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server, sa_client;
+#endif
+ 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;
+ }
+
+#ifdef USE_IPV6
+ if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
+#else
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+#endif
+ {
+ 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));
+
+#ifdef USE_IPV6
+ sa_server.sin6_family = AF_INET6;
+ sa_server.sin6_port = htons(nPort);
+ sa_server.sin6_addr = addr_local;
+#else
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nPort);
+ sa_server.sin_addr = addr_local;
+#endif
+
+ 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;
+#ifdef USE_IPV6
+ struct sockaddr_in6 sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server, sa_client;
+#endif
+ int server;
+ int rc;
+ int nByte;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return;
+ }
+
+#ifdef USE_IPV6
+ if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
+#else
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+#endif
+ {
+ 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));
+
+#ifdef USE_IPV6
+ sa_client.sin6_family = AF_INET6;
+ sa_client.sin6_port = htons(0);
+ sa_client.sin6_addr = addr_local;
+#else
+ sa_client.sin_family = AF_INET;
+ sa_client.sin_port = htons(0);
+ sa_client.sin_addr = addr_local;
+#endif
+
+ if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
+ {
+ psock_errno("bind()");
+ soclose(server);
+ free(cBuffer);
+ return;
+ }
+
+#ifdef USE_IPV6
+ sa_server.sin6_family = AF_INET6;
+ sa_server.sin6_port = htons(nPort);
+ sa_server.sin6_addr = addr_server;
+#else
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nPort);
+ sa_server.sin_addr = addr_server;
+#endif
+
+ 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;
+#ifdef USE_IPV6
+ struct sockaddr_in6 sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server, sa_client;
+#endif
+ int rc;
+ socklen_type nBytes;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return THREADRESULT;
+ }
+
+#ifdef USE_IPV6
+ if ((udpsocket = socket(PF_INET6, SOCK_DGRAM, 0)) < 0)
+#else
+ if ((udpsocket = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
+#endif
+ {
+ 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));
+
+#ifdef USE_IPV6
+ sa_server.sin6_family = AF_INET6;
+ sa_server.sin6_port = htons(nAuxPort);
+ sa_server.sin6_addr = addr_local;
+#else
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_local;
+#endif
+
+ 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;
+#ifdef USE_IPV6
+ struct sockaddr_in6 sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server, sa_client;
+#endif
+ int server, client;
+ struct timeval tv;
+ fd_set fds;
+ int rc, nByte;
+ socklen_type nLength;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return THREADRESULT;
+ }
+
+#ifdef USE_IPV6
+ if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
+#else
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+#endif
+ {
+ 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));
+
+#ifdef USE_IPV6
+ sa_server.sin6_family = AF_INET6;
+ sa_server.sin6_port = htons(nAuxPort);
+ sa_server.sin6_addr = addr_local;
+#else
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_local;
+#endif
+
+ 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);
+
+#ifdef USE_IPV6
+ sa_client.sin6_port = htons(nAuxPort);
+#else
+ sa_client.sin_port = htons(nAuxPort);
+#endif
+
+ 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;
+#ifdef USE_IPV6
+ struct sockaddr_in6 sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server, sa_client;
+#endif
+ int server;
+ int rc, nByte;
+
+ if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
+ {
+ perror("malloc()");
+ return;
+ }
+
+#ifdef USE_IPV6
+ if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
+#else
+ if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+#endif
+ {
+ 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));
+
+#ifdef USE_IPV6
+ sa_client.sin6_family = AF_INET6;
+ sa_client.sin6_port = htons(0);
+ sa_client.sin6_addr = addr_local;
+#else
+ sa_client.sin_family = AF_INET;
+ sa_client.sin_port = htons(0);
+ sa_client.sin_addr = addr_local;
+#endif
+
+ if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
+ {
+ psock_errno("bind(STREAM)");
+ soclose(server);
+ free(cBuffer);
+ return;
+ }
+
+#ifdef USE_IPV6
+ sa_server.sin6_family = AF_INET6;
+ sa_server.sin6_port = htons(nAuxPort);
+ sa_server.sin6_addr = addr_server;
+#else
+ sa_server.sin_family = AF_INET;
+ sa_server.sin_port = htons(nAuxPort);
+ sa_server.sin_addr = addr_server;
+#endif
+
+ 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)
+#ifdef USE_IPV6
+ addr_local = in6addr_any;
+#else
+ addr_local.s_addr = INADDR_ANY;
+#endif
+ else
+ {
+ if (isdigit(*szLocal))
+#ifdef USE_IPV6
+ inet_pton(AF_INET6, szLocal, &addr_local);
+#else
+ addr_local.s_addr = inet_addr(szLocal);
+#endif
+ else
+ {
+ if ((host = gethostbyname(szLocal)) == NULL)
+ return psock_errno("gethostbyname()"), 1;
+
+#ifdef USE_IPV6
+ addr_local = * (struct in6_addr *) (host->h_addr);
+#else
+ addr_local = * (struct in_addr *) (host->h_addr);
+#endif
+ }
+ }
+
+ if (!bSRV)
+ {
+ if (optind == argc)
+ usage();
+
+ if (isdigit(*argv[optind]))
+#ifdef USE_IPV6
+ inet_pton(AF_INET6, argv[optind], &addr_server);
+#else
+ addr_server.s_addr = inet_addr(argv[optind]);
+#endif
+ else
+ {
+ if ((host = gethostbyname(argv[optind])) == NULL)
+ return psock_errno("gethostbyname()"), 1;
+
+#ifdef USE_IPV6
+ addr_server = * (struct in6_addr *) (host->h_addr);
+#else
+ addr_server = * (struct in_addr *) (host->h_addr);
+#endif
+ }
+ }
+ }
+
+ /* 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 */
+