tor-browser

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

layer.c (14576B)


      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 "prio.h"
      7 #include "prprf.h"
      8 #include "prlog.h"
      9 #include "prnetdb.h"
     10 #include "prthread.h"
     11 
     12 #include "plerror.h"
     13 #include "plgetopt.h"
     14 
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 /*
     19 ** Testing layering of I/O
     20 **
     21 **      The layered server
     22 ** A thread that acts as a server. It creates a TCP listener with a dummy
     23 ** layer pushed on top. Then listens for incoming connections. Each connection
     24 ** request for connection will be layered as well, accept one request, echo
     25 ** it back and close.
     26 **
     27 **      The layered client
     28 ** Pretty much what you'd expect.
     29 */
     30 
     31 static PRFileDesc* logFile;
     32 static PRDescIdentity identity;
     33 static PRNetAddr server_address;
     34 
     35 static PRIOMethods myMethods;
     36 
     37 typedef enum Verbosity { silent, quiet, chatty, noisy } Verbosity;
     38 
     39 static PRIntn minor_iterations = 5;
     40 static PRIntn major_iterations = 1;
     41 static Verbosity verbosity = quiet;
     42 
     43 #ifdef DEBUG
     44 #  define PORT_INC_DO +100
     45 #else
     46 #  define PORT_INC_DO
     47 #endif
     48 #ifdef IS_64
     49 #  define PORT_INC_3264 +200
     50 #else
     51 #  define PORT_INC_3264
     52 #endif
     53 
     54 static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264;
     55 
     56 static PRFileDesc* PushLayer(PRFileDesc* stack) {
     57  PRFileDesc* layer = PR_CreateIOLayerStub(identity, &myMethods);
     58  PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
     59  if (verbosity > quiet) {
     60    PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
     61  }
     62  PR_ASSERT(PR_SUCCESS == rv);
     63  return stack;
     64 } /* PushLayer */
     65 
     66 static PRFileDesc* PushNewLayers(PRFileDesc* stack) {
     67  PRDescIdentity tmp_identity;
     68  PRFileDesc* layer;
     69  PRStatus rv;
     70 
     71  /* push a dummy layer */
     72  tmp_identity = PR_GetUniqueIdentity("Dummy 1");
     73  layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
     74  rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
     75  if (verbosity > quiet)
     76    PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
     77  PR_ASSERT(PR_SUCCESS == rv);
     78 
     79  /* push a data processing layer */
     80  layer = PR_CreateIOLayerStub(identity, &myMethods);
     81  rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
     82  if (verbosity > quiet)
     83    PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
     84  PR_ASSERT(PR_SUCCESS == rv);
     85 
     86  /* push another dummy layer */
     87  tmp_identity = PR_GetUniqueIdentity("Dummy 2");
     88  layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
     89  rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
     90  if (verbosity > quiet)
     91    PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
     92  PR_ASSERT(PR_SUCCESS == rv);
     93  return stack;
     94 } /* PushLayer */
     95 
     96 #if 0
     97 static PRFileDesc *PopLayer(PRFileDesc *stack)
     98 {
     99    PRFileDesc *popped = PR_PopIOLayer(stack, identity);
    100    if (verbosity > quiet) {
    101        PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
    102    }
    103    popped->dtor(popped);
    104 
    105    return stack;
    106 }  /* PopLayer */
    107 #endif
    108 
    109 static void PR_CALLBACK Client(void* arg) {
    110  PRStatus rv;
    111  PRUint8 buffer[100];
    112  PRIntn empty_flags = 0;
    113  PRIntn bytes_read, bytes_sent;
    114  PRFileDesc* stack = (PRFileDesc*)arg;
    115 
    116  /* Initialize the buffer so that Purify won't complain */
    117  memset(buffer, 0, sizeof(buffer));
    118 
    119  rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
    120  PR_ASSERT(PR_SUCCESS == rv);
    121  while (minor_iterations-- > 0) {
    122    bytes_sent = PR_Send(stack, buffer, sizeof(buffer), empty_flags,
    123                         PR_INTERVAL_NO_TIMEOUT);
    124    PR_ASSERT(sizeof(buffer) == bytes_sent);
    125    if (verbosity > chatty) {
    126      PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent);
    127    }
    128    bytes_read =
    129        PR_Recv(stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT);
    130    if (verbosity > chatty) {
    131      PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read);
    132    }
    133    PR_ASSERT(bytes_read == bytes_sent);
    134  }
    135 
    136  if (verbosity > quiet) {
    137    PR_fprintf(logFile, "Client shutting down stack\n");
    138  }
    139 
    140  rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH);
    141  PR_ASSERT(PR_SUCCESS == rv);
    142 } /* Client */
    143 
    144 static void PR_CALLBACK Server(void* arg) {
    145  PRStatus rv;
    146  PRUint8 buffer[100];
    147  PRFileDesc* service;
    148  PRUintn empty_flags = 0;
    149  PRIntn bytes_read, bytes_sent;
    150  PRFileDesc* stack = (PRFileDesc*)arg;
    151  PRNetAddr client_address;
    152 
    153  service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
    154  if (verbosity > quiet) {
    155    PR_fprintf(logFile, "Server accepting connection\n");
    156  }
    157 
    158  do {
    159    bytes_read = PR_Recv(service, buffer, sizeof(buffer), empty_flags,
    160                         PR_INTERVAL_NO_TIMEOUT);
    161    if (0 != bytes_read) {
    162      if (verbosity > chatty) {
    163        PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read);
    164      }
    165      PR_ASSERT(bytes_read > 0);
    166      bytes_sent = PR_Send(service, buffer, bytes_read, empty_flags,
    167                           PR_INTERVAL_NO_TIMEOUT);
    168      if (verbosity > chatty) {
    169        PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent);
    170      }
    171      PR_ASSERT(bytes_read == bytes_sent);
    172    }
    173 
    174  } while (0 != bytes_read);
    175 
    176  if (verbosity > quiet) {
    177    PR_fprintf(logFile, "Server shutting down and closing stack\n");
    178  }
    179  rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH);
    180  PR_ASSERT(PR_SUCCESS == rv);
    181  rv = PR_Close(service);
    182  PR_ASSERT(PR_SUCCESS == rv);
    183 
    184 } /* Server */
    185 
    186 static PRInt32 PR_CALLBACK MyRecv(PRFileDesc* fd, void* buf, PRInt32 amount,
    187                                  PRIntn flags, PRIntervalTime timeout) {
    188  char* b = (char*)buf;
    189  PRFileDesc* lo = fd->lower;
    190  PRInt32 rv, readin = 0, request = 0;
    191  rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
    192  if (verbosity > chatty)
    193    PR_fprintf(logFile, "MyRecv sending permission for %d bytes\n", request);
    194  if (0 < rv) {
    195    if (verbosity > chatty)
    196      PR_fprintf(logFile, "MyRecv received permission request for %d bytes\n",
    197                 request);
    198    rv = lo->methods->send(lo, &request, sizeof(request), flags, timeout);
    199    if (0 < rv) {
    200      if (verbosity > chatty)
    201        PR_fprintf(logFile, "MyRecv sending permission for %d bytes\n",
    202                   request);
    203      while (readin < request) {
    204        rv = lo->methods->recv(lo, b + readin, amount - readin, flags, timeout);
    205        if (rv <= 0) {
    206          break;
    207        }
    208        if (verbosity > chatty)
    209          PR_fprintf(logFile, "MyRecv received %d bytes\n", rv);
    210        readin += rv;
    211      }
    212      rv = readin;
    213    }
    214  }
    215  return rv;
    216 } /* MyRecv */
    217 
    218 static PRInt32 PR_CALLBACK MySend(PRFileDesc* fd, const void* buf,
    219                                  PRInt32 amount, PRIntn flags,
    220                                  PRIntervalTime timeout) {
    221  PRFileDesc* lo = fd->lower;
    222  const char* b = (const char*)buf;
    223  PRInt32 rv, wroteout = 0, request;
    224  if (verbosity > chatty)
    225    PR_fprintf(logFile, "MySend asking permission to send %d bytes\n", amount);
    226  rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout);
    227  if (0 < rv) {
    228    rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
    229    if (0 < rv) {
    230      PR_ASSERT(request == amount);
    231      if (verbosity > chatty)
    232        PR_fprintf(logFile, "MySend got permission to send %d bytes\n",
    233                   request);
    234      while (wroteout < request) {
    235        rv = lo->methods->send(lo, b + wroteout, request - wroteout, flags,
    236                               timeout);
    237        if (rv <= 0) {
    238          break;
    239        }
    240        if (verbosity > chatty)
    241          PR_fprintf(logFile, "MySend wrote %d bytes\n", rv);
    242        wroteout += rv;
    243      }
    244      rv = amount;
    245    }
    246  }
    247  return rv;
    248 } /* MySend */
    249 
    250 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) {
    251  PRIntn verbage = (PRIntn)verbosity + delta;
    252  if (verbage < (PRIntn)silent) {
    253    verbage = (PRIntn)silent;
    254  } else if (verbage > (PRIntn)noisy) {
    255    verbage = (PRIntn)noisy;
    256  }
    257  return (Verbosity)verbage;
    258 } /* ChangeVerbosity */
    259 
    260 int main(int argc, char** argv) {
    261  PRStatus rv;
    262  PRIntn mits;
    263  PLOptStatus os;
    264  PRFileDesc *client, *service;
    265  PRFileDesc *client_stack, *service_stack;
    266  PRNetAddr any_address;
    267  const char* server_name = NULL;
    268  const PRIOMethods* stubMethods;
    269  PRThread *client_thread, *server_thread;
    270  PRThreadScope thread_scope = PR_LOCAL_THREAD;
    271  PLOptState* opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
    272  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    273    if (PL_OPT_BAD == os) {
    274      continue;
    275    }
    276    switch (opt->option) {
    277      case 0:
    278        server_name = opt->value;
    279        break;
    280      case 'd': /* debug mode */
    281        if (verbosity < noisy) {
    282          verbosity = ChangeVerbosity(verbosity, 1);
    283        }
    284        break;
    285      case 'q': /* debug mode */
    286        if (verbosity > silent) {
    287          verbosity = ChangeVerbosity(verbosity, -1);
    288        }
    289        break;
    290      case 'G': /* use global threads */
    291        thread_scope = PR_GLOBAL_THREAD;
    292        break;
    293      case 'C': /* number of threads waiting */
    294        major_iterations = atoi(opt->value);
    295        break;
    296      case 'c': /* number of client threads */
    297        minor_iterations = atoi(opt->value);
    298        break;
    299      case 'p': /* default port */
    300        default_port = atoi(opt->value);
    301        break;
    302      default:
    303        break;
    304    }
    305  }
    306  PL_DestroyOptState(opt);
    307 
    308  logFile = PR_GetSpecialFD(PR_StandardError);
    309 
    310  identity = PR_GetUniqueIdentity("Dummy");
    311  stubMethods = PR_GetDefaultIOMethods();
    312 
    313  /*
    314  ** The protocol we're going to implement is one where in order to initiate
    315  ** a send, the sender must first solicit permission. Therefore, every
    316  ** send is really a send - receive - send sequence.
    317  */
    318  myMethods = *stubMethods; /* first get the entire batch */
    319  myMethods.recv = MyRecv;  /* then override the ones we care about */
    320  myMethods.send = MySend;  /* then override the ones we care about */
    321 
    322  if (NULL == server_name)
    323    rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
    324  else {
    325    rv = PR_StringToNetAddr(server_name, &server_address);
    326    PR_ASSERT(PR_SUCCESS == rv);
    327    rv = PR_InitializeNetAddr(PR_IpAddrNull, default_port, &server_address);
    328  }
    329  PR_ASSERT(PR_SUCCESS == rv);
    330 
    331  /* one type w/o layering */
    332 
    333  mits = minor_iterations;
    334  while (major_iterations-- > 0) {
    335    if (verbosity > silent) {
    336      PR_fprintf(logFile, "Beginning non-layered test\n");
    337    }
    338    client = PR_NewTCPSocket();
    339    PR_ASSERT(NULL != client);
    340    service = PR_NewTCPSocket();
    341    PR_ASSERT(NULL != service);
    342    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
    343    PR_ASSERT(PR_SUCCESS == rv);
    344    rv = PR_Bind(service, &any_address);
    345    PR_ASSERT(PR_SUCCESS == rv);
    346    rv = PR_Listen(service, 10);
    347    PR_ASSERT(PR_SUCCESS == rv);
    348 
    349    minor_iterations = mits;
    350    server_thread =
    351        PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH,
    352                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    353    PR_ASSERT(NULL != server_thread);
    354 
    355    client_thread =
    356        PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL,
    357                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    358    PR_ASSERT(NULL != client_thread);
    359 
    360    rv = PR_JoinThread(client_thread);
    361    PR_ASSERT(PR_SUCCESS == rv);
    362    rv = PR_JoinThread(server_thread);
    363    PR_ASSERT(PR_SUCCESS == rv);
    364 
    365    rv = PR_Close(client);
    366    PR_ASSERT(PR_SUCCESS == rv);
    367    rv = PR_Close(service);
    368    PR_ASSERT(PR_SUCCESS == rv);
    369    if (verbosity > silent) {
    370      PR_fprintf(logFile, "Ending non-layered test\n");
    371    }
    372 
    373    /* with layering */
    374    if (verbosity > silent) {
    375      PR_fprintf(logFile, "Beginning layered test\n");
    376    }
    377    client = PR_NewTCPSocket();
    378    PR_ASSERT(NULL != client);
    379    PushLayer(client);
    380    service = PR_NewTCPSocket();
    381    PR_ASSERT(NULL != service);
    382    PushLayer(service);
    383    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
    384    PR_ASSERT(PR_SUCCESS == rv);
    385    rv = PR_Bind(service, &any_address);
    386    PR_ASSERT(PR_SUCCESS == rv);
    387    rv = PR_Listen(service, 10);
    388    PR_ASSERT(PR_SUCCESS == rv);
    389 
    390    minor_iterations = mits;
    391    server_thread =
    392        PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH,
    393                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    394    PR_ASSERT(NULL != server_thread);
    395 
    396    client_thread =
    397        PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL,
    398                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    399    PR_ASSERT(NULL != client_thread);
    400 
    401    rv = PR_JoinThread(client_thread);
    402    PR_ASSERT(PR_SUCCESS == rv);
    403    rv = PR_JoinThread(server_thread);
    404    PR_ASSERT(PR_SUCCESS == rv);
    405 
    406    rv = PR_Close(client);
    407    PR_ASSERT(PR_SUCCESS == rv);
    408    rv = PR_Close(service);
    409    PR_ASSERT(PR_SUCCESS == rv);
    410    /* with layering, using new style stack */
    411    if (verbosity > silent)
    412      PR_fprintf(logFile, "Beginning layered test with new style stack\n");
    413    client = PR_NewTCPSocket();
    414    PR_ASSERT(NULL != client);
    415    client_stack = PR_CreateIOLayer(client);
    416    PushNewLayers(client_stack);
    417    service = PR_NewTCPSocket();
    418    PR_ASSERT(NULL != service);
    419    service_stack = PR_CreateIOLayer(service);
    420    PushNewLayers(service_stack);
    421    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
    422    PR_ASSERT(PR_SUCCESS == rv);
    423    rv = PR_Bind(service, &any_address);
    424    PR_ASSERT(PR_SUCCESS == rv);
    425    rv = PR_Listen(service, 10);
    426    PR_ASSERT(PR_SUCCESS == rv);
    427 
    428    minor_iterations = mits;
    429    server_thread =
    430        PR_CreateThread(PR_USER_THREAD, Server, service_stack, PR_PRIORITY_HIGH,
    431                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    432    PR_ASSERT(NULL != server_thread);
    433 
    434    client_thread = PR_CreateThread(PR_USER_THREAD, Client, client_stack,
    435                                    PR_PRIORITY_NORMAL, thread_scope,
    436                                    PR_JOINABLE_THREAD, 16 * 1024);
    437    PR_ASSERT(NULL != client_thread);
    438 
    439    rv = PR_JoinThread(client_thread);
    440    PR_ASSERT(PR_SUCCESS == rv);
    441    rv = PR_JoinThread(server_thread);
    442    PR_ASSERT(PR_SUCCESS == rv);
    443 
    444    rv = PR_Close(client_stack);
    445    PR_ASSERT(PR_SUCCESS == rv);
    446    rv = PR_Close(service_stack);
    447    PR_ASSERT(PR_SUCCESS == rv);
    448    if (verbosity > silent) {
    449      PR_fprintf(logFile, "Ending layered test\n");
    450    }
    451  }
    452  return 0;
    453 } /* main */
    454 
    455 /* layer.c */