tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

accept.c (14010B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /***********************************************************************
      7 **  1996 - Netscape Communications Corporation
      8 **
      9 ** Name: accept.c
     10 **
     11 ** Description: Run accept() sucessful connection tests.
     12 **
     13 ** Modification History:
     14 ** 04-Jun-97 AGarcia - Reconvert test file to return a 0 for PASS and a 1 for
     15 *FAIL
     16 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode
     17 **             The debug mode will print all of the printfs associated with this
     18 *test.
     19 **             The regress mode will be the default mode. Since the regress tool
     20 *limits
     21 **           the output to a one line status:PASS or FAIL,all of the printf
     22 *statements
     23 **             have been handled with an if (debug_mode) statement.
     24 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been
     25 *updated to
     26 **            recognize the return code from tha main program.
     27 ** 12-June-97 Revert to return code 0 and 1.
     28 ***********************************************************************/
     29 
     30 /***********************************************************************
     31 ** Includes
     32 ***********************************************************************/
     33 
     34 #include "nspr.h"
     35 #include "prpriv.h"
     36 
     37 #include <stdlib.h>
     38 #include <string.h>
     39 
     40 #include "plgetopt.h"
     41 #include "plerror.h"
     42 
     43 #define BASE_PORT 10000
     44 
     45 #define CLIENT_DATA 128
     46 
     47 #define ACCEPT_NORMAL 0x1
     48 #define ACCEPT_FAST 0x2
     49 #define ACCEPT_READ 0x3
     50 #define ACCEPT_READ_FAST 0x4
     51 #define ACCEPT_READ_FAST_CB 0x5
     52 
     53 #define CLIENT_NORMAL 0x1
     54 #define CLIENT_TIMEOUT_ACCEPT 0x2
     55 #define CLIENT_TIMEOUT_SEND 0x3
     56 
     57 #define SERVER_MAX_BIND_COUNT 100
     58 
     59 #define TIMEOUTSECS 2
     60 PRIntervalTime timeoutTime;
     61 
     62 static PRInt32 count = 1;
     63 static PRFileDesc* output;
     64 static PRNetAddr serverAddr;
     65 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
     66 static PRInt32 clientCommand;
     67 static PRInt32 iterations;
     68 static PRStatus rv;
     69 static PRFileDesc* listenSock;
     70 static PRFileDesc* clientSock = NULL;
     71 static PRNetAddr listenAddr;
     72 static PRNetAddr clientAddr;
     73 static PRThread* clientThread;
     74 static PRNetAddr* raddr;
     75 static char buf[4096 + 2 * sizeof(PRNetAddr) + 32];
     76 static PRInt32 status;
     77 static PRInt32 bytesRead;
     78 
     79 PRIntn failed_already = 0;
     80 PRIntn debug_mode;
     81 
     82 void Test_Assert(const char* msg, const char* file, PRIntn line) {
     83  failed_already = 1;
     84  if (debug_mode) {
     85    PR_fprintf(output, "@%s:%d ", file, line);
     86    PR_fprintf(output, msg);
     87  }
     88 } /* Test_Assert */
     89 
     90 #define TEST_ASSERT(expr) \
     91  if (!(expr)) Test_Assert(#expr, __FILE__, __LINE__)
     92 
     93 #ifdef WINNT
     94 #  define CALLBACK_MAGIC 0x12345678
     95 
     96 void timeout_callback(void* magic) {
     97  TEST_ASSERT(magic == (void*)CALLBACK_MAGIC);
     98  if (debug_mode) {
     99    PR_fprintf(output, "timeout callback called okay\n");
    100  }
    101 }
    102 #endif
    103 
    104 static void PR_CALLBACK ClientThread(void* _action) {
    105  PRInt32 action = *(PRInt32*)_action;
    106  PRInt32 iterations = count;
    107  PRFileDesc* sock = NULL;
    108 
    109  serverAddr.inet.family = PR_AF_INET;
    110  serverAddr.inet.port = listenAddr.inet.port;
    111  serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
    112 
    113  for (; iterations--;) {
    114    PRInt32 rv;
    115    char buf[CLIENT_DATA];
    116 
    117    memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */
    118    sock = PR_NewTCPSocket();
    119    if (!sock) {
    120      if (!debug_mode) {
    121        failed_already = 1;
    122      } else {
    123        PR_fprintf(output, "client: unable to create socket\n");
    124      }
    125      return;
    126    }
    127 
    128    if (action != CLIENT_TIMEOUT_ACCEPT) {
    129      if ((rv = PR_Connect(sock, &serverAddr, timeoutTime)) < 0) {
    130        if (!debug_mode) {
    131          failed_already = 1;
    132        } else
    133          PR_fprintf(
    134              output,
    135              "client: unable to connect to server (%ld, %ld, %ld, %ld)\n",
    136              iterations, rv, PR_GetError(), PR_GetOSError());
    137        goto ErrorExit;
    138      }
    139 
    140      if (action != CLIENT_TIMEOUT_SEND) {
    141        if ((rv = PR_Send(sock, buf, CLIENT_DATA, 0, timeoutTime)) < 0) {
    142          if (!debug_mode) {
    143            failed_already = 1;
    144          } else {
    145            PR_fprintf(output,
    146                       "client: unable to send to server (%d, %ld, %ld)\n",
    147                       CLIENT_DATA, rv, PR_GetError());
    148          }
    149          goto ErrorExit;
    150        }
    151      } else {
    152        PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
    153      }
    154    } else {
    155      PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
    156    }
    157    if (debug_mode) {
    158      PR_fprintf(output, ".");
    159    }
    160    PR_Close(sock);
    161    sock = NULL;
    162  }
    163  if (debug_mode) {
    164    PR_fprintf(output, "\n");
    165  }
    166 
    167 ErrorExit:
    168  if (sock != NULL) {
    169    PR_Close(sock);
    170  }
    171 }
    172 
    173 static void RunTest(PRInt32 acceptType, PRInt32 clientAction) {
    174  int i;
    175 
    176  /* First bind to the socket */
    177  listenSock = PR_NewTCPSocket();
    178  if (!listenSock) {
    179    failed_already = 1;
    180    if (debug_mode) {
    181      PR_fprintf(output, "unable to create listen socket\n");
    182    }
    183    return;
    184  }
    185  memset(&listenAddr, 0, sizeof(listenAddr));
    186  listenAddr.inet.family = PR_AF_INET;
    187  listenAddr.inet.port = PR_htons(BASE_PORT);
    188  listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
    189  /*
    190   * try a few times to bind server's address, if addresses are in
    191   * use
    192   */
    193  i = 0;
    194  while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) {
    195    if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
    196      listenAddr.inet.port += 2;
    197      if (i++ < SERVER_MAX_BIND_COUNT) {
    198        continue;
    199      }
    200    }
    201    failed_already = 1;
    202    if (debug_mode) {
    203      PR_fprintf(output, "accept: ERROR - PR_Bind failed\n");
    204    }
    205    return;
    206  }
    207 
    208  rv = PR_Listen(listenSock, 100);
    209  if (rv == PR_FAILURE) {
    210    failed_already = 1;
    211    if (debug_mode) {
    212      PR_fprintf(output, "unable to listen\n");
    213    }
    214    return;
    215  }
    216 
    217  clientCommand = clientAction;
    218  clientThread =
    219      PR_CreateThread(PR_USER_THREAD, ClientThread, (void*)&clientCommand,
    220                      PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
    221  if (!clientThread) {
    222    failed_already = 1;
    223    if (debug_mode) {
    224      PR_fprintf(output, "error creating client thread\n");
    225    }
    226    return;
    227  }
    228 
    229  iterations = count;
    230  for (; iterations--;) {
    231    switch (acceptType) {
    232      case ACCEPT_NORMAL:
    233        clientSock = PR_Accept(listenSock, &clientAddr, timeoutTime);
    234        switch (clientAction) {
    235          case CLIENT_TIMEOUT_ACCEPT:
    236            TEST_ASSERT(clientSock == 0);
    237            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    238            break;
    239          case CLIENT_NORMAL:
    240            TEST_ASSERT(clientSock);
    241            bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime);
    242            TEST_ASSERT(bytesRead == CLIENT_DATA);
    243            break;
    244          case CLIENT_TIMEOUT_SEND:
    245            TEST_ASSERT(clientSock);
    246            bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime);
    247            TEST_ASSERT(bytesRead == -1);
    248            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    249            break;
    250        }
    251        break;
    252      case ACCEPT_READ:
    253        status = PR_AcceptRead(listenSock, &clientSock, &raddr, buf,
    254                               CLIENT_DATA, timeoutTime);
    255        switch (clientAction) {
    256          case CLIENT_TIMEOUT_ACCEPT:
    257            /* Invalid test case */
    258            TEST_ASSERT(0);
    259            break;
    260          case CLIENT_NORMAL:
    261            TEST_ASSERT(clientSock);
    262            TEST_ASSERT(status == CLIENT_DATA);
    263            break;
    264          case CLIENT_TIMEOUT_SEND:
    265            TEST_ASSERT(status == -1);
    266            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    267            break;
    268        }
    269        break;
    270 #ifdef WINNT
    271      case ACCEPT_FAST:
    272        clientSock = PR_NTFast_Accept(listenSock, &clientAddr, timeoutTime);
    273        switch (clientAction) {
    274          case CLIENT_TIMEOUT_ACCEPT:
    275            TEST_ASSERT(clientSock == 0);
    276            if (debug_mode) {
    277              PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError());
    278            }
    279            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    280            break;
    281          case CLIENT_NORMAL:
    282            TEST_ASSERT(clientSock);
    283            bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime);
    284            TEST_ASSERT(bytesRead == CLIENT_DATA);
    285            break;
    286          case CLIENT_TIMEOUT_SEND:
    287            TEST_ASSERT(clientSock);
    288            bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime);
    289            TEST_ASSERT(bytesRead == -1);
    290            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    291            break;
    292        }
    293        break;
    294        break;
    295      case ACCEPT_READ_FAST:
    296        status = PR_NTFast_AcceptRead(listenSock, &clientSock, &raddr, buf,
    297                                      4096, timeoutTime);
    298        switch (clientAction) {
    299          case CLIENT_TIMEOUT_ACCEPT:
    300            /* Invalid test case */
    301            TEST_ASSERT(0);
    302            break;
    303          case CLIENT_NORMAL:
    304            TEST_ASSERT(clientSock);
    305            TEST_ASSERT(status == CLIENT_DATA);
    306            break;
    307          case CLIENT_TIMEOUT_SEND:
    308            TEST_ASSERT(clientSock == NULL);
    309            TEST_ASSERT(status == -1);
    310            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    311            break;
    312        }
    313        break;
    314      case ACCEPT_READ_FAST_CB:
    315        status = PR_NTFast_AcceptRead_WithTimeoutCallback(
    316            listenSock, &clientSock, &raddr, buf, 4096, timeoutTime,
    317            timeout_callback, (void*)CALLBACK_MAGIC);
    318        switch (clientAction) {
    319          case CLIENT_TIMEOUT_ACCEPT:
    320            /* Invalid test case */
    321            TEST_ASSERT(0);
    322            break;
    323          case CLIENT_NORMAL:
    324            TEST_ASSERT(clientSock);
    325            TEST_ASSERT(status == CLIENT_DATA);
    326            break;
    327          case CLIENT_TIMEOUT_SEND:
    328            if (debug_mode) {
    329              PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock);
    330            }
    331            TEST_ASSERT(clientSock == NULL);
    332            TEST_ASSERT(status == -1);
    333            TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
    334            break;
    335        }
    336        break;
    337 #endif
    338    }
    339    if (clientSock != NULL) {
    340      PR_Close(clientSock);
    341      clientSock = NULL;
    342    }
    343  }
    344  PR_Close(listenSock);
    345 
    346  PR_JoinThread(clientThread);
    347 }
    348 
    349 void AcceptUpdatedTest(void) { RunTest(ACCEPT_NORMAL, CLIENT_NORMAL); }
    350 void AcceptNotUpdatedTest(void) { RunTest(ACCEPT_FAST, CLIENT_NORMAL); }
    351 void AcceptReadTest(void) { RunTest(ACCEPT_READ, CLIENT_NORMAL); }
    352 void AcceptReadNotUpdatedTest(void) {
    353  RunTest(ACCEPT_READ_FAST, CLIENT_NORMAL);
    354 }
    355 void AcceptReadCallbackTest(void) {
    356  RunTest(ACCEPT_READ_FAST_CB, CLIENT_NORMAL);
    357 }
    358 
    359 void TimeoutAcceptUpdatedTest(void) {
    360  RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_ACCEPT);
    361 }
    362 void TimeoutAcceptNotUpdatedTest(void) {
    363  RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_ACCEPT);
    364 }
    365 void TimeoutAcceptReadCallbackTest(void) {
    366  RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_ACCEPT);
    367 }
    368 
    369 void TimeoutReadUpdatedTest(void) {
    370  RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_SEND);
    371 }
    372 void TimeoutReadNotUpdatedTest(void) {
    373  RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_SEND);
    374 }
    375 void TimeoutReadReadTest(void) { RunTest(ACCEPT_READ, CLIENT_TIMEOUT_SEND); }
    376 void TimeoutReadReadNotUpdatedTest(void) {
    377  RunTest(ACCEPT_READ_FAST, CLIENT_TIMEOUT_SEND);
    378 }
    379 void TimeoutReadReadCallbackTest(void) {
    380  RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_SEND);
    381 }
    382 
    383 /************************************************************************/
    384 
    385 static void Measure(void (*func)(void), const char* msg) {
    386  PRIntervalTime start, stop;
    387  double d;
    388 
    389  start = PR_IntervalNow();
    390  (*func)();
    391  stop = PR_IntervalNow();
    392 
    393  d = (double)PR_IntervalToMicroseconds(stop - start);
    394  if (debug_mode) {
    395    PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count);
    396  }
    397 }
    398 
    399 int main(int argc, char** argv) {
    400  /* The command line argument: -d is used to determine if the test is being run
    401  in debug mode. The regress tool requires only one line output:PASS or FAIL.
    402  All of the printfs associated with this test has been handled with a if
    403  (debug_mode) test. Usage: test_name [-d] [-c n]
    404  */
    405  PLOptStatus os;
    406  PLOptState* opt = PL_CreateOptState(argc, argv, "Gdc:");
    407  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    408    if (PL_OPT_BAD == os) {
    409      continue;
    410    }
    411    switch (opt->option) {
    412      case 'G': /* global threads */
    413        thread_scope = PR_GLOBAL_THREAD;
    414        break;
    415      case 'd': /* debug mode */
    416        debug_mode = 1;
    417        break;
    418      case 'c': /* loop counter */
    419        count = atoi(opt->value);
    420        break;
    421      default:
    422        break;
    423    }
    424  }
    425  PL_DestroyOptState(opt);
    426 
    427  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    428  output = PR_STDERR;
    429 
    430  timeoutTime = PR_SecondsToInterval(TIMEOUTSECS);
    431  if (debug_mode) {
    432    PR_fprintf(output, "\nRun accept() sucessful connection tests\n");
    433  }
    434 
    435  Measure(AcceptUpdatedTest, "PR_Accept()");
    436  Measure(AcceptReadTest, "PR_AcceptRead()");
    437 #ifdef WINNT
    438  Measure(AcceptNotUpdatedTest, "PR_NTFast_Accept()");
    439  Measure(AcceptReadNotUpdatedTest, "PR_NTFast_AcceptRead()");
    440  Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()");
    441 #endif
    442  if (debug_mode) {
    443    PR_fprintf(output, "\nRun accept() timeout in the accept tests\n");
    444  }
    445 #ifdef WINNT
    446  Measure(TimeoutReadReadCallbackTest,
    447          "PR_NTFast_AcceptRead_WithTimeoutCallback()");
    448 #endif
    449  Measure(TimeoutReadUpdatedTest, "PR_Accept()");
    450  if (debug_mode) {
    451    PR_fprintf(output, "\nRun accept() timeout in the read tests\n");
    452  }
    453  Measure(TimeoutReadReadTest, "PR_AcceptRead()");
    454 #ifdef WINNT
    455  Measure(TimeoutReadNotUpdatedTest, "PR_NTFast_Accept()");
    456  Measure(TimeoutReadReadNotUpdatedTest, "PR_NTFast_AcceptRead()");
    457  Measure(TimeoutReadReadCallbackTest,
    458          "PR_NTFast_AcceptRead_WithTimeoutCallback()");
    459 #endif
    460  PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS");
    461  return failed_already;
    462 }