1 /* netio.c
2 *
3 * Author: Kai-Uwe Rommel <rommel@ars.de>
4 * Created: Wed Sep 25 1996
5 */
6
7 static char *rcsid =
8 "$Id: netio.c,v 1.34 2018/12/16 22:45:24 rommel Exp rommel $";
9 static char *rcsrev = "$Revision: 1.34 $";
10
11 /*
12 * $Log: netio.c,v $
13 * Revision 1.34 2018/12/16 22:45:24 rommel
14 * fix for OS/2
15 *
16 * Revision 1.33 2018/12/16 20:52:52 rommel
17 * various changes
18 * updates for current MinGW32/64
19 * updates for current Linux (Ubuntu 16)
20 *
21 * Revision 1.32 2012/11/22 16:47:24 Rommel
22 * added binding to client sockets, too
23 *
24 * Revision 1.31 2010/10/14 16:44:38 Rommel
25 * fixed sleep calls
26 *
27 * Revision 1.30 2010/10/14 14:32:41 Rommel
28 * removed NetBIOS code
29 * added server side result printing
30 * fixed packet loss calculation (data type bug)
31 *
32 * Revision 1.29 2010/10/14 11:28:19 Rommel
33 * central printing routine
34 *
35 * Revision 1.28 2009/09/07 14:09:39 Rommel
36 * changed number output from bytes/KB to bytes/KB/MB
37 *
38 * Revision 1.27 2008/02/11 09:00:22 Rommel
39 * re-randomize buffer data for each loop run
40 *
41 * Revision 1.26 2005/08/30 14:45:51 Rommel
42 * minor fixes
43 *
44 * Revision 1.25 2004/05/26 07:23:04 Rommel
45 * some more corrections from Oliver Lau and Frank Schnell
46 *
47 * Revision 1.24 2004/05/17 16:01:03 Rommel
48 * fix for _send/_recv from Thomas Jahns
49 *
50 * Revision 1.23 2003/09/30 09:32:22 Rommel
51 * corrections from Matthias Scheler for error handling
52 * added socket buffer size setting
53 * added htonl/ntohl code (hint from Oliver Lau)
54 * restructured send/recv error/result checking
55 * more verbose server side messages
56 * other minor changes
57 *
58 * Revision 1.22 2003/09/22 14:58:33 Rommel
59 * added server side progress messages
60 *
61 * Revision 1.21 2003/08/28 12:44:11 Rommel
62 * fixed display of non-k-multiple packet sizes
63 *
64 * Revision 1.20 2003/08/27 11:05:48 Rommel
65 * allow block size specifikation in bytes or k bytes
66 *
67 * Revision 1.19 2003/08/17 16:53:45 Rommel
68 * added Unix/Linux pthreads support (required for UDP)
69 *
70 * Revision 1.18 2003/08/17 14:46:17 Rommel
71 * added UDP benchmark
72 * several minor changes (cleanup)
73 * configurable binding address
74 *
75 * Revision 1.17 2003/07/12 17:25:00 Rommel
76 * made block size selectable
77 *
78 * Revision 1.16 2003/02/10 09:06:59 Rommel
79 * fixed sender algorithm
80 *
81 * Revision 1.15 2001/09/17 13:56:40 Rommel
82 * changed to perform bidirectional benchmarks
83 *
84 * Revision 1.14 2001/04/19 12:20:55 Rommel
85 * added fixes for Unix systems
86 *
87 * Revision 1.13 2001/03/26 11:37:41 Rommel
88 * avoid integer overflows during throughput calculation
89 *
90 * Revision 1.12 2000/12/01 15:57:57 Rommel
91 * *** empty log message ***
92 *
93 * Revision 1.11 2000/03/01 12:21:47 rommel
94 * fixed _INTEGRAL_MAX_BITS problem for WIN32
95 *
96 * Revision 1.10 1999/10/28 17:36:57 rommel
97 * fixed OS/2 timer code
98 *
99 * Revision 1.9 1999/10/28 17:04:12 rommel
100 * fixed timer code
101 *
102 * Revision 1.8 1999/10/24 19:08:20 rommel
103 * imported DOS support from G. Vanem <giva@bgnett.no>
104 *
105 *
106 * Revision 1.8 1999/10/12 11:02:00 giva
107 * added Watt-32 with djgpp support. Added debug mode.
108 * G. Vanem <giva@bgnett.no>
109 *
110 * Revision 1.7 1999/06/13 18:42:25 rommel
111 * added Linux port with patches from Detlef Plotzky <plo@bvu.de>
112 *
113 * Revision 1.6 1998/10/12 11:14:58 rommel
114 * change to malloc'ed (and tiled) memory for transfer buffers
115 * (hint from Guenter Kukkukk <kukuk@berlin.snafu.de>)
116 * for increased performance
117 *
118 * Revision 1.5 1998/07/31 14:15:03 rommel
119 * added random buffer data
120 * fixed bugs
121 *
122 * Revision 1.4 1997/09/12 17:35:04 rommel
123 * termination bug fixes
124 *
125 * Revision 1.3 1997/09/12 12:00:15 rommel
126 * added Win32 port
127 * (tested for Windows NT only)
128 *
129 * Revision 1.2 1997/09/12 10:44:22 rommel
130 * added TCP/IP and a command line interface
131 *
132 * Revision 1.1 1996/09/25 08:42:29 rommel
133 * Initial revision
134 *
135 */
136
137 #ifdef WIN32
138 #define _INTEGRAL_MAX_BITS 64
139 #endif
140
141 #include <stdio.h>
142 #include <stdlib.h>
143 #include <string.h>
144 #include <ctype.h>
145 #include <signal.h>
146 #include <time.h>
147 #if defined(UNIX) || defined(DJGPP)
148 #include <arpa/inet.h>
149 #include <sys/time.h>
150 #include <unistd.h>
151 #include <errno.h>
152 #else
153 #include <process.h>
154 #include "getopt.h"
155 #endif
156
157 #define DEFAULTPORT 0x494F /* "IO" */
158 #define DEFAULTNBSRV "NETIOSRV"
159 #define DEFAULTNBCLT "NETIOCLT"
160 #define THREADSTACK 65536
161
162 /* TCP/IP system specific details */
163
164 #ifdef OS2
165
166 #define BSD_SELECT
167 #include <types.h>
168 #include <netinet/in.h>
169 #include <sys/select.h>
170 #include <sys/socket.h>
171 #include <sys/time.h>
172 #include <netdb.h>
173
174 #define TCP_NODELAY 1
175
176 #ifdef __IBMC__
177 #define newthread(entry) (_beginthread(entry, 0, THREADSTACK, 0) == -1)
178 #else
179 #define newthread(entry) (_beginthread(entry, THREADSTACK, 0) == -1)
180 #endif
181 #define THREAD void
182 #define THREADRESULT
183
184 #endif /* OS2 */
185
186 #ifdef WATT32
187
188 #include <tcp.h> /* sock_init() etc. */
189 #include <netinet/in.h>
190 #include <sys/socket.h>
191 #include <netdb.h>
192 #define soclose close_s
193 #define select select_s
194 #define psock_errno perror
195
196 #endif /* WATT32 */
197
198 #ifdef WIN32
199
200 #include <ws2tcpip.h>
201 #include <windows.h>
202 #include <winsock.h>
203 #define soclose closesocket
204 #define SOCKLEN_T
205
sock_init(void)206 int sock_init(void)
207 {
208 WSADATA wsaData;
209 return WSAStartup(MAKEWORD(1, 1), &wsaData);
210 }
211
psock_errno(char * text)212 void psock_errno(char *text)
213 {
214 int rc = WSAGetLastError();
215 printf("%s: error code %d\n", text, rc);
216 }
217
218 #ifdef __IBMC__
219 #define newthread(entry) (_beginthread(entry, 0, THREADSTACK, 0) == -1)
220 #else
221 #define newthread(entry) (_beginthread(entry, THREADSTACK, 0) == -1)
222 #endif
223 #define THREAD void
224 #define THREADRESULT
225
226 #endif /* WIN32 */
227
228 #ifdef UNIX
229
230 #include <sys/types.h>
231 #include <sys/socket.h>
232 #include <sys/time.h>
233 #include <time.h>
234 #include <netinet/in.h>
235 #include <netinet/tcp.h>
236 #include <arpa/inet.h>
237 #include <netdb.h>
238
239 #define SOCKLEN_T
240 #define psock_errno(x) perror(x)
241 #define soclose(x) close(x)
242
sock_init(void)243 int sock_init(void)
244 {
245 return 0;
246 }
247
248 #include <pthread.h>
249 pthread_t thread;
250 #define newthread(entry) (pthread_create(&thread, 0, entry, 0) != 0)
251 #define THREAD void*
252 #define THREADRESULT ((void*)0)
253
254 #endif /* UNIX */
255
256 #ifdef SOCKLEN_T
257 typedef socklen_t socklen_type;
258 #else
259 typedef size_t socklen_type;
260 #endif
261
262 /* global data */
263
264 #ifndef max
265 #define max(x, y) ((x) > (y) ? (x) : (y))
266 #endif
267
268 #ifndef min
269 #define min(x, y) ((x) < (y) ? (x) : (y))
270 #endif
271
272 #ifndef EINTR
273 #define EINTR 0
274 #endif
275
276 int nSizes[] = {1024, 2048, 4096, 8192, 16384, 32768};
277 size_t nnSizes = sizeof(nSizes) / sizeof(int);
278 #define NMAXSIZE 65536
279
280 int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767};
281 size_t ntSizes = sizeof(tSizes) / sizeof(int);
282 #define TMAXSIZE 65536
283
284 #define INTERVAL 6
285
286 /* you may need to adapt this to your platform/compiler */
287 typedef unsigned int uint32;
288
289 typedef struct
290 {
291 uint32 cmd;
292 uint32 data;
293 }
294 CONTROL;
295
296 #define CMD_QUIT 0
297 #define CMD_C2S 1
298 #define CMD_S2C 2
299 #define CMD_RES 3
300
301 #define CTLSIZE sizeof(CONTROL)
302
303 /* timer code */
304
305 int bTimeOver;
306
307 #ifdef OS2
308
309 #define INCL_DOS
310 #define INCL_NOPM
311 #include <os2.h>
312
313 typedef QWORD TIMER;
314
TimerThread(ULONG nSeconds)315 void APIENTRY TimerThread(ULONG nSeconds)
316 {
317 HEV hSem;
318 HTIMER hTimer;
319
320 DosCreateEventSem(0, &hSem, DC_SEM_SHARED, 0);
321
322 DosAsyncTimer(nSeconds * 1000, (HSEM) hSem, &hTimer);
323 DosWaitEventSem(hSem, SEM_INDEFINITE_WAIT);
324 DosStopTimer(hTimer);
325
326 DosCloseEventSem(hSem);
327
328 bTimeOver = 1;
329
330 DosExit(EXIT_THREAD, 0);
331 }
332
StartAlarm(long nSeconds)333 int StartAlarm(long nSeconds)
334 {
335 TID ttid;
336
337 bTimeOver = 0;
338
339 if (DosCreateThread(&ttid, TimerThread, nSeconds, 0, THREADSTACK))
340 return printf("Cannot create timer thread.\n"), -1;
341
342 return 0;
343 }
344
StartTimer(TIMER * nStart)345 int StartTimer(TIMER *nStart)
346 {
347 if (DosTmrQueryTime(nStart))
348 return printf("Timer error.\n"), -1;
349
350 return 0;
351 }
352
StopTimer(TIMER * nStart,int nAccuracy)353 long StopTimer(TIMER *nStart, int nAccuracy)
354 {
355 TIMER nStop;
356 ULONG nFreq;
357
358 if (DosTmrQueryTime(&nStop))
359 return printf("Timer error.\n"), -1;
360 if (DosTmrQueryFreq(&nFreq))
361 return printf("Timer error.\n"), -1;
362
363 nFreq = (nFreq + nAccuracy / 2) / nAccuracy;
364
365 return (* (long long *) &nStop - * (long long *) nStart) / nFreq;
366 }
367
368 #endif /* OS2 */
369
370 #ifdef WIN32
371
372 typedef LARGE_INTEGER TIMER;
373
374 #define sleep(x) Sleep((x) * 1000);
375
TimerThread(void * pArg)376 DWORD CALLBACK TimerThread(void *pArg)
377 {
378 long nSeconds = * (long *) pArg;
379
380 Sleep(nSeconds * 1000);
381 bTimeOver = 1;
382
383 return 0;
384 }
385
StartAlarm(long nSeconds)386 int StartAlarm(long nSeconds)
387 {
388 static long sSeconds;
389 DWORD ttid;
390
391 sSeconds = nSeconds;
392
393 bTimeOver = 0;
394
395 if (CreateThread(0, THREADSTACK, TimerThread, (void *) &sSeconds, 0, &ttid) == NULL)
396 return printf("Cannot create timer thread.\n"), -1;
397
398 return 0;
399 }
400
StartTimer(TIMER * nStart)401 int StartTimer(TIMER *nStart)
402 {
403 if (!QueryPerformanceCounter(nStart))
404 return printf("Timer error.\n"), -1;
405
406 return 0;
407 }
408
StopTimer(TIMER * nStart,int nAccuracy)409 long StopTimer(TIMER *nStart, int nAccuracy)
410 {
411 TIMER nStop, nFreq;
412
413 if (!QueryPerformanceCounter(&nStop))
414 return printf("Timer error.\n"), -1;
415 if (!QueryPerformanceFrequency(&nFreq))
416 return printf("Timer error.\n"), -1;
417
418 nFreq.QuadPart = (nFreq.QuadPart + nAccuracy / 2) / nAccuracy;
419
420 return (nStop.QuadPart - nStart->QuadPart) / nFreq.QuadPart;
421 }
422
423 #endif /* WIN32 */
424
425 #if defined(UNIX) || defined(DJGPP)
426
427 typedef struct timeval TIMER;
428
on_alarm(int signum)429 void on_alarm(int signum)
430 {
431 alarm(0);
432 bTimeOver = 1;
433 }
434
StartAlarm(long nSeconds)435 int StartAlarm(long nSeconds)
436 {
437 bTimeOver = 0;
438 signal(SIGALRM, on_alarm);
439 alarm(nSeconds);
440 return 0;
441 }
442
StartTimer(TIMER * nStart)443 int StartTimer(TIMER *nStart)
444 {
445 struct timezone tz = {0, 0};
446
447 gettimeofday(nStart, &tz);
448
449 return 0;
450 }
451
StopTimer(TIMER * nStart,int nAccuracy)452 long StopTimer(TIMER *nStart, int nAccuracy)
453 {
454 struct timezone tz = {0, 0};
455 TIMER nStop;
456
457 gettimeofday(&nStop, &tz);
458
459 return (nStop.tv_sec - nStart->tv_sec) * nAccuracy
460 + (nStop.tv_usec - nStart->tv_usec) * nAccuracy / 1000000;
461 }
462
463 #endif /* UNIX || DJGPP */
464
465 /* initialize data to transfer */
466
GenerateRandomData(char * cBuffer,size_t nSize)467 void GenerateRandomData(char *cBuffer, size_t nSize)
468 {
469 if (cBuffer != NULL)
470 {
471 size_t i;
472
473 cBuffer[0] = 0;
474 srand(time(NULL));
475
476 for (i = 1; i < nSize; i++)
477 cBuffer[i] = (char) rand();
478 }
479 }
480
InitBuffer(size_t nSize)481 char *InitBuffer(size_t nSize)
482 {
483 char *cBuffer = malloc(nSize);
484 GenerateRandomData(cBuffer, nSize);
485 return cBuffer;
486 }
487
PacketSize(int nSize)488 char *PacketSize(int nSize)
489 {
490 static char szBuffer[64];
491
492 if ((nSize % 1024) == 0 || (nSize % 1024) == 1023)
493 sprintf(szBuffer, "%2dk", (nSize + 512) / 1024);
494 else
495 sprintf(szBuffer, "%d", nSize);
496
497 return szBuffer;
498 }
499
500 /* print results */
501
502 typedef enum {nf_auto, nf_bytes, nf_kbytes, nf_mbytes, nf_gbytes} numberformat;
503 numberformat nFormat = nf_auto;
504
print_result(long long nData,long nTime)505 void print_result(long long nData, long nTime)
506 {
507 numberformat nThisFormat = nFormat;
508 double nResult;
509
510 if (nThisFormat == nf_auto)
511 {
512 if (nData < 10 * 1024 * INTERVAL)
513 nThisFormat = nf_bytes;
514 else if (nData < 10 * 1024 * 1024 * INTERVAL)
515 nThisFormat = nf_kbytes;
516 else if (nData < (long long) 1024 * 1024 * 1024 * INTERVAL)
517 nThisFormat = nf_mbytes;
518 else
519 nThisFormat = nf_gbytes;
520 }
521
522 switch(nThisFormat)
523 {
524 case nf_bytes:
525 nResult = (double) nData * 1024 / nTime;
526 printf(" %0.0f Byte/s", nResult);
527 break;
528
529 case nf_kbytes:
530 nResult = (double) nData / nTime;
531 printf(" %0.2f KByte/s", nResult);
532 break;
533
534 case nf_mbytes:
535 nResult = (double) nData / nTime / 1024;
536 printf(" %0.2f MByte/s", nResult);
537 break;
538
539 case nf_gbytes:
540 nResult = (double) nData / nTime / 1024 / 1024;
541 printf(" %0.3f GByte/s", nResult);
542 break;
543 }
544 }
545
546 /* TCP/IP code */
547
send_data(int socket,void * buffer,size_t size,int flags)548 int send_data(int socket, void *buffer, size_t size, int flags)
549 {
550 int rc = send(socket, buffer, size, flags);
551
552 if (rc < 0)
553 {
554 psock_errno("send()");
555 return -1;
556 }
557
558 if (rc != size)
559 return 1;
560
561 return 0;
562 }
563
recv_data(int socket,void * buffer,size_t size,int flags)564 int recv_data(int socket, void *buffer, size_t size, int flags)
565 {
566 ssize_t rc = recv(socket, buffer, size, flags);
567
568 if (rc < 0)
569 {
570 psock_errno("recv()");
571 return -1;
572 }
573
574 if (rc != size)
575 return 1;
576
577 return 0;
578 }
579
580 const int sobufsize = 131072;
581 int nPort = DEFAULTPORT;
582 int nAuxPort = DEFAULTPORT + 1;
583 #ifdef USE_IPV6
584 struct in6_addr addr_server;
585 struct in6_addr addr_local;
586 #else
587 struct in_addr addr_server;
588 struct in_addr addr_local;
589 #endif
590
591 int udpsocket, udpd;
592 unsigned long nUDPCount;
593 long long nUDPData;
594
TCP_Server(void * arg)595 THREAD TCP_Server(void *arg)
596 {
597 char *cBuffer;
598 CONTROL ctl;
599 TIMER nTimer;
600 long nTime;
601 long long nData;
602 #ifdef USE_IPV6
603 struct sockaddr_in6 sa_server, sa_client;
604 #else
605 struct sockaddr_in sa_server, sa_client;
606 #endif
607 int server, client;
608 socklen_type length;
609 struct timeval tv;
610 fd_set fds;
611 int rc;
612 int nByte;
613 int flag = 1;
614
615 if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
616 {
617 perror("malloc()");
618 return THREADRESULT;
619 }
620
621 #ifdef USE_IPV6
622 if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
623 #else
624 if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
625 #endif
626 {
627 psock_errno("socket()");
628 free(cBuffer);
629 return THREADRESULT;
630 }
631
632 setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
633 setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
634 setsockopt(server, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
635
636 #ifdef USE_IPV6
637 sa_server.sin6_family = AF_INET6;
638 sa_server.sin6_port = htons(nPort);
639 sa_server.sin6_addr = addr_local;
640 #else
641 sa_server.sin_family = AF_INET;
642 sa_server.sin_port = htons(nPort);
643 sa_server.sin_addr = addr_local;
644 #endif
645
646 if (bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
647 {
648 psock_errno("bind()");
649 soclose(server);
650 free(cBuffer);
651 return THREADRESULT;
652 }
653
654 if (listen(server, 2) != 0)
655 {
656 psock_errno("listen()");
657 soclose(server);
658 free(cBuffer);
659 return THREADRESULT;
660 }
661
662 for (;;)
663 {
664 printf("TCP server listening.\n");
665
666 FD_ZERO(&fds);
667 FD_SET(server, &fds);
668 tv.tv_sec = 3600;
669 tv.tv_usec = 0;
670
671 if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
672 {
673 psock_errno("select()");
674 break;
675 }
676
677 if (rc == 0 || FD_ISSET(server, &fds) == 0)
678 continue;
679
680 length = sizeof(sa_client);
681 if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) == -1)
682 continue;
683
684 setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
685 setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
686
687 printf("TCP connection established ... ");
688 fflush(stdout);
689
690 for (;;)
691 {
692 if (recv_data(client, (void *) &ctl, CTLSIZE, 0))
693 break;
694
695 ctl.cmd = ntohl(ctl.cmd);
696 ctl.data = ntohl(ctl.data);
697
698 if (ctl.cmd == CMD_C2S)
699 {
700 StartTimer(&nTimer);
701
702 printf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data));
703 nData = 0;
704
705 do
706 {
707 for (nByte = 0; nByte < ctl.data; )
708 {
709 rc = recv(client, cBuffer + nByte, ctl.data - nByte, 0);
710
711 if (rc < 0 && errno != EINTR)
712 {
713 psock_errno("recv()");
714 break;
715 }
716
717 if (rc > 0)
718 nByte += rc;
719 }
720
721 nData += ctl.data;
722 }
723 while (cBuffer[0] == 0 && rc > 0);
724
725 if ((nTime = StopTimer(&nTimer, 1024)) != -1)
726 print_result(nData, nTime);
727 }
728 else if (ctl.cmd == CMD_S2C)
729 {
730 if (StartAlarm(INTERVAL) == 0)
731 {
732 StartTimer(&nTimer);
733
734 printf("\nSending to client, packet size %s ... ", PacketSize(ctl.data));
735 cBuffer[0] = 0;
736 nData = 0;
737
738 while (!bTimeOver)
739 {
740 //GenerateRandomData(cBuffer, ctl.data);
741
742 for (nByte = 0; nByte < ctl.data; )
743 {
744 rc = send(client, cBuffer + nByte, ctl.data - nByte, 0);
745
746 if (rc < 0 && errno != EINTR)
747 {
748 psock_errno("send()");
749 break;
750 }
751
752 if (rc > 0)
753 nByte += rc;
754 }
755
756 nData += ctl.data;
757 }
758
759 cBuffer[0] = 1;
760
761 if (send_data(client, cBuffer, ctl.data, 0))
762 break;
763
764 if ((nTime = StopTimer(&nTimer, 1024)) != -1)
765 print_result(nData, nTime);
766 }
767 }
768 else /* quit */
769 break;
770 }
771
772 printf("\nDone.\n");
773
774 soclose(client);
775
776 if (rc < 0)
777 break;
778 }
779
780 soclose(server);
781 free(cBuffer);
782
783 return THREADRESULT;
784 }
785
TCP_Bench(void * arg)786 void TCP_Bench(void *arg)
787 {
788 char *cBuffer;
789 CONTROL ctl;
790 TIMER nTimer;
791 long nTime;
792 long long nData;
793 int i;
794 #ifdef USE_IPV6
795 struct sockaddr_in6 sa_server, sa_client;
796 #else
797 struct sockaddr_in sa_server, sa_client;
798 #endif
799 int server;
800 int rc;
801 int nByte;
802 int flag = 1;
803
804 if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
805 {
806 perror("malloc()");
807 return;
808 }
809
810 #ifdef USE_IPV6
811 if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
812 #else
813 if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
814 #endif
815 {
816 psock_errno("socket()");
817 free(cBuffer);
818 return;
819 }
820
821 setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
822 setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
823 setsockopt(server, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
824
825 #ifdef USE_IPV6
826 sa_client.sin6_family = AF_INET6;
827 sa_client.sin6_port = htons(0);
828 sa_client.sin6_addr = addr_local;
829 #else
830 sa_client.sin_family = AF_INET;
831 sa_client.sin_port = htons(0);
832 sa_client.sin_addr = addr_local;
833 #endif
834
835 if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
836 {
837 psock_errno("bind()");
838 soclose(server);
839 free(cBuffer);
840 return;
841 }
842
843 #ifdef USE_IPV6
844 sa_server.sin6_family = AF_INET6;
845 sa_server.sin6_port = htons(nPort);
846 sa_server.sin6_addr = addr_server;
847 #else
848 sa_server.sin_family = AF_INET;
849 sa_server.sin_port = htons(nPort);
850 sa_server.sin_addr = addr_server;
851 #endif
852
853 if (connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
854 {
855 psock_errno("connect()");
856 soclose(server);
857 free(cBuffer);
858 return;
859 }
860
861 printf("\nTCP connection established.\n");
862
863 for (i = 0; i < ntSizes; i++)
864 {
865 printf("Packet size %s bytes: ", PacketSize(tSizes[i]));
866 fflush(stdout);
867
868 /* tell the server we will send it data now */
869
870 ctl.cmd = htonl(CMD_C2S);
871 ctl.data = htonl(tSizes[i]);
872
873 if (send_data(server, (void *) &ctl, CTLSIZE, 0))
874 break;
875
876 /* 1 - Tx test */
877
878 if (StartAlarm(INTERVAL) == 0)
879 {
880 StartTimer(&nTimer);
881 nData = 0;
882 cBuffer[0] = 0;
883
884 while (!bTimeOver)
885 {
886 //GenerateRandomData(cBuffer, tSizes[i]);
887
888 for (nByte = 0; nByte < tSizes[i]; )
889 {
890 rc = send(server, cBuffer + nByte, tSizes[i] - nByte, 0);
891
892 if (rc < 0 && errno != EINTR)
893 {
894 psock_errno("send()");
895 break;
896 }
897
898 if (rc > 0)
899 nByte += rc;
900 }
901
902 nData += tSizes[i];
903 }
904
905 if ((nTime = StopTimer(&nTimer, 1024)) == -1)
906 printf(" (failed)");
907 else
908 print_result(nData, nTime);
909
910 printf(" Tx, ");
911 fflush(stdout);
912
913 cBuffer[0] = 1;
914
915 if (send_data(server, cBuffer, tSizes[i], 0))
916 break;
917 }
918
919 /* tell the server we expect him to send us data now */
920
921 ctl.cmd = htonl(CMD_S2C);
922 ctl.data = htonl(tSizes[i]);
923
924 if (send_data(server, (void *) &ctl, CTLSIZE, 0))
925 break;
926
927 /* 2 - Rx test */
928
929 StartTimer(&nTimer);
930 nData = 0;
931
932 do
933 {
934 for (nByte = 0; nByte < tSizes[i]; )
935 {
936 rc = recv(server, cBuffer + nByte, tSizes[i] - nByte, 0);
937
938 if (rc < 0 && errno != EINTR)
939 {
940 psock_errno("recv()");
941 break;
942 }
943
944 if (rc > 0)
945 nByte += rc;
946 }
947
948 nData += tSizes[i];
949 }
950 while (cBuffer[0] == 0 && rc > 0);
951
952 if ((nTime = StopTimer(&nTimer, 1024)) == -1)
953 printf(" (failed)");
954 else
955 print_result(nData, nTime);
956
957 printf(" Rx.\n");
958 }
959
960 ctl.cmd = htonl(CMD_QUIT);
961 ctl.data = 0;
962
963 send_data(server, (void *) &ctl, CTLSIZE, 0);
964
965 printf("Done.\n");
966
967 soclose(server);
968 free(cBuffer);
969 }
970
UDP_Receiver(void * arg)971 THREAD UDP_Receiver(void *arg)
972 {
973 char *cBuffer;
974 #ifdef USE_IPV6
975 struct sockaddr_in6 sa_server, sa_client;
976 #else
977 struct sockaddr_in sa_server, sa_client;
978 #endif
979 int rc;
980 socklen_type nBytes;
981
982 if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
983 {
984 perror("malloc()");
985 return THREADRESULT;
986 }
987
988 #ifdef USE_IPV6
989 if ((udpsocket = socket(PF_INET6, SOCK_DGRAM, 0)) < 0)
990 #else
991 if ((udpsocket = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
992 #endif
993 {
994 psock_errno("socket(DGRAM)");
995 free(cBuffer);
996 return THREADRESULT;
997 }
998
999 setsockopt(udpsocket, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
1000 setsockopt(udpsocket, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
1001
1002 #ifdef USE_IPV6
1003 sa_server.sin6_family = AF_INET6;
1004 sa_server.sin6_port = htons(nAuxPort);
1005 sa_server.sin6_addr = addr_local;
1006 #else
1007 sa_server.sin_family = AF_INET;
1008 sa_server.sin_port = htons(nAuxPort);
1009 sa_server.sin_addr = addr_local;
1010 #endif
1011
1012 if (bind(udpsocket, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
1013 {
1014 psock_errno("bind(DGRAM)");
1015 soclose(udpsocket);
1016 free(cBuffer);
1017 return THREADRESULT;
1018 }
1019
1020 udpd = 1;
1021
1022 for (;;)
1023 {
1024 nBytes = sizeof(sa_client);
1025 rc = recvfrom(udpsocket, cBuffer, TMAXSIZE, 0, (struct sockaddr *) &sa_client, &nBytes);
1026
1027 if (rc < 0 && errno != EINTR)
1028 psock_errno("recvfrom()");
1029
1030 if (rc > 0)
1031 {
1032 nUDPCount++;
1033 nUDPData += rc;
1034 }
1035 }
1036
1037 soclose(udpsocket);
1038 free(cBuffer);
1039
1040 return THREADRESULT;
1041 }
1042
UDP_Server(void * arg)1043 THREAD UDP_Server(void *arg)
1044 {
1045 char *cBuffer;
1046 CONTROL ctl;
1047 TIMER nTimer;
1048 long nTime;
1049 long long nData;
1050 #ifdef USE_IPV6
1051 struct sockaddr_in6 sa_server, sa_client;
1052 #else
1053 struct sockaddr_in sa_server, sa_client;
1054 #endif
1055 int server, client;
1056 struct timeval tv;
1057 fd_set fds;
1058 int rc, nByte;
1059 socklen_type nLength;
1060
1061 if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
1062 {
1063 perror("malloc()");
1064 return THREADRESULT;
1065 }
1066
1067 #ifdef USE_IPV6
1068 if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
1069 #else
1070 if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
1071 #endif
1072 {
1073 psock_errno("socket(STREAM)");
1074 free(cBuffer);
1075 return THREADRESULT;
1076 }
1077
1078 setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
1079 setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
1080
1081 #ifdef USE_IPV6
1082 sa_server.sin6_family = AF_INET6;
1083 sa_server.sin6_port = htons(nAuxPort);
1084 sa_server.sin6_addr = addr_local;
1085 #else
1086 sa_server.sin_family = AF_INET;
1087 sa_server.sin_port = htons(nAuxPort);
1088 sa_server.sin_addr = addr_local;
1089 #endif
1090
1091 if (bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
1092 {
1093 psock_errno("bind(STREAM)");
1094 soclose(server);
1095 free(cBuffer);
1096 return THREADRESULT;
1097 }
1098
1099 if (listen(server, 2) != 0)
1100 {
1101 psock_errno("listen()");
1102 soclose(server);
1103 free(cBuffer);
1104 return THREADRESULT;
1105 }
1106
1107 for (;;)
1108 {
1109 printf("UDP server listening.\n");
1110
1111 FD_ZERO(&fds);
1112 FD_SET(server, &fds);
1113 tv.tv_sec = 3600;
1114 tv.tv_usec = 0;
1115
1116 if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
1117 {
1118 psock_errno("select()");
1119 break;
1120 }
1121
1122 if (rc == 0 || FD_ISSET(server, &fds) == 0)
1123 continue;
1124
1125 nLength = sizeof(sa_client);
1126 if ((client = accept(server, (struct sockaddr *) &sa_client, &nLength)) == -1)
1127 continue;
1128
1129 setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
1130 setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
1131
1132 printf("UDP connection established ... ");
1133 fflush(stdout);
1134
1135 #ifdef USE_IPV6
1136 sa_client.sin6_port = htons(nAuxPort);
1137 #else
1138 sa_client.sin_port = htons(nAuxPort);
1139 #endif
1140
1141 for (;;)
1142 {
1143 if (recv_data(client, (void *) &ctl, CTLSIZE, 0))
1144 break;
1145
1146 ctl.cmd = ntohl(ctl.cmd);
1147 ctl.data = ntohl(ctl.data);
1148
1149 if (ctl.cmd == CMD_C2S)
1150 {
1151 StartTimer(&nTimer);
1152 nUDPCount = 0;
1153 nUDPData = 0;
1154
1155 printf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data));
1156
1157 ctl.cmd = htonl(ctl.cmd);
1158 ctl.data = htonl(ctl.data);
1159
1160 if (send_data(client, (void *) &ctl, CTLSIZE, 0))
1161 break;
1162 }
1163 else if (ctl.cmd == CMD_RES)
1164 {
1165 ctl.cmd = htonl(ctl.cmd);
1166 ctl.data = htonl(nUDPCount);
1167
1168 if (send_data(client, (void *) &ctl, CTLSIZE, 0))
1169 break;
1170
1171 if ((nTime = StopTimer(&nTimer, 1024)) != -1)
1172 print_result(nUDPData, nTime);
1173 }
1174 else if (ctl.cmd == CMD_S2C)
1175 {
1176 if (StartAlarm(INTERVAL) == 0)
1177 {
1178 StartTimer(&nTimer);
1179 nData = 0;
1180
1181 printf("\nSending to client, packet size %s ... ", PacketSize(ctl.data));
1182 cBuffer[0] = 0;
1183 nLength = ctl.data;
1184
1185 ctl.cmd = htonl(CMD_RES);
1186 ctl.data = 0;
1187
1188 while (!bTimeOver)
1189 {
1190 //GenerateRandomData(cBuffer, nLength);
1191
1192 for (nByte = 0; nByte < nLength; )
1193 {
1194 do
1195 {
1196 rc = sendto(udpsocket, cBuffer + nByte, nLength - nByte, 0,
1197 (struct sockaddr *) &sa_client, sizeof(sa_client));
1198 }
1199 #ifdef ENOBUFS
1200 while (rc < 0 && errno == ENOBUFS);
1201 #else
1202 while (0);
1203 #endif
1204
1205 if (rc < 0 && errno != EINTR)
1206 {
1207 psock_errno("sendto()");
1208 break;
1209 }
1210
1211 if (rc > 0)
1212 nByte += rc;
1213 }
1214
1215 ctl.data++;
1216 nData += nLength;
1217 }
1218
1219 ctl.data = htonl(ctl.data);
1220
1221 if (send_data(client, (void *) &ctl, CTLSIZE, 0))
1222 break;
1223
1224 if ((nTime = StopTimer(&nTimer, 1024)) != -1)
1225 print_result(nData, nTime);
1226 }
1227 }
1228 else /* quit */
1229 break;
1230 }
1231
1232 printf("\nDone.\n");
1233
1234 soclose(client);
1235
1236 if (rc < 0)
1237 break;
1238 }
1239
1240 soclose(server);
1241 free(cBuffer);
1242
1243 return THREADRESULT;
1244 }
1245
UDP_Bench(void * arg)1246 void UDP_Bench(void *arg)
1247 {
1248 char *cBuffer;
1249 CONTROL ctl;
1250 TIMER nTimer;
1251 long nTime, nCount;
1252 long nResult;
1253 long long nData;
1254 int i;
1255 #ifdef USE_IPV6
1256 struct sockaddr_in6 sa_server, sa_client;
1257 #else
1258 struct sockaddr_in sa_server, sa_client;
1259 #endif
1260 int server;
1261 int rc, nByte;
1262
1263 if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
1264 {
1265 perror("malloc()");
1266 return;
1267 }
1268
1269 #ifdef USE_IPV6
1270 if ((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
1271 #else
1272 if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
1273 #endif
1274 {
1275 psock_errno("socket()");
1276 free(cBuffer);
1277 return;
1278 }
1279
1280 setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
1281 setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
1282
1283 #ifdef USE_IPV6
1284 sa_client.sin6_family = AF_INET6;
1285 sa_client.sin6_port = htons(0);
1286 sa_client.sin6_addr = addr_local;
1287 #else
1288 sa_client.sin_family = AF_INET;
1289 sa_client.sin_port = htons(0);
1290 sa_client.sin_addr = addr_local;
1291 #endif
1292
1293 if (bind(server, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
1294 {
1295 psock_errno("bind(STREAM)");
1296 soclose(server);
1297 free(cBuffer);
1298 return;
1299 }
1300
1301 #ifdef USE_IPV6
1302 sa_server.sin6_family = AF_INET6;
1303 sa_server.sin6_port = htons(nAuxPort);
1304 sa_server.sin6_addr = addr_server;
1305 #else
1306 sa_server.sin_family = AF_INET;
1307 sa_server.sin_port = htons(nAuxPort);
1308 sa_server.sin_addr = addr_server;
1309 #endif
1310
1311 if (connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
1312 {
1313 psock_errno("connect()");
1314 soclose(server);
1315 free(cBuffer);
1316 return;
1317 }
1318
1319 printf("\nUDP connection established.\n");
1320
1321 for (i = 0; i < ntSizes; i++)
1322 {
1323 printf("Packet size %s bytes: ", PacketSize(tSizes[i]));
1324 fflush(stdout);
1325
1326 /* tell the server we will send it data now */
1327
1328 ctl.cmd = htonl(CMD_C2S);
1329 ctl.data = htonl(tSizes[i]);
1330
1331 if (send_data(server, (void *) &ctl, CTLSIZE, 0))
1332 break;
1333
1334 if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
1335 break;
1336
1337 /* 1 - Tx test */
1338
1339 if (StartAlarm(INTERVAL) == 0)
1340 {
1341 StartTimer(&nTimer);
1342 nData = 0;
1343 nCount = 0;
1344 cBuffer[0] = 0;
1345
1346 while (!bTimeOver)
1347 {
1348 //GenerateRandomData(cBuffer, tSizes[i]);
1349
1350 for (nByte = 0; nByte < tSizes[i]; )
1351 {
1352 rc = sendto(udpsocket, cBuffer + nByte, tSizes[i] - nByte, 0,
1353 (struct sockaddr *) &sa_server, sizeof(sa_server));
1354
1355 if (rc < 0)
1356 {
1357 if (errno != EINTR)
1358 {
1359 psock_errno("sendto()");
1360 break;
1361 }
1362 }
1363 else
1364 nByte += rc;
1365 }
1366
1367 nData += tSizes[i];
1368 nCount++;
1369 }
1370
1371 if ((nTime = StopTimer(&nTimer, 1024)) == -1)
1372 printf(" (failed)");
1373
1374 ctl.cmd = htonl(CMD_RES);
1375
1376 if (send_data(server, (void *) &ctl, CTLSIZE, 0))
1377 break;
1378
1379 if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
1380 break;
1381
1382 ctl.data = ntohl(ctl.data);
1383 nData = (long long) tSizes[i] * ctl.data;
1384
1385 print_result(nData, nTime);
1386 nResult = (nCount - ctl.data) * 100 / nCount;
1387 printf(" (%ld%%) Tx, ", nResult);
1388 fflush(stdout);
1389 }
1390
1391 /* tell the server we expect him to send us data now */
1392
1393 ctl.cmd = htonl(CMD_S2C);
1394 ctl.data = htonl(tSizes[i]);
1395
1396 if (send_data(server, (void *) &ctl, CTLSIZE, 0))
1397 break;
1398
1399 /* 2 - Rx test */
1400
1401 StartTimer(&nTimer);
1402 nUDPCount = 0;
1403 nUDPData = 0;
1404
1405 if (recv_data(server, (void *) &ctl, CTLSIZE, 0))
1406 break;
1407
1408 if ((nTime = StopTimer(&nTimer, 1024)) == -1)
1409 printf(" (failed)");
1410
1411 ctl.data = ntohl(ctl.data);
1412
1413 print_result(nUDPData, nTime);
1414 nResult = (ctl.data - nUDPCount) * 100 / ctl.data;
1415 printf(" (%ld%%) Rx.\n", nResult);
1416 }
1417
1418 ctl.cmd = htonl(CMD_QUIT);
1419 ctl.data = 0;
1420
1421 send_data(server, (void *) &ctl, CTLSIZE, 0);
1422
1423 printf("Done.\n");
1424
1425 soclose(server);
1426 free(cBuffer);
1427 }
1428
1429 /* main / user interface */
1430
1431 int bSRV, bTCP, bUDP;
1432
handler(int sig)1433 void handler(int sig)
1434 {
1435 _exit(0);
1436 }
1437
usage(void)1438 void usage(void)
1439 {
1440 printf(
1441 "\nUsage: netio [options] [<server>]\n"
1442 "\n -s run server side of benchmark (otherwise run client)"
1443 "\n -b <size>[k] use this block size (otherwise run with 1,2,4,8,16 and 32k)"
1444 "\n -B -K -M -G force number formatting to Bytes, K, M or G Bytes\n"
1445
1446 "\n -t use TCP protocol for benchmark"
1447 "\n -u use UDP protocol for benchmark"
1448 "\n -h <addr/name> bind TCP and UDP sockets to this local host address/name"
1449 "\n defaults to all (server) or unspecified (client)"
1450 "\n -p <port> bind TCP and UDP servers to this port (default is %d)\n"
1451
1452 "\n <server> If the client side of the benchmark is running,"
1453 "\n a server name or address is required.\n"
1454
1455 "\nThe server side can run either TCP (-t) or UDP (-u) protocol or both"
1456 "\n(default, if neither -t or -u is specified). The client runs one of"
1457 "\nthese protocols only (must specify -t or -u).\n"
1458 "\n", nPort);
1459 exit(1);
1460 }
1461
main(int argc,char ** argv)1462 int main(int argc, char **argv)
1463 {
1464 char szVersion[32], *szName = 0, *szLocal = 0, *szEnd;
1465 int option;
1466 struct hostent *host;
1467 long nSize;
1468
1469 strcpy(szVersion, rcsrev + sizeof("$Revision: ") - 1);
1470 *strchr(szVersion, ' ') = 0;
1471
1472 printf("\nNETIO - Network Throughput Benchmark, Version %s"
1473 "\n(C) 1997-2018 Kai Uwe Rommel\n", szVersion);
1474
1475 if (argc == 1)
1476 usage();
1477
1478 /* check arguments */
1479
1480 while ((option = getopt(argc, argv, "?stup:h:b:dBKMG")) != -1)
1481 switch (option)
1482 {
1483 case 's':
1484 bSRV = 1;
1485 break;
1486 case 't':
1487 bTCP = 1;
1488 break;
1489 case 'u':
1490 bUDP = 1;
1491 break;
1492 case 'p':
1493 nPort = atoi(optarg);
1494 nAuxPort = nPort + 1;
1495 break;
1496 case 'h':
1497 szLocal = optarg;
1498 break;
1499 case 'b':
1500 nSize = strtol(optarg, &szEnd, 10);
1501 if (*szEnd == 'k')
1502 nSize *= 1024;
1503 nSizes[0] = min(max(nSize, 1), NMAXSIZE);
1504 tSizes[0] = min(max(nSize, 1), TMAXSIZE);
1505 nnSizes = ntSizes = 1;
1506 break;
1507 #ifdef WATT32
1508 case 'd':
1509 dbug_init();
1510 break;
1511 #endif
1512 case 'B':
1513 nFormat = nf_bytes;
1514 break;
1515 case 'K':
1516 nFormat = nf_kbytes;
1517 break;
1518 case 'M':
1519 nFormat = nf_mbytes;
1520 break;
1521 case 'G':
1522 nFormat = nf_gbytes;
1523 break;
1524 default:
1525 usage();
1526 break;
1527 }
1528
1529 if (bSRV == 1 && bTCP == 0 && bUDP == 0)
1530 bTCP = bUDP = 1;
1531
1532 /* initialize TCP/IP */
1533
1534 if (bTCP || bUDP)
1535 {
1536 if (sock_init())
1537 return psock_errno("sock_init()"), 1;
1538
1539 if (szLocal == 0)
1540 #ifdef USE_IPV6
1541 addr_local = in6addr_any;
1542 #else
1543 addr_local.s_addr = INADDR_ANY;
1544 #endif
1545 else
1546 {
1547 if (isdigit(*szLocal))
1548 #ifdef USE_IPV6
1549 inet_pton(AF_INET6, szLocal, &addr_local);
1550 #else
1551 addr_local.s_addr = inet_addr(szLocal);
1552 #endif
1553 else
1554 {
1555 if ((host = gethostbyname(szLocal)) == NULL)
1556 return psock_errno("gethostbyname()"), 1;
1557
1558 #ifdef USE_IPV6
1559 addr_local = * (struct in6_addr *) (host->h_addr);
1560 #else
1561 addr_local = * (struct in_addr *) (host->h_addr);
1562 #endif
1563 }
1564 }
1565
1566 if (!bSRV)
1567 {
1568 if (optind == argc)
1569 usage();
1570
1571 if (isdigit(*argv[optind]))
1572 #ifdef USE_IPV6
1573 inet_pton(AF_INET6, argv[optind], &addr_server);
1574 #else
1575 addr_server.s_addr = inet_addr(argv[optind]);
1576 #endif
1577 else
1578 {
1579 if ((host = gethostbyname(argv[optind])) == NULL)
1580 return psock_errno("gethostbyname()"), 1;
1581
1582 #ifdef USE_IPV6
1583 addr_server = * (struct in6_addr *) (host->h_addr);
1584 #else
1585 addr_server = * (struct in_addr *) (host->h_addr);
1586 #endif
1587 }
1588 }
1589 }
1590
1591 /* do work */
1592
1593 signal(SIGINT, handler);
1594
1595 if (bSRV)
1596 {
1597 printf("\n");
1598
1599 if (bTCP)
1600 {
1601 if (newthread(TCP_Server))
1602 return printf("Cannot create additional thread.\n"), 2;
1603 }
1604 if (bUDP)
1605 {
1606 if (newthread(UDP_Receiver))
1607 return printf("Cannot create additional thread.\n"), 2;
1608 if (newthread(UDP_Server))
1609 return printf("Cannot create additional thread.\n"), 2;
1610 }
1611
1612 for (;;) sleep(86400);
1613 }
1614 else
1615 {
1616 if (bTCP + bUDP > 1) /* exactly one only */
1617 usage();
1618
1619 if (bTCP)
1620 TCP_Bench(0);
1621 else if (bUDP)
1622 {
1623 if (newthread(UDP_Receiver))
1624 return printf("Cannot create additional thread.\n"), 2;
1625 while (udpd == 0) sleep(1);
1626 UDP_Bench(0);
1627 }
1628 }
1629
1630 /* terminate */
1631
1632 printf("\n");
1633
1634 return 0;
1635 }
1636
1637 /* end of netio.c */
1638