tor-browser

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

nonblock.c (6074B)


      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 #include "nspr.h"
      7 #include "prio.h"
      8 #include "prerror.h"
      9 #include "prlog.h"
     10 #include "prprf.h"
     11 #include "prnetdb.h"
     12 #include "plerror.h"
     13 #include "obsolete/probslet.h"
     14 
     15 #include <stdio.h>
     16 #include <string.h>
     17 #include <stdlib.h>
     18 
     19 #define NUMBER_ROUNDS 5
     20 
     21 #define UNIT_TIME 100 /* unit time in milliseconds */
     22 #define CHUNK_SIZE 10
     23 #undef USE_PR_SELECT /* If defined, we use PR_Select. \
     24                      * If not defined, use PR_Poll instead. */
     25 
     26 #if defined(USE_PR_SELECT)
     27 #  include "pprio.h"
     28 #endif
     29 
     30 static void PR_CALLBACK clientThreadFunc(void* arg) {
     31  PRUintn port = (PRUintn)arg;
     32  PRFileDesc* sock;
     33  PRNetAddr addr;
     34  char buf[CHUNK_SIZE];
     35  int i;
     36  PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
     37  PRSocketOptionData optval;
     38  PRStatus retVal;
     39  PRInt32 nBytes;
     40 
     41  /* Initialize the buffer so that Purify won't complain */
     42  memset(buf, 0, sizeof(buf));
     43 
     44  addr.inet.family = PR_AF_INET;
     45  addr.inet.port = PR_htons((PRUint16)port);
     46  addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
     47  PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
     48 
     49  /* time 1 */
     50  PR_Sleep(unitTime);
     51  sock = PR_NewTCPSocket();
     52  optval.option = PR_SockOpt_Nonblocking;
     53  optval.value.non_blocking = PR_TRUE;
     54  PR_SetSocketOption(sock, &optval);
     55  retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
     56  if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) {
     57 #if !defined(USE_PR_SELECT)
     58    PRPollDesc pd;
     59    PRInt32 n;
     60    fprintf(stderr, "connect: EWOULDBLOCK, good\n");
     61    pd.fd = sock;
     62    pd.in_flags = PR_POLL_WRITE;
     63    n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
     64    PR_ASSERT(n == 1);
     65    PR_ASSERT(pd.out_flags == PR_POLL_WRITE);
     66 #else
     67    PR_fd_set writeSet;
     68    PRInt32 n;
     69    fprintf(stderr, "connect: EWOULDBLOCK, good\n");
     70    PR_FD_ZERO(&writeSet);
     71    PR_FD_SET(sock, &writeSet);
     72    n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT);
     73    PR_ASSERT(n == 1);
     74    PR_ASSERT(PR_FD_ISSET(sock, &writeSet));
     75 #endif
     76  }
     77  printf("client connected\n");
     78  fflush(stdout);
     79 
     80  /* time 4, 7, 11, etc. */
     81  for (i = 0; i < NUMBER_ROUNDS; i++) {
     82    PR_Sleep(3 * unitTime);
     83    nBytes = PR_Write(sock, buf, sizeof(buf));
     84    if (nBytes == -1) {
     85      if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
     86        fprintf(stderr, "write: EWOULDBLOCK\n");
     87        exit(1);
     88      } else {
     89        fprintf(stderr, "write: failed\n");
     90      }
     91    }
     92    printf("client sent %d bytes\n", nBytes);
     93    fflush(stdout);
     94  }
     95 
     96  PR_Close(sock);
     97 }
     98 
     99 static PRIntn PR_CALLBACK RealMain(PRIntn argc, char** argv) {
    100  PRFileDesc *listenSock, *sock;
    101  PRUint16 listenPort;
    102  PRNetAddr addr;
    103  char buf[CHUNK_SIZE];
    104  PRThread* clientThread;
    105  PRInt32 retVal;
    106  PRSocketOptionData optval;
    107  PRIntn i;
    108  PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
    109 
    110  /* Create a listening socket */
    111  if ((listenSock = PR_NewTCPSocket()) == NULL) {
    112    fprintf(stderr, "Can't create a new TCP socket\n");
    113    exit(1);
    114  }
    115  addr.inet.family = PR_AF_INET;
    116  addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    117  addr.inet.port = PR_htons(0);
    118  if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
    119    fprintf(stderr, "Can't bind socket\n");
    120    exit(1);
    121  }
    122  if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
    123    fprintf(stderr, "PR_GetSockName failed\n");
    124    exit(1);
    125  }
    126  listenPort = PR_ntohs(addr.inet.port);
    127  if (PR_Listen(listenSock, 5) == PR_FAILURE) {
    128    fprintf(stderr, "Can't listen on a socket\n");
    129    exit(1);
    130  }
    131 
    132  PR_snprintf(buf, sizeof(buf),
    133              "The server thread is listening on port %hu\n\n", listenPort);
    134  printf("%s", buf);
    135 
    136  clientThread = PR_CreateThread(PR_USER_THREAD, clientThreadFunc,
    137                                 (void*)listenPort, PR_PRIORITY_NORMAL,
    138                                 PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
    139  if (clientThread == NULL) {
    140    fprintf(stderr, "can't create thread\n");
    141    exit(1);
    142  }
    143 
    144  printf("client thread created.\n");
    145 
    146  optval.option = PR_SockOpt_Nonblocking;
    147  optval.value.non_blocking = PR_TRUE;
    148  PR_SetSocketOption(listenSock, &optval);
    149  /* time 0 */
    150  sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
    151  if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
    152    PL_PrintError("First Accept\n");
    153    fprintf(stderr, "First PR_Accept() xxx\n");
    154    exit(1);
    155  }
    156  printf("accept: EWOULDBLOCK, good\n");
    157  fflush(stdout);
    158  /* time 2 */
    159  PR_Sleep(2 * unitTime);
    160  sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
    161  if (sock == NULL) {
    162    PL_PrintError("Second Accept\n");
    163    fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n", PR_GetError(),
    164            PR_GetOSError());
    165    exit(1);
    166  }
    167  printf("accept: succeeded, good\n");
    168  fflush(stdout);
    169  PR_Close(listenSock);
    170 
    171  PR_SetSocketOption(sock, &optval);
    172 
    173  /* time 3, 5, 6, 8, etc. */
    174  for (i = 0; i < NUMBER_ROUNDS; i++) {
    175    PR_Sleep(unitTime);
    176    retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
    177    if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
    178      PL_PrintError("First Receive:\n");
    179      fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n", retVal,
    180              PR_GetError());
    181      exit(1);
    182    }
    183    printf("read: EWOULDBLOCK, good\n");
    184    fflush(stdout);
    185    PR_Sleep(2 * unitTime);
    186    retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
    187    if (retVal != CHUNK_SIZE) {
    188      PL_PrintError("Second Receive:\n");
    189      fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", retVal,
    190              PR_GetError());
    191      exit(1);
    192    }
    193    printf("read: %d bytes, good\n", retVal);
    194    fflush(stdout);
    195  }
    196  PR_Close(sock);
    197 
    198  printf("All tests finished\n");
    199  printf("PASS\n");
    200  return 0;
    201 }
    202 
    203 int main(int argc, char** argv) {
    204  PRIntn rv;
    205 
    206  rv = PR_Initialize(RealMain, argc, argv, 0);
    207  return rv;
    208 } /* main */