home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2004 November
/
PCWorld_2004-11_cd.bin
/
software
/
vyzkuste
/
naradi
/
naradi2.exe
/
hwutil2
/
Netio
/
Netio.exe
/
netio.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-09-30
|
36KB
|
1,742 lines
/* netio.c
*
* Author: Kai-Uwe Rommel <rommel@ars.de>
* Created: Wed Sep 25 1996
*/
static char *rcsid =
"$Id: netio.c,v 1.23 2003/09/30 09:32:22 Rommel Exp Rommel $";
static char *rcsrev = "$Revision: 1.23 $";
/*
* $Log: netio.c,v $
* 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"
#include "netbios.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
#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
#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*
#endif /* UNIX */
/* 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};
int nnSizes = sizeof(nSizes) / sizeof(int);
#define NMAXSIZE 65536
int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767};
int ntSizes = sizeof(tSizes) / sizeof(int);
#define TMAXSIZE 65536
#define INTERVAL 6
typedef struct
{
long cmd;
long 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 nArg)
{
HEV hSem;
HTIMER hTimer;
DosCreateEventSem(0, &hSem, DC_SEM_SHARED, 0);
DosAsyncTimer(nArg * 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;
DWORD CALLBACK TimerThread(void * pArg)
{
Sleep((long) pArg * 1000);
bTimeOver = 1;
return 0;
}
int StartAlarm(long nSeconds)
{
DWORD ttid;
bTimeOver = 0;
if (CreateThread(0, THREADSTACK, TimerThread, (void *) nSeconds, 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 */
char *InitBuffer(int nSize)
{
char *cBuffer = malloc(nSize);
if (cBuffer != NULL)
{
int i;
cBuffer[0] = 0;
srand(1);
for (i = 1; i < nSize; i++)
cBuffer[i] = (char) rand();
}
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;
}
/* NetBIOS code */
#ifdef USE_NETBIOS
char *szServerName = DEFAULTNBSRV;
char *szClientName = DEFAULTNBCLT;
USHORT nAdapter = 0;
NCB WorkNcb;
USHORT nLSN, rc;
THREAD NetBIOS_Server(void *arg)
{
char *cBuffer;
CONTROL ctl;
int nByte;
if ((cBuffer = InitBuffer(NMAXSIZE)) == NULL)
{
perror("malloc()");
return;
}
if ((rc = NCBAddName(&WorkNcb, nAdapter, szServerName)) != 0 && rc != 13)
{
printf("NetBIOS AddName Failed, rc=0x%02X\n", rc);
free(cBuffer);
return;
}
for (;;)
{
printf("NetBIOS server listening.\n");
if ((rc = NCBListen(&WorkNcb, nAdapter, szServerName, "*", 0, 0, TRUE)) != 0)
{
printf("NetBIOS Listen failed, rc=0x%02X\n", rc);
break;
}
nLSN = WorkNcb.basic_ncb.bncb.ncb_lsn;
printf("NetBIOS connection established ... ");
fflush(stdout);
for (;;)
{
if ((rc = NCBReceive(&WorkNcb, nAdapter, nLSN,
(void *) &ctl, CTLSIZE, TRUE)) != 0)
{
printf("NetBIOS Receive Failed, rc=0x%02X\n", rc);
break;
}
if (ctl.cmd == CMD_C2S)
{
printf("\nReceiving from client, packet size %s ...", PacketSize(ctl.data));
do
{
for (nByte = 0; nByte < ctl.data; )
{
rc = NCBReceive(&WorkNcb, nAdapter, nLSN,
cBuffer + nByte, ctl.data - nByte, TRUE);
if (rc != 0 && rc != NB_MESSAGE_INCOMPLETE)
{
printf("NetBIOS Receive Failed, rc=0x%02X\n", rc);
break;
}
nByte += WorkNcb.basic_ncb.bncb.ncb_length;
}
}
while (cBuffer[0] == 0 && rc == 0);
}
else if (ctl.cmd == CMD_S2C)
{
printf("\nSending to client, packet size %s ...", PacketSize(ctl.data));
if (StartAlarm(INTERVAL) == 0)
{
cBuffer[0] = 0;
while (!bTimeOver)
{
for (nByte = 0; nByte < ctl.data; )
{
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
cBuffer + nByte, ctl.data - nByte, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
nByte += WorkNcb.basic_ncb.bncb.ncb_length;
}
}
cBuffer[0] = 1;
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
cBuffer, ctl.data, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
}
}
else /* quit */
break;
}
NCBHangup(&WorkNcb, nAdapter, nLSN);
printf("\nDone.\n");
}
NCBDeleteName(&WorkNcb, nAdapter, szServerName);
free(cBuffer);
}
void NetBIOS_Bench(void *arg)
{
char *cBuffer;
TIMER nTimer;
CONTROL ctl;
long nTime, nResult;
long nData;
int i;
int nByte;
if ((cBuffer = InitBuffer(NMAXSIZE)) == NULL)
{
perror("malloc()");
return;
}
if ((rc = NCBAddName(&WorkNcb, nAdapter, szClientName)) != 0 && rc != 13)
{
printf("NetBIOS AddName Failed, rc=0x%02X\n", rc);
free(cBuffer);
return;
}
if ((rc = NCBCall(&WorkNcb, nAdapter, szClientName, szServerName, 0, 0, TRUE)) != 0)
printf("NetBIOS Call failed, rc=0x%02X\n", rc);
else
{
nLSN = WorkNcb.basic_ncb.bncb.ncb_lsn;
printf("\nNetBIOS connection established.\n");
for (i = 0; i < nnSizes; i++)
{
printf("Packet size %s bytes: ", PacketSize(nSizes[i]));
fflush(stdout);
/* tell the server we will send it data now */
ctl.cmd = CMD_C2S;
ctl.data = nSizes[i];
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
(void *) &ctl, CTLSIZE, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
/* 1 - Tx test */
if (StartAlarm(INTERVAL) == 0 && StartTimer(&nTimer) == 0)
{
nData = 0;
cBuffer[0] = 0;
while (!bTimeOver)
{
for (nByte = 0; nByte < ctl.data; )
{
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
cBuffer + nByte, ctl.data - nByte, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
nByte += WorkNcb.basic_ncb.bncb.ncb_length;
}
nData += ctl.data;
}
if ((nTime = StopTimer(&nTimer, 1024)) == -1)
printf("(failed)");
else
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
printf(" Tx, ");
fflush(stdout);
cBuffer[0] = 1;
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
cBuffer, ctl.data, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
}
/* tell the server we expect him to send us data now */
ctl.cmd = CMD_S2C;
ctl.data = nSizes[i];
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
(void *) &ctl, CTLSIZE, TRUE)) != 0)
{
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
break;
}
/* 2 - Rx test */
if (StartTimer(&nTimer) == 0)
{
nData = 0;
do
{
for (nByte = 0; nByte < ctl.data; )
{
rc = NCBReceive(&WorkNcb, nAdapter, nLSN,
cBuffer + nByte, ctl.data - nByte, TRUE);
if (rc != 0 && rc != NB_MESSAGE_INCOMPLETE)
{
printf("NetBIOS Receive Failed, rc=0x%02X\n", rc);
break;
}
nByte += WorkNcb.basic_ncb.bncb.ncb_length;
}
nData += ctl.data;
}
while (cBuffer[0] == 0 && rc == 0);
if ((nTime = StopTimer(&nTimer, 1024)) == -1)
printf(" (failed)");
else
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
printf(" Rx.\n");
}
}
ctl.cmd = CMD_QUIT;
ctl.data = 0;
if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
(void *) &ctl, CTLSIZE, TRUE)) != 0)
printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
NCBHangup(&WorkNcb, nAdapter, nLSN);
}
NCBDeleteName(&WorkNcb, nAdapter, szClientName);
free(cBuffer);
}
#endif /* USE_NETBIOS */
/* TCP/IP code */
int _send(int socket, void *buffer, int 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(int socket, void *buffer, int size, int flags)
{
int 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;
long long nData;
struct sockaddr_in sa_server, sa_client;
int server, client, length;
struct timeval tv;
fd_set fds;
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_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;
}
if (listen(server, 2) != 0)
{
psock_errno("listen()");
soclose(server);
free(cBuffer);
return;
}
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(client, (void *) &ctl, CTLSIZE, 0))
break;
ctl.cmd = ntohl(ctl.cmd);
ctl.data = ntohl(ctl.data);
if (ctl.cmd == CMD_C2S)
{
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);
}
else if (ctl.cmd == CMD_S2C)
{
if (StartAlarm(INTERVAL) == 0)
{
printf("\nSending to client, packet size %s ... ", PacketSize(ctl.data));
cBuffer[0] = 0;
nData = 0;
while (!bTimeOver)
{
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(client, cBuffer, ctl.data, 0))
break;
}
}
else /* quit */
break;
}
printf("\nDone.\n");
soclose(client);
if (rc < 0)
break;
}
soclose(server);
free(cBuffer);
}
void TCP_Bench(void *arg)
{
char *cBuffer;
CONTROL ctl;
TIMER nTimer;
long nTime, nResult;
long long nData;
int i;
struct sockaddr_in sa_server;
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_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(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 1 - Tx test */
if (StartAlarm(INTERVAL) == 0 && StartTimer(&nTimer) == 0)
{
nData = 0;
cBuffer[0] = 0;
while (!bTimeOver)
{
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)");
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
printf(" Tx, ");
fflush(stdout);
cBuffer[0] = 1;
if (_send(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(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 2 - Rx test */
if (StartTimer(&nTimer) == 0)
{
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)");
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
printf(" Rx.\n");
}
}
ctl.cmd = htonl(CMD_QUIT);
ctl.data = 0;
_send(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, nBytes;
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
{
perror("malloc()");
return;
}
if ((udpsocket = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
psock_errno("socket(DGRAM)");
free(cBuffer);
return;
}
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;
}
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);
}
THREAD UDP_Server(void *arg)
{
char *cBuffer;
CONTROL ctl;
long long nData;
struct sockaddr_in sa_server, sa_client;
int server, client;
struct timeval tv;
fd_set fds;
int rc, nByte, nLength;
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
{
perror("malloc()");
return;
}
if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
psock_errno("socket(STREAM)");
free(cBuffer);
return;
}
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;
}
if (listen(server, 2) != 0)
{
psock_errno("listen()");
soclose(server);
free(cBuffer);
return;
}
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(client, (void *) &ctl, CTLSIZE, 0))
break;
ctl.cmd = ntohl(ctl.cmd);
ctl.data = ntohl(ctl.data);
if (ctl.cmd == CMD_C2S)
{
printf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data));
nUDPCount = 0;
nUDPData = 0;
ctl.cmd = htonl(ctl.cmd);
ctl.data = htonl(ctl.data);
if (_send(client, (void *) &ctl, CTLSIZE, 0))
break;
}
else if (ctl.cmd == CMD_RES)
{
ctl.cmd = htonl(ctl.cmd);
ctl.data = htonl(nUDPCount);
if (_send(client, (void *) &ctl, CTLSIZE, 0))
break;
}
else if (ctl.cmd == CMD_S2C)
{
if (StartAlarm(INTERVAL) == 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)
{
for (nByte = 0; nByte < nLength; )
{
rc = sendto(udpsocket, cBuffer + nByte, nLength - nByte, 0,
(struct sockaddr *) &sa_client, sizeof(sa_client));
if (rc < 0 && errno != EINTR)
{
psock_errno("sendto()");
break;
}
if (rc > 0)
nByte += rc;
}
ctl.data++;
}
ctl.data = htonl(ctl.data);
if (_send(client, (void *) &ctl, CTLSIZE, 0))
break;
}
}
else /* quit */
break;
}
printf("\nDone.\n");
soclose(client);
if (rc < 0)
break;
}
soclose(server);
free(cBuffer);
}
void UDP_Bench(void *arg)
{
char *cBuffer;
CONTROL ctl;
TIMER nTimer;
long nTime, nResult, nCount;
long long nData;
int i;
struct sockaddr_in sa_server;
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_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(server, (void *) &ctl, CTLSIZE, 0))
break;
if (_recv(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 1 - Tx test */
if (StartAlarm(INTERVAL) == 0 && StartTimer(&nTimer) == 0)
{
cBuffer[0] = 0;
nData = 0;
nCount = 0;
while (!bTimeOver)
{
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(server, (void *) &ctl, CTLSIZE, 0))
break;
if (_recv(server, (void *) &ctl, CTLSIZE, 0))
break;
ctl.data = ntohl(ctl.data);
nData = (long long) tSizes[i] * ctl.data;
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
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]);
nUDPCount = 0;
nUDPData = 0;
if (_send(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 2 - Rx test */
if (StartTimer(&nTimer) == 0)
{
if (_recv(server, (void *) &ctl, CTLSIZE, 0))
break;
if ((nTime = StopTimer(&nTimer, 1024)) == -1)
printf(" (failed)");
ctl.data = ntohl(ctl.data);
nData = nUDPData;
if (nData < 100 * 1024 * INTERVAL)
{
nResult = nData * 1024 / nTime;
printf(" %ld Byte/s", nResult);
}
else
{
nResult = nData / nTime;
printf(" %ld KByte/s", nResult);
}
nResult = (ctl.data - nUDPCount) * 100 / ctl.data;
printf(" (%ld%%) Rx.\n", nResult);
}
}
ctl.cmd = htonl(CMD_QUIT);
ctl.data = 0;
_send(server, (void *) &ctl, CTLSIZE, 0);
printf("Done.\n");
soclose(server);
free(cBuffer);
}
/* main / user interface */
int bSRV, bNB, bTCP, bUDP;
void handler(int sig)
{
#ifdef USE_NETBIOS
if (bNB)
{
NCBDeleteName(&WorkNcb, nAdapter, szServerName);
NCBDeleteName(&WorkNcb, nAdapter, szClientName);
NCBClose(&WorkNcb, nAdapter);
}
#endif
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"
"\n -t use TCP protocol for benchmark"
"\n -u use UDP protocol for benchmark"
"\n -h <addr> bind TCP and UDP servers to this local host address/name only"
"\n (default is to bind to all local addresses)"
"\n -p <port> bind TCP and UDP servers to this port (default is %d)\n"
#ifdef USE_NETBIOS
"\n -n use NetBIOS protocol for benchmark"
"\n -m <name> use this as the local NetBIOS name (defaults are NETIOSRV"
"\n for the server and NETIOCLT for the client)"
"\n -a <adapter> use this NetBIOS adapter (default is 0)\n"
"\n <server> If TCP or UDP is used for the client, a server name or address"
"\n is required. For NetBIOS, this is optional, for the case that"
"\n the server uses a different NetBIOS name than NETIOSRV.\n"
"\nThe server side can run either NetBIOS (-n), TCP (-t) or UDP (-u) protocol"
"\nor all three (default, if neither -t, -u or -n are specified). The client"
"\nruns one of these protocols only (-t, -u or -n must be specified).\n"
"\nThe -m and -a options apply to both client and server sides."
#else
"\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"
#endif
"\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-2003 Kai Uwe Rommel\n", szVersion);
if (argc == 1)
usage();
/* check arguments */
#ifndef USE_NETBIOS
/* bTCP = 1; */
#endif
while ((option = getopt(argc, argv, "?stunp:m:a:dh:b:")) != -1)
switch (option)
{
case 's':
bSRV = 1;
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;
case 'p':
nPort = atoi(optarg);
nAuxPort = nPort + 1;
break;
case 'h':
szLocal = optarg;
break;
case 't':
bTCP = 1;
break;
case 'u':
bUDP = 1;
break;
#ifdef USE_NETBIOS
case 'n':
bNB = 1;
break;
case 'a':
nAdapter = atoi(optarg);
break;
case 'm':
szName = optarg;
break;
#endif
#ifdef WATT32
case 'd':
dbug_init();
break;
#endif
default:
usage();
break;
}
if (bSRV == 1 && bTCP == 0 && bUDP == 0 && bNB == 0)
bTCP = bUDP = bNB = 1;
/* initialize NetBIOS and/or TCP/IP */
#ifdef USE_NETBIOS
if (bNB)
{
NetBIOS_API = NETBIOS;
if (NetBIOS_Avail())
return printf("NetBIOS not found\n"), 1;
if ((rc = NCBReset(&WorkNcb, nAdapter, 2, 2, 2)) != 0)
return printf("NetBIOS Reset failed, rc=0x%02X\n", rc), rc;
if (szName)
{
if (bSRV)
szServerName = szName;
else
szClientName = szName;
}
if (!bSRV & optind < argc)
szServerName = argv[optind];
}
#endif
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;
}
#ifdef USE_NETBIOS
if (bNB)
{
if (newthread(NetBIOS_Server))
return printf("Cannot create additional thread.\n"), 2;
}
#endif
while (udpd == 0) sleep(1);
for (;;) sleep(86400);
}
else
{
if (bTCP + bUDP + bNB > 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);
}
#ifdef USE_NETBIOS
else if (bNB)
NetBIOS_Bench(0);
#endif
}
/* terminate */
#ifdef USE_NETBIOS
if (bNB)
NCBClose(&WorkNcb, nAdapter);
#else
printf("\n");
#endif
return 0;
}
/* end of netio.c */