tor-browser

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

multiacc.c (6182B)


      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 * File: multiacc.c
      8 *
      9 * Description:
     10 * This test creates multiple threads that accept on the
     11 * same listening socket.
     12 */
     13 
     14 #include "nspr.h"
     15 
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #define NUM_SERVER_THREADS 10
     21 
     22 static int num_server_threads = NUM_SERVER_THREADS;
     23 static PRThreadScope thread_scope = PR_GLOBAL_THREAD;
     24 static PRBool exit_flag = PR_FALSE;
     25 
     26 static void ServerThreadFunc(void* arg) {
     27  PRFileDesc* listenSock = (PRFileDesc*)arg;
     28  PRFileDesc* acceptSock;
     29  PRErrorCode err;
     30  PRStatus status;
     31 
     32  while (!exit_flag) {
     33    acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
     34    if (NULL == acceptSock) {
     35      err = PR_GetError();
     36      if (PR_PENDING_INTERRUPT_ERROR == err) {
     37        printf("server thread is interrupted\n");
     38        fflush(stdout);
     39        continue;
     40      }
     41      fprintf(stderr, "PR_Accept failed: %d\n", err);
     42      exit(1);
     43    }
     44    status = PR_Close(acceptSock);
     45    if (PR_FAILURE == status) {
     46      fprintf(stderr, "PR_Close failed\n");
     47      exit(1);
     48    }
     49  }
     50 }
     51 
     52 int main(int argc, char** argv) {
     53  PRNetAddr serverAddr;
     54  PRFileDesc* dummySock;
     55  PRFileDesc* listenSock;
     56  PRFileDesc* clientSock;
     57  PRThread* dummyThread;
     58  PRThread** serverThreads;
     59  PRStatus status;
     60  PRUint16 port;
     61  int idx;
     62  PRInt32 nbytes;
     63  char buf[1024];
     64 
     65  serverThreads = (PRThread**)PR_Malloc(num_server_threads * sizeof(PRThread*));
     66  if (NULL == serverThreads) {
     67    fprintf(stderr, "PR_Malloc failed\n");
     68    exit(1);
     69  }
     70 
     71  /*
     72   * Create a dummy listening socket and have the first
     73   * (dummy) thread listen on it.  This is to ensure that
     74   * the first thread becomes the I/O continuation thread
     75   * in the pthreads implementation (see ptio.c) and remains
     76   * so throughout the test, so that we never have to
     77   * recycle the I/O continuation thread.
     78   */
     79  dummySock = PR_NewTCPSocket();
     80  if (NULL == dummySock) {
     81    fprintf(stderr, "PR_NewTCPSocket failed\n");
     82    exit(1);
     83  }
     84  memset(&serverAddr, 0, sizeof(serverAddr));
     85  status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
     86  if (PR_FAILURE == status) {
     87    fprintf(stderr, "PR_InitializeNetAddr failed\n");
     88    exit(1);
     89  }
     90  status = PR_Bind(dummySock, &serverAddr);
     91  if (PR_FAILURE == status) {
     92    fprintf(stderr, "PR_Bind failed\n");
     93    exit(1);
     94  }
     95  status = PR_Listen(dummySock, 5);
     96  if (PR_FAILURE == status) {
     97    fprintf(stderr, "PR_Listen failed\n");
     98    exit(1);
     99  }
    100 
    101  listenSock = PR_NewTCPSocket();
    102  if (NULL == listenSock) {
    103    fprintf(stderr, "PR_NewTCPSocket failed\n");
    104    exit(1);
    105  }
    106  memset(&serverAddr, 0, sizeof(serverAddr));
    107  status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
    108  if (PR_FAILURE == status) {
    109    fprintf(stderr, "PR_InitializeNetAddr failed\n");
    110    exit(1);
    111  }
    112  status = PR_Bind(listenSock, &serverAddr);
    113  if (PR_FAILURE == status) {
    114    fprintf(stderr, "PR_Bind failed\n");
    115    exit(1);
    116  }
    117  status = PR_GetSockName(listenSock, &serverAddr);
    118  if (PR_FAILURE == status) {
    119    fprintf(stderr, "PR_GetSockName failed\n");
    120    exit(1);
    121  }
    122  port = PR_ntohs(serverAddr.inet.port);
    123  status = PR_Listen(listenSock, 5);
    124  if (PR_FAILURE == status) {
    125    fprintf(stderr, "PR_Listen failed\n");
    126    exit(1);
    127  }
    128 
    129  printf("creating dummy thread\n");
    130  fflush(stdout);
    131  dummyThread =
    132      PR_CreateThread(PR_USER_THREAD, ServerThreadFunc, dummySock,
    133                      PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
    134  if (NULL == dummyThread) {
    135    fprintf(stderr, "PR_CreateThread failed\n");
    136    exit(1);
    137  }
    138  printf("sleeping one second before creating server threads\n");
    139  fflush(stdout);
    140  PR_Sleep(PR_SecondsToInterval(1));
    141  for (idx = 0; idx < num_server_threads; idx++) {
    142    serverThreads[idx] = PR_CreateThread(PR_USER_THREAD, ServerThreadFunc,
    143                                         listenSock, PR_PRIORITY_NORMAL,
    144                                         thread_scope, PR_JOINABLE_THREAD, 0);
    145    if (NULL == serverThreads[idx]) {
    146      fprintf(stderr, "PR_CreateThread failed\n");
    147      exit(1);
    148    }
    149  }
    150 
    151  memset(&serverAddr, 0, sizeof(serverAddr));
    152  PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr);
    153  clientSock = PR_NewTCPSocket();
    154  if (NULL == clientSock) {
    155    fprintf(stderr, "PR_NewTCPSocket failed\n");
    156    exit(1);
    157  }
    158  printf("sleeping one second before connecting\n");
    159  fflush(stdout);
    160  PR_Sleep(PR_SecondsToInterval(1));
    161  status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT);
    162  if (PR_FAILURE == status) {
    163    fprintf(stderr, "PR_Connect failed\n");
    164    exit(1);
    165  }
    166  nbytes = PR_Read(clientSock, buf, sizeof(buf));
    167  if (nbytes != 0) {
    168    fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes);
    169    exit(1);
    170  }
    171  status = PR_Close(clientSock);
    172  if (PR_FAILURE == status) {
    173    fprintf(stderr, "PR_Close failed\n");
    174    exit(1);
    175  }
    176  printf("sleeping one second before shutting down server threads\n");
    177  fflush(stdout);
    178  PR_Sleep(PR_SecondsToInterval(1));
    179 
    180  exit_flag = PR_TRUE;
    181  status = PR_Interrupt(dummyThread);
    182  if (PR_FAILURE == status) {
    183    fprintf(stderr, "PR_Interrupt failed\n");
    184    exit(1);
    185  }
    186  status = PR_JoinThread(dummyThread);
    187  if (PR_FAILURE == status) {
    188    fprintf(stderr, "PR_JoinThread failed\n");
    189    exit(1);
    190  }
    191  for (idx = 0; idx < num_server_threads; idx++) {
    192    status = PR_Interrupt(serverThreads[idx]);
    193    if (PR_FAILURE == status) {
    194      fprintf(stderr, "PR_Interrupt failed\n");
    195      exit(1);
    196    }
    197    status = PR_JoinThread(serverThreads[idx]);
    198    if (PR_FAILURE == status) {
    199      fprintf(stderr, "PR_JoinThread failed\n");
    200      exit(1);
    201    }
    202  }
    203  PR_Free(serverThreads);
    204  status = PR_Close(dummySock);
    205  if (PR_FAILURE == status) {
    206    fprintf(stderr, "PR_Close failed\n");
    207    exit(1);
    208  }
    209  status = PR_Close(listenSock);
    210  if (PR_FAILURE == status) {
    211    fprintf(stderr, "PR_Close failed\n");
    212    exit(1);
    213  }
    214 
    215  printf("PASS\n");
    216  return 0;
    217 }