tor-browser

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

tmocon.c (11765B)


      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: tmocon.c
      9 **
     10 ** Description: test client socket connection.
     11 **
     12 ** Modification History:
     13 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
     14 **           The debug mode will print all of the printfs associated with this
     15 *test.
     16 **           The regress mode will be the default mode. Since the regress tool
     17 *limits
     18 **           the output to a one line status:PASS or FAIL,all of the printf
     19 *statements
     20 **           have been handled with an if (debug_mode) statement.
     21 ***********************************************************************/
     22 
     23 /***********************************************************************
     24 ** Includes
     25 ***********************************************************************/
     26 /* Used to get the command line option */
     27 #include "plgetopt.h"
     28 
     29 #include "nspr.h"
     30 #include "pprio.h"
     31 
     32 #include "plerror.h"
     33 #include "plgetopt.h"
     34 
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 
     39 /* for getcwd */
     40 #if defined(XP_UNIX)
     41 #  include <unistd.h>
     42 #elif defined(XP_PC)
     43 #  include <direct.h>
     44 #endif
     45 
     46 #ifdef WINCE
     47 #  include <windows.h>
     48 char* getcwd(char* buf, size_t size) {
     49  wchar_t wpath[MAX_PATH];
     50  _wgetcwd(wpath, MAX_PATH);
     51  WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0);
     52 }
     53 #endif
     54 
     55 #ifdef DEBUG
     56 #  define PORT_INC_DO +100
     57 #else
     58 #  define PORT_INC_DO
     59 #endif
     60 #ifdef IS_64
     61 #  define PORT_INC_3264 +200
     62 #else
     63 #  define PORT_INC_3264
     64 #endif
     65 
     66 #define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
     67 
     68 #define DEFAULT_DALLY 1
     69 #define DEFAULT_THREADS 1
     70 #define DEFAULT_TIMEOUT 10
     71 #define DEFAULT_MESSAGES 100
     72 #define DEFAULT_MESSAGESIZE 100
     73 
     74 static PRFileDesc* debug_out = NULL;
     75 
     76 typedef struct Shared {
     77  PRBool random;
     78  PRBool failed;
     79  PRBool intermittant;
     80  PRIntn debug;
     81  PRInt32 messages;
     82  PRIntervalTime dally;
     83  PRIntervalTime timeout;
     84  PRInt32 message_length;
     85  PRNetAddr serverAddress;
     86 } Shared;
     87 
     88 static PRIntervalTime Timeout(const Shared* shared) {
     89  PRIntervalTime timeout = shared->timeout;
     90  if (shared->random) {
     91    PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */
     92    PRUint32 random = rand() % quarter;    /* something in[0..timeout / 4) */
     93    timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */
     94  }
     95  return timeout;
     96 } /* Timeout */
     97 
     98 static void CauseTimeout(const Shared* shared) {
     99  if (shared->intermittant) {
    100    PR_Sleep(Timeout(shared));
    101  }
    102 } /* CauseTimeout */
    103 
    104 static PRStatus MakeReceiver(Shared* shared) {
    105  PRStatus rv = PR_FAILURE;
    106  if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback)) {
    107    char* argv[3];
    108    char path[1024 + sizeof("/tmoacc")];
    109 
    110    getcwd(path, sizeof(path));
    111 
    112    (void)strcat(path, "/tmoacc");
    113 #ifdef XP_PC
    114    (void)strcat(path, ".exe");
    115 #endif
    116    argv[0] = path;
    117    if (shared->debug > 0) {
    118      argv[1] = "-d";
    119      argv[2] = NULL;
    120    } else {
    121      argv[1] = NULL;
    122    }
    123    if (shared->debug > 1) {
    124      PR_fprintf(debug_out, " creating accept process %s ...", path);
    125    }
    126    fflush(stdout);
    127    rv = PR_CreateProcessDetached(path, argv, NULL, NULL);
    128    if (PR_SUCCESS == rv) {
    129      if (shared->debug > 1) {
    130        PR_fprintf(debug_out, " wait 5 seconds");
    131      }
    132      if (shared->debug > 1) {
    133        PR_fprintf(debug_out, " before connecting to accept process ...");
    134      }
    135      fflush(stdout);
    136      PR_Sleep(PR_SecondsToInterval(5));
    137      return rv;
    138    }
    139    shared->failed = PR_TRUE;
    140    if (shared->debug > 0) {
    141      PL_FPrintError(debug_out, "PR_CreateProcessDetached failed");
    142    }
    143  }
    144  return rv;
    145 } /* MakeReceiver */
    146 
    147 static void Connect(void* arg) {
    148  PRStatus rv;
    149  char* buffer = NULL;
    150  PRFileDesc* clientSock;
    151  Shared* shared = (Shared*)arg;
    152  PRInt32 loop, bytes, flags = 0;
    153  struct Descriptor {
    154    PRInt32 length;
    155    PRUint32 checksum;
    156  } descriptor;
    157  debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError);
    158 
    159  buffer = (char*)PR_MALLOC(shared->message_length);
    160 
    161  for (bytes = 0; bytes < shared->message_length; ++bytes) {
    162    buffer[bytes] = (char)bytes;
    163  }
    164 
    165  descriptor.checksum = 0;
    166  for (bytes = 0; bytes < shared->message_length; ++bytes) {
    167    PRUint32 overflow = descriptor.checksum & 0x80000000;
    168    descriptor.checksum = (descriptor.checksum << 1);
    169    if (0x00000000 != overflow) {
    170      descriptor.checksum += 1;
    171    }
    172    descriptor.checksum += buffer[bytes];
    173  }
    174  descriptor.checksum = PR_htonl(descriptor.checksum);
    175 
    176  for (loop = 0; loop < shared->messages; ++loop) {
    177    if (shared->debug > 1) {
    178      PR_fprintf(debug_out, "[%d]socket ... ", loop);
    179    }
    180    clientSock = PR_NewTCPSocket();
    181    if (clientSock) {
    182      /*
    183       * We need to slow down the rate of generating connect requests,
    184       * otherwise the listen backlog queue on the accept side may
    185       * become full and we will get connection refused or timeout
    186       * error.
    187       */
    188 
    189      PR_Sleep(shared->dally);
    190      if (shared->debug > 1) {
    191        char buf[128];
    192        PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf));
    193        PR_fprintf(debug_out, "connecting to %s ... ", buf);
    194      }
    195      rv = PR_Connect(clientSock, &shared->serverAddress, Timeout(shared));
    196      if (PR_SUCCESS == rv) {
    197        PRInt32 descriptor_length =
    198            (loop < (shared->messages - 1)) ? shared->message_length : 0;
    199        descriptor.length = PR_htonl(descriptor_length);
    200        if (shared->debug > 1)
    201          PR_fprintf(debug_out, "sending %d bytes ... ", descriptor_length);
    202        CauseTimeout(shared); /* might cause server to timeout */
    203        bytes = PR_Send(clientSock, &descriptor, sizeof(descriptor), flags,
    204                        Timeout(shared));
    205        if (bytes != sizeof(descriptor)) {
    206          shared->failed = PR_TRUE;
    207          if (shared->debug > 0) {
    208            PL_FPrintError(debug_out, "PR_Send failed");
    209          }
    210        }
    211        if (0 != descriptor_length) {
    212          CauseTimeout(shared);
    213          bytes = PR_Send(clientSock, buffer, descriptor_length, flags,
    214                          Timeout(shared));
    215          if (bytes != descriptor_length) {
    216            shared->failed = PR_TRUE;
    217            if (shared->debug > 0) {
    218              PL_FPrintError(debug_out, "PR_Send failed");
    219            }
    220          }
    221        }
    222        if (shared->debug > 1) {
    223          PR_fprintf(debug_out, "closing ... ");
    224        }
    225        rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
    226        rv = PR_Close(clientSock);
    227        if (shared->debug > 1) {
    228          if (PR_SUCCESS == rv) {
    229            PR_fprintf(debug_out, "\n");
    230          } else {
    231            PL_FPrintError(debug_out, "shutdown failed");
    232          }
    233        }
    234      } else {
    235        if (shared->debug > 1) {
    236          PL_FPrintError(debug_out, "connect failed");
    237        }
    238        PR_Close(clientSock);
    239        if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR)) {
    240          if (MakeReceiver(shared) == PR_FAILURE) {
    241            break;
    242          }
    243        } else {
    244          if (shared->debug > 1) {
    245            PR_fprintf(debug_out, " exiting\n");
    246          }
    247          break;
    248        }
    249      }
    250    } else {
    251      shared->failed = PR_TRUE;
    252      if (shared->debug > 0) {
    253        PL_FPrintError(debug_out, "create socket");
    254      }
    255      break;
    256    }
    257  }
    258 
    259  PR_DELETE(buffer);
    260 } /* Connect */
    261 
    262 int Tmocon(int argc, char** argv) {
    263  /*
    264   * USAGE
    265   * -d       turn on debugging output                (default = off)
    266   * -v       turn on verbose output                  (default = off)
    267   * -h <n>   dns name of host serving the connection (default = self)
    268   * -i       dally intermittantly to cause timeouts  (default = off)
    269   * -m <n>   number of messages to send              (default = 100)
    270   * -s <n>   size of each message                    (default = 100)
    271   * -t <n>   number of threads sending               (default = 1)
    272   * -G       use global threads                      (default = local)
    273   * -T <n>   timeout on I/O operations (seconds)     (default = 10)
    274   * -D <n>   dally between connect requests (seconds)(default = 0)
    275   * -R       randomize the dally types around 'T'    (default = no)
    276   */
    277 
    278  PRStatus rv;
    279  int exitStatus;
    280  PLOptStatus os;
    281  Shared* shared = NULL;
    282  PRThread** thread = NULL;
    283  PRIntn index, threads = DEFAULT_THREADS;
    284  PRThreadScope thread_scope = PR_LOCAL_THREAD;
    285  PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT;
    286  PLOptState* opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:");
    287 
    288  shared = PR_NEWZAP(Shared);
    289 
    290  shared->debug = 0;
    291  shared->failed = PR_FALSE;
    292  shared->random = PR_FALSE;
    293  shared->messages = DEFAULT_MESSAGES;
    294  shared->message_length = DEFAULT_MESSAGESIZE;
    295 
    296  memset(&shared->serverAddress, 0, sizeof(shared->serverAddress));
    297  rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT,
    298                            &shared->serverAddress);
    299  PR_ASSERT(PR_SUCCESS == rv);
    300 
    301  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    302    if (PL_OPT_BAD == os) {
    303      continue;
    304    }
    305    switch (opt->option) {
    306      case 'd':
    307        if (0 == shared->debug) {
    308          shared->debug = 1;
    309        }
    310        break;
    311      case 'v':
    312        if (0 == shared->debug) {
    313          shared->debug = 2;
    314        }
    315        break;
    316      case 'i':
    317        shared->intermittant = PR_TRUE;
    318        break;
    319      case 'R':
    320        shared->random = PR_TRUE;
    321        break;
    322      case 'G':
    323        thread_scope = PR_GLOBAL_THREAD;
    324        break;
    325      case 'h': /* the value for backlock */
    326      {
    327        PRIntn es = 0;
    328        PRHostEnt host;
    329        char buffer[1024];
    330        (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host);
    331        es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &shared->serverAddress);
    332        PR_ASSERT(es > 0);
    333      } break;
    334      case 'm': /* number of messages to send */
    335        shared->messages = atoi(opt->value);
    336        break;
    337      case 't': /* number of threads sending */
    338        threads = atoi(opt->value);
    339        break;
    340      case 'D': /* dally time between transmissions */
    341        dally = atoi(opt->value);
    342        break;
    343      case 'T': /* timeout on I/O operations */
    344        timeout = atoi(opt->value);
    345        break;
    346      case 's': /* total size of each message */
    347        shared->message_length = atoi(opt->value);
    348        break;
    349      default:
    350        break;
    351    }
    352  }
    353  PL_DestroyOptState(opt);
    354 
    355  if (0 == timeout) {
    356    timeout = DEFAULT_TIMEOUT;
    357  }
    358  if (0 == threads) {
    359    threads = DEFAULT_THREADS;
    360  }
    361  if (0 == shared->messages) {
    362    shared->messages = DEFAULT_MESSAGES;
    363  }
    364  if (0 == shared->message_length) {
    365    shared->message_length = DEFAULT_MESSAGESIZE;
    366  }
    367 
    368  shared->dally = PR_SecondsToInterval(dally);
    369  shared->timeout = PR_SecondsToInterval(timeout);
    370 
    371  thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
    372 
    373  for (index = 0; index < threads; ++index)
    374    thread[index] =
    375        PR_CreateThread(PR_USER_THREAD, Connect, shared, PR_PRIORITY_NORMAL,
    376                        thread_scope, PR_JOINABLE_THREAD, 0);
    377  for (index = 0; index < threads; ++index) {
    378    rv = PR_JoinThread(thread[index]);
    379  }
    380 
    381  PR_DELETE(thread);
    382 
    383  PR_fprintf(PR_GetSpecialFD(PR_StandardError), "%s\n",
    384             ((shared->failed) ? "FAILED" : "PASSED"));
    385  exitStatus = (shared->failed) ? 1 : 0;
    386  PR_DELETE(shared);
    387  return exitStatus;
    388 }
    389 
    390 int main(int argc, char** argv) {
    391  return (PR_VersionCheck(PR_VERSION)) ? PR_Initialize(Tmocon, argc, argv, 4)
    392                                       : -1;
    393 } /* main */
    394 
    395 /* tmocon.c */