home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / netio113.zip / netio.c < prev    next >
C/C++ Source or Header  |  2001-03-28  |  16KB  |  816 lines

  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.13 2001/03/26 11:37:41 Rommel Exp Rommel $";
  9. static char *rcsrev = "$Revision: 1.13 $";
  10.  
  11. /*
  12.  * $Log: netio.c,v $
  13.  * Revision 1.13  2001/03/26 11:37:41  Rommel
  14.  * avoid integer overflows during throughput calculation
  15.  *
  16.  * Revision 1.12  2000/12/01 15:57:57  Rommel
  17.  * *** empty log message ***
  18.  *
  19.  * Revision 1.11  2000/03/01 12:21:47  rommel
  20.  * fixed _INTEGRAL_MAX_BITS problem for WIN32
  21.  *
  22.  * Revision 1.10  1999/10/28 17:36:57  rommel
  23.  * fixed OS/2 timer code
  24.  *
  25.  * Revision 1.9  1999/10/28 17:04:12  rommel
  26.  * fixed timer code
  27.  *
  28.  * Revision 1.8  1999/10/24 19:08:20  rommel
  29.  * imported DOS support from G. Vanem <giva@bgnett.no>
  30.  *
  31.  *
  32.  * Revision 1.8  1999/10/12 11:02:00  giva
  33.  * added Watt-32 with djgpp support. Added debug mode.
  34.  * G. Vanem <giva@bgnett.no>
  35.  *
  36.  * Revision 1.7  1999/06/13 18:42:25  rommel
  37.  * added Linux port with patches from Detlef Plotzky <plo@bvu.de>
  38.  *
  39.  * Revision 1.6  1998/10/12 11:14:58  rommel
  40.  * change to malloc'ed (and tiled) memory for transfer buffers
  41.  * (hint from Guenter Kukkukk <kukuk@berlin.snafu.de>)
  42.  * for increased performance
  43.  *
  44.  * Revision 1.5  1998/07/31 14:15:03  rommel
  45.  * added random buffer data
  46.  * fixed bugs
  47.  *
  48.  * Revision 1.4  1997/09/12 17:35:04  rommel
  49.  * termination bug fixes
  50.  *
  51.  * Revision 1.3  1997/09/12 12:00:15  rommel
  52.  * added Win32 port
  53.  * (tested for Windows NT only)
  54.  *
  55.  * Revision 1.2  1997/09/12 10:44:22  rommel
  56.  * added TCP/IP and a command line interface
  57.  *
  58.  * Revision 1.1  1996/09/25 08:42:29  rommel
  59.  * Initial revision
  60.  *
  61.  */
  62.  
  63. #ifdef WIN32
  64. #define _INTEGRAL_MAX_BITS 64
  65. #endif
  66.  
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <ctype.h>
  71. #include <signal.h>
  72. #if defined(LINUX) || defined(DJGPP)
  73. #include <sys/time.h>
  74. #include <unistd.h>
  75. #include <errno.h>
  76. #else
  77. #include <process.h>
  78. #include "getopt.h"
  79. #include "netbios.h"
  80. #endif
  81.  
  82. /* TCP/IP system specific details */
  83.  
  84. #ifdef OS2
  85. #define BSD_SELECT
  86. #include <types.h>
  87. #include <netinet/in.h>
  88. #include <sys/select.h>
  89. #include <sys/socket.h>
  90. #include <sys/time.h>
  91. #include <netdb.h>
  92. #endif
  93.  
  94. #ifdef WATT32
  95. #include <tcp.h>       /* sock_init() etc. */
  96. #include <netinet/in.h>
  97. #include <sys/socket.h>
  98. #include <netdb.h>
  99. #define soclose     close_s
  100. #define select      select_s
  101. #define psock_errno perror
  102. #endif
  103.  
  104. #ifdef WIN32
  105. #include <windows.h>
  106. #include <winsock.h>
  107. #define soclose closesocket
  108.  
  109. int sock_init(void)
  110. {
  111.   WSADATA wsaData;
  112.   return WSAStartup(MAKEWORD(1, 1), &wsaData);
  113. }
  114.  
  115. void psock_errno(char *text)
  116. {
  117.   int rc = WSAGetLastError();
  118.   printf("%s: error code %d\n", text, rc);
  119. }
  120.  
  121. #endif
  122.  
  123. #ifdef LINUX
  124.  
  125. #include <sys/types.h>
  126. #include <sys/socket.h>
  127. #include <sys/time.h>
  128. #include <netinet/in.h>
  129. #include <netdb.h>
  130.  
  131. #define psock_errno(x) perror(x)
  132. #define soclose(x) close(x)
  133.  
  134. int sock_init(void)
  135. {
  136.   return 0;
  137. }
  138.  
  139. #endif
  140.  
  141. /* global data */
  142.  
  143. #define THREADSTACK 65536
  144.  
  145. int nSizes[] = {1024, 2048, 4096, 8192, 16384, 32768};
  146. #define NSIZES (sizeof(nSizes) / sizeof(int))
  147. #define NMAXSIZE 32768
  148.  
  149. int tSizes[] = {1024, 2048, 4096, 8192, 16384, 32767};
  150. #define TSIZES (sizeof(tSizes) / sizeof(int))
  151. #define TMAXSIZE 32767
  152.  
  153. #define INTERVAL 10
  154.  
  155. /* timer code */
  156.  
  157. int bTimeOver;
  158.  
  159. #ifdef OS2
  160.  
  161. #define INCL_DOS
  162. #define INCL_NOPM
  163. #include <os2.h>
  164.  
  165. typedef QWORD TIMER;
  166.  
  167. void APIENTRY TimerThread(ULONG nArg)
  168. {
  169.   HEV hSem;
  170.   HTIMER hTimer;
  171.  
  172.   DosCreateEventSem(0, &hSem, DC_SEM_SHARED, 0);
  173.  
  174.   DosAsyncTimer(nArg * 1000, (HSEM) hSem, &hTimer);
  175.   DosWaitEventSem(hSem, SEM_INDEFINITE_WAIT);
  176.   DosStopTimer(hTimer);
  177.  
  178.   DosCloseEventSem(hSem);
  179.  
  180.   bTimeOver = 1;
  181.  
  182.   DosExit(EXIT_THREAD, 0);
  183. }
  184.  
  185. int StartAlarm(long nSeconds)
  186. {
  187.   TID ttid;
  188.  
  189.   bTimeOver = 0;
  190.  
  191.   if (DosCreateThread(&ttid, TimerThread, nSeconds, 0, THREADSTACK))
  192.     return printf("Cannot create timer thread.\n"), -1;
  193.  
  194.   return 0;
  195. }
  196.  
  197. int StartTimer(TIMER *nStart)
  198. {
  199.   if (DosTmrQueryTime(nStart))
  200.     return printf("Timer error.\n"), -1;
  201.  
  202.   return 0;
  203. }
  204.  
  205. long StopTimer(TIMER *nStart, int nAccuracy)
  206. {
  207.   TIMER nStop;
  208.   ULONG nFreq;
  209.  
  210.   if (DosTmrQueryTime(&nStop))
  211.     return printf("Timer error.\n"), -1;
  212.   if (DosTmrQueryFreq(&nFreq))
  213.     return printf("Timer error.\n"), -1;
  214.  
  215.   nFreq = (nFreq + nAccuracy / 2) / nAccuracy;
  216.  
  217.   return (* (__int64*) &nStop - * (__int64*) nStart) / nFreq;
  218. }
  219.  
  220. #endif
  221.  
  222. #ifdef WIN32
  223.  
  224. typedef LARGE_INTEGER TIMER;
  225.  
  226. DWORD CALLBACK TimerThread(void * pArg)
  227. {
  228.   Sleep((long) pArg * 1000);
  229.   bTimeOver = 1;
  230.  
  231.   return 0;
  232. }
  233.  
  234. int StartAlarm(long nSeconds)
  235. {
  236.   DWORD ttid;
  237.  
  238.   bTimeOver = 0;
  239.  
  240.   if (CreateThread(0, THREADSTACK, TimerThread, (void *) nSeconds, 0, &ttid) == NULL)
  241.     return printf("Cannot create timer thread.\n"), -1;
  242.  
  243.   return 0;
  244. }
  245.  
  246. int StartTimer(TIMER *nStart)
  247. {
  248.   if (!QueryPerformanceCounter(nStart))
  249.     return printf("Timer error.\n"), -1;
  250.  
  251.   return 0;
  252. }
  253.  
  254. long StopTimer(TIMER *nStart, int nAccuracy)
  255. {
  256.   TIMER nStop, nFreq;
  257.  
  258.   if (!QueryPerformanceCounter(&nStop))
  259.     return printf("Timer error.\n"), -1;
  260.   if (!QueryPerformanceFrequency(&nFreq))
  261.     return printf("Timer error.\n"), -1;
  262.  
  263.   nFreq.QuadPart = (nFreq.QuadPart + nAccuracy / 2) / nAccuracy;
  264.  
  265.   return (nStop.QuadPart - nStart->QuadPart) / nFreq.QuadPart;
  266. }
  267.  
  268. #endif
  269.  
  270. #if defined(LINUX) || defined(DJGPP)
  271.  
  272. typedef struct timeval TIMER;
  273.  
  274. void on_alarm(int signum)
  275. {
  276.   alarm(0);
  277.   bTimeOver = 1;
  278. }
  279.  
  280. int StartAlarm(long nSeconds)
  281. {
  282.   bTimeOver = 0;
  283.   signal(SIGALRM, on_alarm);
  284.   alarm(nSeconds);
  285. }
  286.  
  287. int StartTimer(TIMER *nStart)
  288. {
  289.   struct timezone tz = {0, 0};
  290.  
  291.   gettimeofday(nStart, &tz);
  292.  
  293.   return 0;
  294. }
  295.  
  296. long StopTimer(TIMER *nStart, int nAccuracy)
  297. {
  298.   struct timezone tz = {0, 0};
  299.   TIMER nStop;
  300.  
  301.   gettimeofday(&nStop, &tz);
  302.  
  303.   return (nStop.tv_sec - nStart->tv_sec) * nAccuracy 
  304.        + (nStop.tv_usec - nStart->tv_usec) * nAccuracy / 1000000;
  305. }
  306. #endif /* LINUX || DJGPP */
  307.  
  308. /* initialize data to transfer */
  309.  
  310. char *InitBuffer(int nSize)
  311. {
  312.   char *cBuffer = malloc(nSize);
  313.  
  314.   if (cBuffer != NULL)
  315.   {
  316.     int i;
  317.  
  318.     cBuffer[0] = 0;
  319.     srand(1);
  320.  
  321.     for (i = 1; i < nSize; i++)
  322.       cBuffer[i] = (char) rand();
  323.   }
  324.  
  325.   return cBuffer;
  326. }
  327.  
  328. /* NetBIOS code */
  329.  
  330. #ifdef USE_NETBIOS
  331.  
  332. char *ServerName = "NETIOSRV";
  333. char *ClientName = "NETIOCLT";
  334. USHORT nAdapter = 0;
  335.  
  336. NCB WorkNcb;
  337. USHORT nLSN, rc;
  338.  
  339. void NetBiosServer(void *arg)
  340. {
  341.   char *cBuffer;
  342.   int bQuit = 0;
  343.  
  344.   if ((cBuffer = InitBuffer(NMAXSIZE)) == NULL)
  345.   {
  346.     perror("malloc()");
  347.     return;
  348.   }
  349.  
  350.   if ((rc = NCBAddName(&WorkNcb, nAdapter, ServerName)) != 0 && rc != 13)
  351.   {
  352.     printf("NetBIOS AddName Failed, rc=0x%02X\n", rc);
  353.     free(cBuffer);
  354.     return;
  355.   }
  356.  
  357.   for (;;)
  358.   {
  359.     printf("NetBIOS server Listening.\n");
  360.  
  361.     if ((rc = NCBListen(&WorkNcb, nAdapter, ServerName, "*", 0, 0, TRUE)) != 0)
  362.     {
  363.       printf("NetBIOS Listen failed, rc=0x%02X\n", rc);
  364.       break;
  365.     }
  366.  
  367.     nLSN = WorkNcb.basic_ncb.bncb.ncb_lsn;
  368.  
  369.     printf("NetBIOS connection established ... ");
  370.     fflush(stdout);
  371.  
  372.     while ((rc = NCBReceive(&WorkNcb, nAdapter, nLSN,
  373.                     cBuffer, NMAXSIZE, TRUE)) == 0
  374.        || rc == NB_MESSAGE_INCOMPLETE);
  375.  
  376.     if (rc != 0 && rc != NB_SESSION_CLOSED)
  377.       printf("NetBIOS Receive Failed, rc=0x%02X\n", rc);
  378.  
  379.     rc = NCBHangup(&WorkNcb, nAdapter, nLSN);
  380.  
  381.     printf("done.\n");
  382.     fflush(stdout);
  383.  
  384.     if (bQuit)
  385.       break;
  386.   }
  387.  
  388.   NCBDeleteName(&WorkNcb, nAdapter, ServerName);
  389.  
  390.   free(cBuffer);
  391. }
  392.  
  393. void NetBiosBench(void *arg)
  394. {
  395.   char *cBuffer;
  396.   TIMER nTimer;
  397.   long nTime;
  398.   long nData;
  399.   int i;
  400.  
  401.   if ((cBuffer = InitBuffer(NMAXSIZE)) == NULL)
  402.   {
  403.     perror("malloc()");
  404.     return;
  405.   }
  406.  
  407.   if ((rc = NCBAddName(&WorkNcb, nAdapter, ClientName)) != 0 && rc != 13)
  408.   {
  409.     printf("NetBIOS AddName Failed, rc=0x%02X\n", rc);
  410.     free(cBuffer);
  411.     return;
  412.   }
  413.  
  414.   if ((rc = NCBCall(&WorkNcb, nAdapter, ClientName, ServerName, 0, 0, TRUE)) != 0)
  415.     printf("NetBIOS Call failed, rc=0x%02X\n", rc);
  416.   else
  417.   {
  418.     nLSN = WorkNcb.basic_ncb.bncb.ncb_lsn;
  419.  
  420.     printf("\nNetBIOS connection established.\n");
  421.  
  422.     for (i = 0; i < NSIZES; i++)
  423.     {
  424.       printf("Packet size %2d KByte: ", (nSizes[i] + 512) / 1024);
  425.       fflush(stdout);
  426.  
  427.       nData = 0;
  428.  
  429.       if (StartAlarm(INTERVAL) == 0 && StartTimer(&nTimer) == 0)
  430.       {
  431.     while (!bTimeOver)
  432.     {
  433.       if ((rc = NCBSend(&WorkNcb, nAdapter, nLSN,
  434.                 cBuffer, nSizes[i], TRUE)) != 0)
  435.       {
  436.         printf("NetBIOS Send Failed, rc=0x%02X\n", rc);
  437.         break;
  438.       }
  439.  
  440.       nData++;
  441.     }
  442.  
  443.     if ((nTime = StopTimer(&nTimer, 1024)) == -1)
  444.       printf("Timing failed.\n");
  445.     else
  446.       if (nData < 100 * 1024 * INTERVAL / nSizes[i])
  447.         printf("  %.0f Byte/s\n", (double) nData * nSizes[i] * 1024 / nTime);
  448.       else
  449.         printf("  %.0f KByte/s\n", (double) nData * nSizes[i] / nTime);
  450.       }
  451.     }
  452.  
  453.     rc = NCBHangup(&WorkNcb, nAdapter, nLSN);
  454.   }
  455.  
  456.   NCBDeleteName(&WorkNcb, nAdapter, ClientName);
  457.  
  458.   free(cBuffer);
  459. }
  460.  
  461. #endif /* USE_NETBIOS */
  462.  
  463. /* TCP/IP code */
  464.  
  465. int nPort = 0x494F; /* "IO" */
  466. struct in_addr addr_server;
  467.  
  468. void TcpIpServer(void *arg)
  469. {
  470.   char *cBuffer;
  471.   int bQuit = 0;
  472.   struct sockaddr_in sa_server, sa_client;
  473.   int server, client, length;
  474.   struct timeval tv;
  475.   fd_set fds;
  476.   int rc;
  477.  
  478.   if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
  479.   {
  480.     perror("malloc()");
  481.     return;
  482.   }
  483.  
  484.   if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  485.   {
  486.     psock_errno("socket()");
  487.     free(cBuffer);
  488.     return;
  489.   }
  490.  
  491.   sa_server.sin_family = AF_INET;
  492.   sa_server.sin_port = htons(nPort);
  493.   sa_server.sin_addr.s_addr = INADDR_ANY;
  494.  
  495.   if (bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
  496.   {
  497.     psock_errno("bind()");
  498.     soclose(server);
  499.     free(cBuffer);
  500.     return;
  501.   }
  502.  
  503.   if (listen(server, 2) != 0)
  504.   {
  505.     psock_errno("listen()");
  506.     soclose(server);
  507.     free(cBuffer);
  508.     return;
  509.   }
  510.  
  511.   for (;;)
  512.   {
  513.     printf("TCP/IP server Listening.\n");
  514.  
  515.     FD_ZERO(&fds);
  516.     FD_SET(server, &fds);
  517.     tv.tv_sec  = 3600;
  518.     tv.tv_usec = 0;
  519.  
  520.     if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
  521.     {
  522.       psock_errno("select()");
  523.       break;
  524.     }
  525.  
  526.     if (rc == 0 || FD_ISSET(server, &fds) == 0)
  527.       continue;
  528.  
  529.     length = sizeof(sa_client);
  530.     if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) == -1)
  531.       continue;
  532.  
  533.     printf("TCP/IP connection established ... ");
  534.     fflush(stdout);
  535.  
  536.     while ((rc = recv(client, cBuffer, TMAXSIZE, 0)) > 0);
  537.  
  538.     if (rc == -1)
  539.     {
  540.       psock_errno("recv()");
  541.       bQuit = 1;
  542.     }
  543.     else
  544.       printf("done.\n");
  545.  
  546.     soclose(client);
  547.  
  548.     if (bQuit)
  549.       break;
  550.   }
  551.  
  552.   soclose(server);
  553.  
  554.   free(cBuffer);
  555. }
  556.  
  557. void TcpIpBench(void *arg)
  558. {
  559.   char *cBuffer;
  560.   TIMER nTimer;
  561.   long nTime;
  562.   long nData;
  563.   int i;
  564.   struct sockaddr_in sa_server;
  565.   int server;
  566.   int rc;
  567.  
  568.   if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
  569.   {
  570.     perror("malloc()");
  571.     return;
  572.   }
  573.  
  574.   sa_server.sin_family = AF_INET;
  575.   sa_server.sin_port = htons(nPort);
  576.   sa_server.sin_addr = addr_server;
  577.  
  578.   if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  579.   {
  580.     psock_errno("socket()");
  581.     free(cBuffer);
  582.     return;
  583.   }
  584.  
  585.   if (connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server)) < 0)
  586.   {
  587.     psock_errno("connect()");
  588.     soclose(server);
  589.     free(cBuffer);
  590.     return;
  591.   }
  592.  
  593.   printf("\nTCP/IP connection established.\n");
  594.  
  595.   for (i = 0; i < TSIZES; i++)
  596.   {
  597.     printf("Packet size %2d KByte: ", (tSizes[i] + 512) / 1024);
  598.     fflush(stdout);
  599.  
  600.     nData = 0;
  601.  
  602.     if (StartAlarm(INTERVAL) == 0 && StartTimer(&nTimer) == 0)
  603.     {
  604.       while (!bTimeOver)
  605.       {
  606.     if ((rc = send(server, cBuffer, tSizes[i], 0)) != tSizes[i] && errno != 0)
  607.     {
  608.       psock_errno("send()");
  609.       break;
  610.     }
  611.  
  612.     nData++;
  613.       }
  614.  
  615.       if ((nTime = StopTimer(&nTimer, 1024)) == -1)
  616.     printf("Timing failed.\n");
  617.       else
  618.     if (nData < 100 * 1024 * INTERVAL / tSizes[i])
  619.       printf("  %.0f Byte/s\n", (double) nData * tSizes[i] * 1024.0 / nTime);
  620.     else
  621.       printf("  %.0f KByte/s\n", (double) nData * tSizes[i] / nTime);
  622.     }
  623.   }
  624.  
  625.   soclose(server);
  626.  
  627.   free(cBuffer);
  628. }
  629.  
  630. /* main / user interface */
  631.  
  632. int bSRV, bNB, bTCP;
  633.  
  634. void handler(int sig)
  635. {
  636. #ifdef USE_NETBIOS
  637.   if (bNB)
  638.   {
  639.     NCBDeleteName(&WorkNcb, nAdapter, ServerName);
  640.     NCBDeleteName(&WorkNcb, nAdapter, ClientName);
  641.     NCBClose(&WorkNcb, nAdapter);
  642.   }
  643. #endif
  644.  
  645.   exit(0);
  646. }
  647.  
  648. void usage(void)
  649. {
  650.   printf(
  651. #ifndef USE_NETBIOS
  652.      "\nUsage: netio [-s] [-p <port>] [<server>]\n"
  653.      "\n\t-s\t\trun server side of benchmark (otherwise run client)"
  654.      "\n\t-p <port>\tuse this port instead of the default (%d)"
  655.          "\n\t<server>\tif the client side of the benchmark is running,"
  656.      "\n\t\t\ta server host name is required\n"
  657. #else
  658.      "\nUsage: netio [-s] [-t | -n] [-p <port>] [-a <adapter>] [<server>]\n"
  659.      "\n\t-s\trun server side of benchmark (otherwise run client)"
  660.      "\n\t-t\tuse TCP/IP protocol for benchmark"
  661.      "\n\t-p <port>\tuse this port for TCP/IP (default is %d)"
  662.      "\n\t-n\tuse NetBIOS protocol for benchmark\n"
  663.      "\n\t-a <adapter>\tuse this NetBIOS adapter (default is 0)\n"
  664.      "\n\t<server>\tif TCP/IP is used for the client,"
  665.      "\n\t\t\ta server host name is required\n"
  666.      "\nThe server side can run either NetBIOS (-n) or TCP/IP (-t) protocol"
  667.      "\nor both (default if neither -t or -n are specified). The client runs"
  668.      "\none of both protocols only (must specify -t or -n).\n"
  669.      "\nThe -p and -a options apply to both client and server sides."
  670. #endif
  671.      "\n", nPort);
  672.   exit(1);
  673. }
  674.  
  675. int main(int argc, char **argv)
  676. {
  677.   char szVersion[32];
  678.   int option;
  679.   struct hostent *host;
  680.  
  681.   strcpy(szVersion, rcsrev + sizeof("$Revision: ") - 1);
  682.   *strchr(szVersion, ' ') = 0;
  683.  
  684.   printf("\nNETIO - Network Throughput Benchmark, Version %s"
  685.      "\n(C) 1997-2001 Kai Uwe Rommel\n", szVersion);
  686.  
  687.   if (argc == 1)
  688.     usage();
  689.  
  690.   /* check arguments */
  691.  
  692. #ifndef USE_NETBIOS
  693.   bTCP = 1;
  694. #endif
  695.  
  696.   while ((option = getopt(argc, argv, "?stnp:a:d")) !=  -1)
  697.     switch (option)
  698.     {
  699.     case 's':
  700.       bSRV = 1;
  701.       break;
  702.     case 't':
  703.       bTCP = 1;
  704.       break;
  705.     case 'p':
  706.       nPort = atoi(optarg);
  707.       break;
  708. #ifdef USE_NETBIOS
  709.     case 'n':
  710.       bNB = 1;
  711.       break;
  712.     case 'a':
  713.       nAdapter = atoi(optarg);
  714.       break;
  715. #endif
  716. #ifdef WATT32
  717.     case 'd':
  718.       dbug_init();
  719.       break;
  720. #endif
  721.     default:
  722.       usage();
  723.       break;
  724.     }
  725.  
  726.   if (bSRV == 1 && bTCP == 0 && bNB == 0)
  727.     bTCP = bNB = 1;
  728.  
  729.   /* initialize NetBIOS and/or TCP/IP */
  730.  
  731. #ifdef USE_NETBIOS
  732.   if (bNB)
  733.   {
  734.     NetBIOS_API = NETBIOS;
  735.  
  736.     if (NetBIOS_Avail())
  737.       return printf("NetBIOS not found\n"), 1;
  738.  
  739.     if ((rc = NCBReset(&WorkNcb, nAdapter, 2, 2, 2)) != 0)
  740.       return printf("NetBIOS Reset failed, rc=0x%02X\n", rc), rc;
  741.   }
  742. #endif
  743.  
  744.   if (bTCP)
  745.   {
  746.     if (sock_init())
  747.       return psock_errno("sock_init()"), 1;
  748.  
  749.     if (!bSRV)
  750.     {
  751.       if (optind == argc)
  752.     usage();
  753.  
  754.       if (isdigit(*argv[optind]))
  755.     addr_server.s_addr = inet_addr(argv[optind]);
  756.       else
  757.       {
  758.     if ((host = gethostbyname(argv[optind])) == NULL)
  759.       return psock_errno("gethostbyname()"), 1;
  760.  
  761.     addr_server = * (struct in_addr *) (host->h_addr);
  762.       }
  763.     }
  764.   }
  765.  
  766.   /* do work */
  767.  
  768.   signal(SIGINT, handler);
  769.  
  770.   if (bSRV)
  771.   {
  772.     printf("\n");
  773.  
  774. #ifndef USE_NETBIOS
  775.     TcpIpServer(0);
  776. #else
  777.     if (bTCP && !bNB)
  778.       TcpIpServer(0);
  779.     else if (bNB && !bTCP)
  780.       NetBiosServer(0);
  781.     else
  782.     {
  783.       if (_beginthread(TcpIpServer, 0, THREADSTACK, 0) == -1)
  784.     return printf("Cannot create additional thread.\n"), 2;
  785.  
  786.       NetBiosServer(0);
  787.     }
  788. #endif
  789.   }
  790.   else
  791.   {
  792.     if ((bTCP ^ bNB) == 0) /* exactly one of both only */
  793.       usage();
  794.  
  795.     if (bTCP)
  796.       TcpIpBench(0);
  797. #ifdef USE_NETBIOS
  798.     else if (bNB)
  799.       NetBiosBench(0);
  800. #endif
  801.   }
  802.  
  803.   /* terminate */
  804.  
  805. #ifdef USE_NETBIOS
  806.   if (bNB)
  807.     NCBClose(&WorkNcb, nAdapter);
  808. #else
  809.   printf("\n");
  810. #endif
  811.  
  812.   return 0;
  813. }
  814.  
  815. /* end of netio.c */
  816.