tor-browser

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

peek.c (10079B)


      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 * A test case for the PR_MSG_PEEK flag of PR_Recv().
      8 *
      9 * Test both blocking and non-blocking sockets.
     10 */
     11 
     12 #include "nspr.h"
     13 
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 #define BUFFER_SIZE 1024
     19 
     20 static int iterations = 10;
     21 
     22 /*
     23 * In iteration i, recv_amount[i] is the number of bytes we
     24 * wish to receive, and send_amount[i] is the number of bytes
     25 * we actually send.  Therefore, the number of elements in the
     26 * recv_amount or send_amount array should equal to 'iterations'.
     27 * For this test to pass we need to ensure that
     28 *     recv_amount[i] <= BUFFER_SIZE,
     29 *     send_amount[i] <= BUFFER_SIZE,
     30 *     send_amount[i] <= recv_amount[i].
     31 */
     32 static PRInt32 recv_amount[10] = {16,  128, 256, 1024, 512,
     33                                  512, 128, 256, 32,   32};
     34 static PRInt32 send_amount[10] = {16, 64, 128, 1024, 512, 256, 128, 64, 16, 32};
     35 
     36 /* Blocking I/O */
     37 static void ServerB(void* arg) {
     38  PRFileDesc* listenSock = (PRFileDesc*)arg;
     39  PRFileDesc* sock;
     40  char buf[BUFFER_SIZE];
     41  PRInt32 nbytes;
     42  int i;
     43  int j;
     44 
     45  sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
     46  if (NULL == sock) {
     47    fprintf(stderr, "PR_Accept failed\n");
     48    exit(1);
     49  }
     50 
     51  for (i = 0; i < iterations; i++) {
     52    memset(buf, 0, sizeof(buf));
     53    nbytes =
     54        PR_Recv(sock, buf, recv_amount[i], PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
     55    if (-1 == nbytes) {
     56      fprintf(stderr, "PR_Recv failed\n");
     57      exit(1);
     58    }
     59    if (send_amount[i] != nbytes) {
     60      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
     61      exit(1);
     62    }
     63    for (j = 0; j < nbytes; j++) {
     64      if (buf[j] != 2 * i) {
     65        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i, buf[j]);
     66        exit(1);
     67      }
     68    }
     69    fprintf(stderr, "server: peeked expected data\n");
     70 
     71    memset(buf, 0, sizeof(buf));
     72    nbytes =
     73        PR_Recv(sock, buf, recv_amount[i], PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
     74    if (-1 == nbytes) {
     75      fprintf(stderr, "PR_Recv failed\n");
     76      exit(1);
     77    }
     78    if (send_amount[i] != nbytes) {
     79      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
     80      exit(1);
     81    }
     82    for (j = 0; j < nbytes; j++) {
     83      if (buf[j] != 2 * i) {
     84        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i, buf[j]);
     85        exit(1);
     86      }
     87    }
     88    fprintf(stderr, "server: peeked expected data\n");
     89 
     90    memset(buf, 0, sizeof(buf));
     91    nbytes = PR_Recv(sock, buf, recv_amount[i], 0, PR_INTERVAL_NO_TIMEOUT);
     92    if (-1 == nbytes) {
     93      fprintf(stderr, "PR_Recv failed\n");
     94      exit(1);
     95    }
     96    if (send_amount[i] != nbytes) {
     97      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
     98      exit(1);
     99    }
    100    for (j = 0; j < nbytes; j++) {
    101      if (buf[j] != 2 * i) {
    102        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i, buf[j]);
    103        exit(1);
    104      }
    105    }
    106    fprintf(stderr, "server: received expected data\n");
    107 
    108    PR_Sleep(PR_SecondsToInterval(1));
    109    memset(buf, 2 * i + 1, send_amount[i]);
    110    nbytes = PR_Send(sock, buf, send_amount[i], 0, PR_INTERVAL_NO_TIMEOUT);
    111    if (-1 == nbytes) {
    112      fprintf(stderr, "PR_Send failed\n");
    113      exit(1);
    114    }
    115    if (send_amount[i] != nbytes) {
    116      fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
    117      exit(1);
    118    }
    119  }
    120  if (PR_Close(sock) == PR_FAILURE) {
    121    fprintf(stderr, "PR_Close failed\n");
    122    exit(1);
    123  }
    124 }
    125 
    126 /* Non-blocking I/O */
    127 static void ClientNB(void* arg) {
    128  PRFileDesc* sock;
    129  PRSocketOptionData opt;
    130  PRUint16 port = (PRUint16)arg;
    131  PRNetAddr addr;
    132  char buf[BUFFER_SIZE];
    133  PRPollDesc pd;
    134  PRInt32 npds;
    135  PRInt32 nbytes;
    136  int i;
    137  int j;
    138 
    139  sock = PR_OpenTCPSocket(PR_AF_INET6);
    140  if (NULL == sock) {
    141    fprintf(stderr, "PR_OpenTCPSocket failed\n");
    142    exit(1);
    143  }
    144  opt.option = PR_SockOpt_Nonblocking;
    145  opt.value.non_blocking = PR_TRUE;
    146  if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) {
    147    fprintf(stderr, "PR_SetSocketOption failed\n");
    148    exit(1);
    149  }
    150  memset(&addr, 0, sizeof(addr));
    151  if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr) ==
    152      PR_FAILURE) {
    153    fprintf(stderr, "PR_SetNetAddr failed\n");
    154    exit(1);
    155  }
    156  if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
    157    if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
    158      fprintf(stderr, "PR_Connect failed\n");
    159      exit(1);
    160    }
    161    pd.fd = sock;
    162    pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
    163    npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
    164    if (-1 == npds) {
    165      fprintf(stderr, "PR_Poll failed\n");
    166      exit(1);
    167    }
    168    if (1 != npds) {
    169      fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
    170      exit(1);
    171    }
    172    if (PR_GetConnectStatus(&pd) == PR_FAILURE) {
    173      fprintf(stderr, "PR_GetConnectStatus failed\n");
    174      exit(1);
    175    }
    176  }
    177 
    178  for (i = 0; i < iterations; i++) {
    179    PR_Sleep(PR_SecondsToInterval(1));
    180    memset(buf, 2 * i, send_amount[i]);
    181    while ((nbytes = PR_Send(sock, buf, send_amount[i], 0,
    182                             PR_INTERVAL_NO_TIMEOUT)) == -1) {
    183      if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
    184        fprintf(stderr, "PR_Send failed\n");
    185        exit(1);
    186      }
    187      pd.fd = sock;
    188      pd.in_flags = PR_POLL_WRITE;
    189      npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
    190      if (-1 == npds) {
    191        fprintf(stderr, "PR_Poll failed\n");
    192        exit(1);
    193      }
    194      if (1 != npds) {
    195        fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
    196        exit(1);
    197      }
    198    }
    199    if (send_amount[i] != nbytes) {
    200      fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
    201      exit(1);
    202    }
    203 
    204    memset(buf, 0, sizeof(buf));
    205    while ((nbytes = PR_Recv(sock, buf, recv_amount[i], PR_MSG_PEEK,
    206                             PR_INTERVAL_NO_TIMEOUT)) == -1) {
    207      if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
    208        fprintf(stderr, "PR_Recv failed\n");
    209        exit(1);
    210      }
    211      pd.fd = sock;
    212      pd.in_flags = PR_POLL_READ;
    213      npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
    214      if (-1 == npds) {
    215        fprintf(stderr, "PR_Poll failed\n");
    216        exit(1);
    217      }
    218      if (1 != npds) {
    219        fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
    220        exit(1);
    221      }
    222    }
    223    if (send_amount[i] != nbytes) {
    224      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
    225      exit(1);
    226    }
    227    for (j = 0; j < nbytes; j++) {
    228      if (buf[j] != 2 * i + 1) {
    229        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i + 1,
    230                buf[j]);
    231        exit(1);
    232      }
    233    }
    234    fprintf(stderr, "client: peeked expected data\n");
    235 
    236    memset(buf, 0, sizeof(buf));
    237    nbytes =
    238        PR_Recv(sock, buf, recv_amount[i], PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
    239    if (-1 == nbytes) {
    240      fprintf(stderr, "PR_Recv failed\n");
    241      exit(1);
    242    }
    243    if (send_amount[i] != nbytes) {
    244      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
    245      exit(1);
    246    }
    247    for (j = 0; j < nbytes; j++) {
    248      if (buf[j] != 2 * i + 1) {
    249        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i + 1,
    250                buf[j]);
    251        exit(1);
    252      }
    253    }
    254    fprintf(stderr, "client: peeked expected data\n");
    255 
    256    memset(buf, 0, sizeof(buf));
    257    nbytes = PR_Recv(sock, buf, recv_amount[i], 0, PR_INTERVAL_NO_TIMEOUT);
    258    if (-1 == nbytes) {
    259      fprintf(stderr, "PR_Recv failed\n");
    260      exit(1);
    261    }
    262    if (send_amount[i] != nbytes) {
    263      fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
    264      exit(1);
    265    }
    266    for (j = 0; j < nbytes; j++) {
    267      if (buf[j] != 2 * i + 1) {
    268        fprintf(stderr, "byte %d should be %d but is %d\n", j, 2 * i + 1,
    269                buf[j]);
    270        exit(1);
    271      }
    272    }
    273    fprintf(stderr, "client: received expected data\n");
    274  }
    275  if (PR_Close(sock) == PR_FAILURE) {
    276    fprintf(stderr, "PR_Close failed\n");
    277    exit(1);
    278  }
    279 }
    280 
    281 static void RunTest(PRThreadScope scope, PRFileDesc* listenSock,
    282                    PRUint16 port) {
    283  PRThread *server, *client;
    284 
    285  server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock,
    286                           PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
    287  if (NULL == server) {
    288    fprintf(stderr, "PR_CreateThread failed\n");
    289    exit(1);
    290  }
    291  client = PR_CreateThread(PR_USER_THREAD, ClientNB, (void*)port,
    292                           PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
    293  if (NULL == client) {
    294    fprintf(stderr, "PR_CreateThread failed\n");
    295    exit(1);
    296  }
    297 
    298  if (PR_JoinThread(server) == PR_FAILURE) {
    299    fprintf(stderr, "PR_JoinThread failed\n");
    300    exit(1);
    301  }
    302  if (PR_JoinThread(client) == PR_FAILURE) {
    303    fprintf(stderr, "PR_JoinThread failed\n");
    304    exit(1);
    305  }
    306 }
    307 
    308 int main(int argc, char** argv) {
    309  PRFileDesc* listenSock;
    310  PRNetAddr addr;
    311  PRUint16 port;
    312 
    313  listenSock = PR_OpenTCPSocket(PR_AF_INET6);
    314  if (NULL == listenSock) {
    315    fprintf(stderr, "PR_OpenTCPSocket failed\n");
    316    exit(1);
    317  }
    318  memset(&addr, 0, sizeof(addr));
    319  if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
    320    fprintf(stderr, "PR_SetNetAddr failed\n");
    321    exit(1);
    322  }
    323  if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
    324    fprintf(stderr, "PR_Bind failed\n");
    325    exit(1);
    326  }
    327  if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
    328    fprintf(stderr, "PR_GetSockName failed\n");
    329    exit(1);
    330  }
    331  port = PR_ntohs(addr.ipv6.port);
    332  if (PR_Listen(listenSock, 5) == PR_FAILURE) {
    333    fprintf(stderr, "PR_Listen failed\n");
    334    exit(1);
    335  }
    336 
    337  fprintf(stderr, "Running the test with local threads\n");
    338  RunTest(PR_LOCAL_THREAD, listenSock, port);
    339  fprintf(stderr, "Running the test with global threads\n");
    340  RunTest(PR_GLOBAL_THREAD, listenSock, port);
    341 
    342  if (PR_Close(listenSock) == PR_FAILURE) {
    343    fprintf(stderr, "PR_Close failed\n");
    344    exit(1);
    345  }
    346  printf("PASS\n");
    347  return 0;
    348 }