tor-browser

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

poll_nm.c (10252B)


      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 **
      8 ** Name: prpoll_norm.c
      9 **
     10 ** Description: This program tests PR_Poll with sockets.
     11 **              Normal operation are tested
     12 **
     13 ** Modification History:
     14 ** 19-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 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been
     23 *updated to
     24 **          recognize the return code from tha main program.
     25 ***********************************************************************/
     26 
     27 /***********************************************************************
     28 ** Includes
     29 ***********************************************************************/
     30 /* Used to get the command line option */
     31 #include "plgetopt.h"
     32 
     33 #include "prinit.h"
     34 #include "prio.h"
     35 #include "prlog.h"
     36 #include "prprf.h"
     37 #include "prnetdb.h"
     38 #include "obsolete/probslet.h"
     39 
     40 #include "private/pprio.h"
     41 
     42 #include <stdio.h>
     43 #include <string.h>
     44 #include <stdlib.h>
     45 
     46 PRIntn failed_already = 0;
     47 PRIntn debug_mode;
     48 
     49 #define NUM_ITERATIONS 5
     50 
     51 static void PR_CALLBACK clientThreadFunc(void* arg) {
     52  PRUintn port = (PRUintn)arg;
     53  PRFileDesc* sock;
     54  PRNetAddr addr;
     55  char buf[128];
     56  int i;
     57  PRStatus sts;
     58  PRInt32 n;
     59 
     60  addr.inet.family = PR_AF_INET;
     61  addr.inet.port = PR_htons((PRUint16)port);
     62  addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
     63  memset(buf, 0, sizeof(buf));
     64  PR_snprintf(buf, sizeof(buf), "%hu", port);
     65 
     66  for (i = 0; i < NUM_ITERATIONS; i++) {
     67    sock = PR_NewTCPSocket();
     68    PR_ASSERT(sock != NULL);
     69 
     70    sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
     71    PR_ASSERT(sts == PR_SUCCESS);
     72 
     73    n = PR_Write(sock, buf, sizeof(buf));
     74    PR_ASSERT(n >= 0);
     75 
     76    sts = PR_Close(sock);
     77    PR_ASSERT(sts == PR_SUCCESS);
     78  }
     79 }
     80 
     81 int main(int argc, char** argv) {
     82  PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
     83  PRUint16 listenPort1, listenPort2;
     84  PRNetAddr addr;
     85  char buf[128];
     86  PRThread* clientThread;
     87  PRPollDesc pds0[20], pds1[20], *pds, *other_pds;
     88  PRIntn npds;
     89  PRInt32 retVal;
     90  PRIntn i, j;
     91  PRSocketOptionData optval;
     92 
     93  /* The command line argument: -d is used to determine if the test is being run
     94  in debug mode. The regress tool requires only one line output:PASS or FAIL.
     95  All of the printfs associated with this test has been handled with a if
     96  (debug_mode) test. Usage: test_name -d
     97  */
     98  PLOptStatus os;
     99  PLOptState* opt = PL_CreateOptState(argc, argv, "d:");
    100  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    101    if (PL_OPT_BAD == os) {
    102      continue;
    103    }
    104    switch (opt->option) {
    105      case 'd': /* debug mode */
    106        debug_mode = 1;
    107        break;
    108      default:
    109        break;
    110    }
    111  }
    112  PL_DestroyOptState(opt);
    113 
    114  /* main test */
    115 
    116  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    117 
    118  if (debug_mode) {
    119    printf("This program tests PR_Poll with sockets.\n");
    120    printf("Normal operation are tested.\n\n");
    121  }
    122 
    123  /* Create two listening sockets */
    124  if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
    125    fprintf(stderr, "Can't create a new TCP socket\n");
    126    failed_already = 1;
    127    goto exit_now;
    128  }
    129  memset(&addr, 0, sizeof(addr));
    130  addr.inet.family = PR_AF_INET;
    131  addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    132  addr.inet.port = PR_htons(0);
    133  if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
    134    fprintf(stderr, "Can't bind socket\n");
    135    failed_already = 1;
    136    goto exit_now;
    137  }
    138  if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
    139    fprintf(stderr, "PR_GetSockName failed\n");
    140    failed_already = 1;
    141    goto exit_now;
    142  }
    143  listenPort1 = PR_ntohs(addr.inet.port);
    144  optval.option = PR_SockOpt_Nonblocking;
    145  optval.value.non_blocking = PR_TRUE;
    146  PR_SetSocketOption(listenSock1, &optval);
    147  if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
    148    fprintf(stderr, "Can't listen on a socket\n");
    149    failed_already = 1;
    150    goto exit_now;
    151  }
    152 
    153  if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
    154    fprintf(stderr, "Can't create a new TCP socket\n");
    155    failed_already = 1;
    156    goto exit_now;
    157  }
    158  addr.inet.family = PR_AF_INET;
    159  addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    160  addr.inet.port = PR_htons(0);
    161  if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
    162    fprintf(stderr, "Can't bind socket\n");
    163    failed_already = 1;
    164    goto exit_now;
    165  }
    166  if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
    167    fprintf(stderr, "PR_GetSockName failed\n");
    168    failed_already = 1;
    169    goto exit_now;
    170  }
    171  listenPort2 = PR_ntohs(addr.inet.port);
    172  PR_SetSocketOption(listenSock2, &optval);
    173  if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
    174    fprintf(stderr, "Can't listen on a socket\n");
    175    failed_already = 1;
    176    goto exit_now;
    177  }
    178  PR_snprintf(buf, sizeof(buf),
    179              "The server thread is listening on ports %hu and %hu\n\n",
    180              listenPort1, listenPort2);
    181  if (debug_mode) {
    182    printf("%s", buf);
    183  }
    184 
    185  /* Set up the poll descriptor array */
    186  pds = pds0;
    187  other_pds = pds1;
    188  memset(pds, 0, sizeof(pds));
    189  pds[0].fd = listenSock1;
    190  pds[0].in_flags = PR_POLL_READ;
    191  pds[1].fd = listenSock2;
    192  pds[1].in_flags = PR_POLL_READ;
    193  /* Add some unused entries to test if they are ignored by PR_Poll() */
    194  memset(&pds[2], 0, sizeof(pds[2]));
    195  memset(&pds[3], 0, sizeof(pds[3]));
    196  memset(&pds[4], 0, sizeof(pds[4]));
    197  npds = 5;
    198 
    199  clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc,
    200                                 (void*)listenPort1, PR_PRIORITY_NORMAL,
    201                                 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    202  if (clientThread == NULL) {
    203    fprintf(stderr, "can't create thread\n");
    204    failed_already = 1;
    205    goto exit_now;
    206  }
    207 
    208  clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc,
    209                                 (void*)listenPort2, PR_PRIORITY_NORMAL,
    210                                 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    211  if (clientThread == NULL) {
    212    fprintf(stderr, "can't create thread\n");
    213    failed_already = 1;
    214    goto exit_now;
    215  }
    216 
    217  if (debug_mode) {
    218    printf("Two client threads are created.  Each of them will\n");
    219    printf("send data to one of the two ports the server is listening on.\n");
    220    printf("The data they send is the port number.  Each of them send\n");
    221    printf("the data five times, so you should see ten lines below,\n");
    222    printf("interleaved in an arbitrary order.\n");
    223  }
    224 
    225  /* two clients, three events per iteration: accept, read, close */
    226  i = 0;
    227  while (i < 2 * 3 * NUM_ITERATIONS) {
    228    PRPollDesc* tmp;
    229    int nextIndex;
    230    int nEvents = 0;
    231 
    232    retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
    233    PR_ASSERT(retVal != 0); /* no timeout */
    234    if (retVal == -1) {
    235      fprintf(stderr, "PR_Poll failed\n");
    236      failed_already = 1;
    237      goto exit_now;
    238    }
    239 
    240    nextIndex = 2;
    241    /* the two listening sockets */
    242    for (j = 0; j < 2; j++) {
    243      other_pds[j] = pds[j];
    244      PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 &&
    245                (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
    246      if (pds[j].out_flags & PR_POLL_READ) {
    247        PRFileDesc* sock;
    248 
    249        nEvents++;
    250        sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
    251        if (sock == NULL) {
    252          fprintf(stderr, "PR_Accept() failed\n");
    253          failed_already = 1;
    254          goto exit_now;
    255        }
    256        other_pds[nextIndex].fd = sock;
    257        other_pds[nextIndex].in_flags = PR_POLL_READ;
    258        nextIndex++;
    259      } else if (pds[j].out_flags & PR_POLL_ERR) {
    260        fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
    261        failed_already = 1;
    262        goto exit_now;
    263      } else if (pds[j].out_flags & PR_POLL_NVAL) {
    264        fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
    265                PR_FileDesc2NativeHandle(pds[j].fd));
    266        failed_already = 1;
    267        goto exit_now;
    268      }
    269    }
    270 
    271    for (j = 2; j < npds; j++) {
    272      if (NULL == pds[j].fd) {
    273        /*
    274         * Keep the unused entries in the poll descriptor array
    275         * for testing purposes.
    276         */
    277        other_pds[nextIndex] = pds[j];
    278        nextIndex++;
    279        continue;
    280      }
    281 
    282      PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 &&
    283                (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
    284      if (pds[j].out_flags & PR_POLL_READ) {
    285        PRInt32 nAvail;
    286        PRInt32 nRead;
    287 
    288        nEvents++;
    289        nAvail = PR_Available(pds[j].fd);
    290        nRead = PR_Read(pds[j].fd, buf, sizeof(buf));
    291        PR_ASSERT(nAvail == nRead);
    292        if (nRead == -1) {
    293          fprintf(stderr, "PR_Read() failed\n");
    294          failed_already = 1;
    295          goto exit_now;
    296        } else if (nRead == 0) {
    297          PR_Close(pds[j].fd);
    298          continue;
    299        } else {
    300          /* Just to be safe */
    301          buf[127] = '\0';
    302          if (debug_mode) {
    303            printf("The server received \"%s\" from a client\n", buf);
    304          }
    305        }
    306      } else if (pds[j].out_flags & PR_POLL_ERR) {
    307        fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
    308        failed_already = 1;
    309        goto exit_now;
    310      } else if (pds[j].out_flags & PR_POLL_NVAL) {
    311        fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
    312        failed_already = 1;
    313        goto exit_now;
    314      }
    315      other_pds[nextIndex] = pds[j];
    316      nextIndex++;
    317    }
    318 
    319    PR_ASSERT(retVal == nEvents);
    320    /* swap */
    321    tmp = pds;
    322    pds = other_pds;
    323    other_pds = tmp;
    324    npds = nextIndex;
    325    i += nEvents;
    326  }
    327 
    328  if (debug_mode) {
    329    printf("Tests passed\n");
    330  }
    331 
    332 exit_now:
    333 
    334  if (listenSock1) {
    335    PR_Close(listenSock1);
    336  }
    337  if (listenSock2) {
    338    PR_Close(listenSock2);
    339  }
    340 
    341  PR_Cleanup();
    342 
    343  if (failed_already) {
    344    return 1;
    345  } else {
    346    return 0;
    347  }
    348 }