tor-browser

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

prselect.c (10181B)


      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 **  1997 - Netscape Communications Corporation
      8 **
      9 ** Name: prselect_err.c
     10 **
     11 ** Description: tests PR_Select with sockets Error condition functions.
     12 **
     13 ** Modification History:
     14 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
     15 **           The debug mode will print all of the printfs associated with this
     16 *test.
     17 **           The regress mode will be the default mode. Since the regress tool
     18 *limits
     19 **           the output to a one line status:PASS or FAIL,all of the printf
     20 *statements
     21 **           have been handled with an if (debug_mode) statement.
     22 ***********************************************************************/
     23 
     24 /***********************************************************************
     25 ** Includes
     26 ***********************************************************************/
     27 /* Used to get the command line option */
     28 #include "plgetopt.h"
     29 #include "prttools.h"
     30 
     31 #include "prinit.h"
     32 #include "prio.h"
     33 #include "prlog.h"
     34 #include "prprf.h"
     35 #include "prerror.h"
     36 #include "prnetdb.h"
     37 
     38 #include <stdio.h>
     39 #include <string.h>
     40 #include <stdlib.h>
     41 
     42 /***********************************************************************
     43 ** PRIVATE FUNCTION:    Test_Result
     44 ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
     45 **              status of the test case.
     46 ** INPUTS:      PASS/FAIL
     47 ** OUTPUTS:     None
     48 ** RETURN:      None
     49 ** SIDE EFFECTS:
     50 **
     51 ** RESTRICTIONS:
     52 **      None
     53 ** MEMORY:      NA
     54 ** ALGORITHM:   Determine what the status is and print accordingly.
     55 **
     56 ***********************************************************************/
     57 
     58 static Test_Result(int result) {
     59  if (result == PASS) {
     60    printf("PASS\n");
     61  } else {
     62    printf("FAIL\n");
     63  }
     64 }
     65 
     66 static void clientThreadFunc(void* arg) {
     67  PRUint16 port = (PRUint16)arg;
     68  PRFileDesc* sock;
     69  PRNetAddr addr;
     70  char buf[128];
     71  int i;
     72 
     73  addr.inet.family = AF_INET;
     74  addr.inet.port = PR_htons(port);
     75  addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
     76  PR_snprintf(buf, sizeof(buf), "%hu", port);
     77 
     78  for (i = 0; i < 5; i++) {
     79    sock = PR_NewTCPSocket();
     80    PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
     81    PR_Write(sock, buf, sizeof(buf));
     82    PR_Close(sock);
     83  }
     84 }
     85 
     86 int main(int argc, char** argv) {
     87  PRFileDesc *listenSock1, *listenSock2;
     88  PRFileDesc* badFD;
     89  PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
     90  PRIntn nfds;
     91  PRUint16 listenPort1, listenPort2;
     92  PRNetAddr addr;
     93  PR_fd_set readFdSet;
     94  char buf[128];
     95  PRThread* clientThread;
     96  PRInt32 retVal;
     97  PRIntn i, j;
     98 
     99  /* The command line argument: -d is used to determine if the test is being run
    100  in debug mode. The regress tool requires only one line output:PASS or FAIL.
    101  All of the printfs associated with this test has been handled with a if
    102  (debug_mode) test. Usage: test_name -d
    103  */
    104  PLOptStatus os;
    105  PLOptState* opt = PL_CreateOptState(argc, argv, "d:");
    106  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    107    if (PL_OPT_BAD == os) {
    108      continue;
    109    }
    110    switch (opt->option) {
    111      case 'd': /* debug mode */
    112        debug_mode = 1;
    113        break;
    114      default:
    115        break;
    116    }
    117  }
    118  PL_DestroyOptState(opt);
    119 
    120  /* main test */
    121 
    122  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    123 
    124  if (debug_mode) {
    125    printf("This program tests PR_Select with sockets.  Timeout, error\n");
    126    printf("reporting, and normal operation are tested.\n\n");
    127  }
    128 
    129  /* Create two listening sockets */
    130  if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
    131    fprintf(stderr, "Can't create a new TCP socket\n");
    132    if (!debug_mode) {
    133      Test_Result(FAIL);
    134    }
    135    exit(1);
    136  }
    137  addr.inet.family = AF_INET;
    138  addr.inet.ip = PR_htonl(INADDR_ANY);
    139  addr.inet.port = PR_htons(0);
    140  if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
    141    fprintf(stderr, "Can't bind socket\n");
    142    if (!debug_mode) {
    143      Test_Result(FAIL);
    144    }
    145    exit(1);
    146  }
    147  if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
    148    fprintf(stderr, "PR_GetSockName failed\n");
    149    if (!debug_mode) {
    150      Test_Result(FAIL);
    151    }
    152    exit(1);
    153  }
    154  listenPort1 = PR_ntohs(addr.inet.port);
    155  if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
    156    fprintf(stderr, "Can't listen on a socket\n");
    157    if (!debug_mode) {
    158      Test_Result(FAIL);
    159    }
    160    exit(1);
    161  }
    162 
    163  if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
    164    fprintf(stderr, "Can't create a new TCP socket\n");
    165    if (!debug_mode) {
    166      Test_Result(FAIL);
    167    }
    168    exit(1);
    169  }
    170  addr.inet.family = AF_INET;
    171  addr.inet.ip = PR_htonl(INADDR_ANY);
    172  addr.inet.port = PR_htons(0);
    173  if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
    174    fprintf(stderr, "Can't bind socket\n");
    175    if (!debug_mode) {
    176      Test_Result(FAIL);
    177    }
    178    exit(1);
    179  }
    180  if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
    181    fprintf(stderr, "PR_GetSockName failed\n");
    182    if (!debug_mode) {
    183      Test_Result(FAIL);
    184    }
    185    exit(1);
    186  }
    187  listenPort2 = PR_ntohs(addr.inet.port);
    188  if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
    189    fprintf(stderr, "Can't listen on a socket\n");
    190    if (!debug_mode) {
    191      Test_Result(FAIL);
    192    }
    193    exit(1);
    194  }
    195  PR_snprintf(buf, sizeof(buf),
    196              "The server thread is listening on ports %hu and %hu\n\n",
    197              listenPort1, listenPort2);
    198  printf("%s", buf);
    199 
    200  /* Set up the fd set */
    201  PR_FD_ZERO(&readFdSet);
    202  PR_FD_SET(listenSock1, &readFdSet);
    203  PR_FD_SET(listenSock2, &readFdSet);
    204 
    205  /* Testing timeout */
    206  if (debug_mode) {
    207    printf("PR_Select should time out in 5 seconds\n");
    208  }
    209  retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
    210                     PR_SecondsToInterval(5));
    211  if (retVal != 0) {
    212    PR_snprintf(buf, sizeof(buf),
    213                "PR_Select should time out and return 0, but it returns %ld\n",
    214                retVal);
    215    fprintf(stderr, "%s", buf);
    216    if (retVal == -1) {
    217      fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), PR_GetOSError());
    218      if (!debug_mode) {
    219        Test_Result(FAIL);
    220      }
    221    }
    222    exit(1);
    223  }
    224  if (debug_mode) {
    225    printf("PR_Select timed out.  Test passed.\n\n");
    226  } else {
    227    Test_Result(PASS);
    228  }
    229 
    230  /* Testing bad fd */
    231  printf("PR_Select should detect a bad file descriptor\n");
    232  if ((badFD = PR_NewTCPSocket()) == NULL) {
    233    fprintf(stderr, "Can't create a TCP socket\n");
    234    exit(1);
    235  }
    236 
    237  PR_FD_SET(listenSock1, &readFdSet);
    238  PR_FD_SET(listenSock2, &readFdSet);
    239  PR_FD_SET(badFD, &readFdSet);
    240  PR_Close(badFD); /* make the fd bad */
    241  retVal =
    242      PR_Select(0 /* unused */, &readFdSet, NULL, NULL, PR_INTERVAL_NO_TIMEOUT);
    243  if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
    244    fprintf(stderr,
    245            "Failed to detect the bad fd: "
    246            "PR_Select returns %d\n",
    247            retVal);
    248    if (retVal == -1) {
    249      fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), PR_GetOSError());
    250    }
    251    exit(1);
    252  }
    253  printf("PR_Select detected a bad fd.  Test passed.\n\n");
    254  PR_FD_CLR(badFD, &readFdSet);
    255 
    256  clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc,
    257                                 (void*)listenPort1, PR_PRIORITY_NORMAL,
    258                                 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    259  if (clientThread == NULL) {
    260    fprintf(stderr, "can't create thread\n");
    261    exit(1);
    262  }
    263 
    264  clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc,
    265                                 (void*)listenPort2, PR_PRIORITY_NORMAL,
    266                                 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    267  if (clientThread == NULL) {
    268    fprintf(stderr, "can't create thread\n");
    269    exit(1);
    270  }
    271 
    272  printf("Two client threads are created.  Each of them will\n");
    273  printf("send data to one of the two ports the server is listening on.\n");
    274  printf("The data they send is the port number.  Each of them send\n");
    275  printf("the data five times, so you should see ten lines below,\n");
    276  printf("interleaved in an arbitrary order.\n");
    277 
    278  /* set up the fd array */
    279  fds = fds0;
    280  other_fds = fds1;
    281  fds[0] = listenSock1;
    282  fds[1] = listenSock2;
    283  nfds = 2;
    284  PR_FD_SET(listenSock1, &readFdSet);
    285  PR_FD_SET(listenSock2, &readFdSet);
    286 
    287  /* 20 events total */
    288  i = 0;
    289  while (i < 20) {
    290    PRFileDesc** tmp;
    291    int nextIndex;
    292    int nEvents = 0;
    293 
    294    retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
    295                       PR_INTERVAL_NO_TIMEOUT);
    296    PR_ASSERT(retVal != 0); /* no timeout */
    297    if (retVal == -1) {
    298      fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
    299              PR_GetOSError());
    300      exit(1);
    301    }
    302 
    303    nextIndex = 2;
    304    /* the two listening sockets */
    305    for (j = 0; j < 2; j++) {
    306      other_fds[j] = fds[j];
    307      if (PR_FD_ISSET(fds[j], &readFdSet)) {
    308        PRFileDesc* sock;
    309 
    310        nEvents++;
    311        sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
    312        if (sock == NULL) {
    313          fprintf(stderr, "PR_Accept() failed\n");
    314          exit(1);
    315        }
    316        other_fds[nextIndex] = sock;
    317        PR_FD_SET(sock, &readFdSet);
    318        nextIndex++;
    319      }
    320      PR_FD_SET(fds[j], &readFdSet);
    321    }
    322 
    323    for (j = 2; j < nfds; j++) {
    324      if (PR_FD_ISSET(fds[j], &readFdSet)) {
    325        PRInt32 nBytes;
    326 
    327        PR_FD_CLR(fds[j], &readFdSet);
    328        nEvents++;
    329        nBytes = PR_Read(fds[j], buf, sizeof(buf));
    330        if (nBytes == -1) {
    331          fprintf(stderr, "PR_Read() failed\n");
    332          exit(1);
    333        }
    334        /* Just to be safe */
    335        buf[127] = '\0';
    336        PR_Close(fds[j]);
    337        printf("The server received \"%s\" from a client\n", buf);
    338      } else {
    339        PR_FD_SET(fds[j], &readFdSet);
    340        other_fds[nextIndex] = fds[j];
    341        nextIndex++;
    342      }
    343    }
    344 
    345    PR_ASSERT(retVal == nEvents);
    346    /* swap */
    347    tmp = fds;
    348    fds = other_fds;
    349    other_fds = tmp;
    350    nfds = nextIndex;
    351    i += nEvents;
    352  }
    353 
    354  printf("All tests finished\n");
    355  PR_Cleanup();
    356  return 0;
    357 }