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