tor-browser

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

writev.c (6335B)


      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 
      8 #include "plgetopt.h"
      9 
     10 #include <stdlib.h>
     11 #include <string.h>
     12 
     13 #ifndef IOV_MAX
     14 #  define IOV_MAX 16
     15 #endif
     16 
     17 #ifdef DEBUG
     18 #  define PORT_INC_DO +100
     19 #else
     20 #  define PORT_INC_DO
     21 #endif
     22 #ifdef IS_64
     23 #  define PORT_INC_3264 +200
     24 #else
     25 #  define PORT_INC_3264
     26 #endif
     27 
     28 #define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
     29 
     30 int PR_CALLBACK Writev(int argc, char** argv) {
     31  PRStatus rv;
     32  PRNetAddr serverAddr;
     33  PRFileDesc *clientSock, *debug = NULL;
     34 
     35  char* buffer = NULL;
     36  PRIOVec* iov = NULL;
     37  PRBool passed = PR_TRUE;
     38  PRIntervalTime timein, elapsed, timeout;
     39  PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0;
     40  PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments;
     41  PRInt32 message_length = 100, fragment_length = 100, messages = 100;
     42  struct Descriptor {
     43    PRInt32 length;
     44    PRUint32 checksum;
     45  } descriptor;
     46 
     47  /*
     48   * USAGE
     49   * -h       dns name of host serving the connection (default = self)
     50   * -m       number of messages to send              (default = 100)
     51   * -s       size of each message                    (default = 100)
     52   * -f       size of each message fragment           (default = 100)
     53   */
     54 
     55  PLOptStatus os;
     56  PLOptState* opt = PL_CreateOptState(argc, argv, "dh:m:s:f:");
     57 
     58  rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr);
     59  PR_ASSERT(PR_SUCCESS == rv);
     60 
     61  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
     62    if (PL_OPT_BAD == os) {
     63      continue;
     64    }
     65    switch (opt->option) {
     66      case 'h': /* the remote host */
     67      {
     68        PRIntn es = 0;
     69        PRHostEnt host;
     70        char buffer[1024];
     71        (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host);
     72        es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr);
     73        PR_ASSERT(es > 0);
     74      } break;
     75      case 'd': /* debug mode */
     76        debug = PR_GetSpecialFD(PR_StandardError);
     77        break;
     78      case 'm': /* number of messages to send */
     79        messages = atoi(opt->value);
     80        break;
     81      case 's': /* total size of each message */
     82        message_length = atoi(opt->value);
     83        break;
     84      case 'f': /* size of each message fragment */
     85        fragment_length = atoi(opt->value);
     86        break;
     87      default:
     88        break;
     89    }
     90  }
     91  PL_DestroyOptState(opt);
     92 
     93  buffer = (char*)malloc(message_length);
     94 
     95  number_fragments =
     96      (message_length + fragment_length - 1) / fragment_length + 1;
     97  while (IOV_MAX < number_fragments) {
     98    fragment_length = message_length / (IOV_MAX - 2);
     99    number_fragments =
    100        (message_length + fragment_length - 1) / fragment_length + 1;
    101    if (NULL != debug)
    102      PR_fprintf(debug, "Too many fragments - reset fragment length to %ld\n",
    103                 fragment_length);
    104  }
    105  iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec));
    106 
    107  iov[0].iov_base = (char*)&descriptor;
    108  iov[0].iov_len = sizeof(descriptor);
    109  for (iov_index = 1; iov_index < number_fragments; ++iov_index) {
    110    iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length;
    111    iov[iov_index].iov_len = fragment_length;
    112  }
    113 
    114  for (bytes = 0; bytes < message_length; ++bytes) {
    115    buffer[bytes] = (char)bytes;
    116  }
    117 
    118  timeout = PR_SecondsToInterval(1);
    119 
    120  for (loop = 0; loop < messages; ++loop) {
    121    if (NULL != debug) {
    122      PR_fprintf(debug, "[%d]socket ... ", loop);
    123    }
    124    clientSock = PR_NewTCPSocket();
    125    if (clientSock) {
    126      timein = PR_IntervalNow();
    127      if (NULL != debug) {
    128        PR_fprintf(debug, "connecting ... ");
    129      }
    130      rv = PR_Connect(clientSock, &serverAddr, timeout);
    131      if (PR_SUCCESS == rv) {
    132        descriptor.checksum = 0;
    133        descriptor.length = (loop < (messages - 1)) ? message_length : 0;
    134        if (0 == descriptor.length) {
    135          number_fragments = 1;
    136        } else
    137          for (iov_index = 0; iov_index < descriptor.length; ++iov_index) {
    138            PRUint32 overflow = descriptor.checksum & 0x80000000;
    139            descriptor.checksum = (descriptor.checksum << 1);
    140            if (0x00000000 != overflow) {
    141              descriptor.checksum += 1;
    142            }
    143            descriptor.checksum += buffer[iov_index];
    144          }
    145        if (NULL != debug)
    146          PR_fprintf(debug, "sending %d bytes ... ", descriptor.length);
    147 
    148        /* then, at the last moment ... */
    149        descriptor.length = PR_ntohl(descriptor.length);
    150        descriptor.checksum = PR_ntohl(descriptor.checksum);
    151 
    152        bytes = PR_Writev(clientSock, iov, number_fragments, timeout);
    153        if (NULL != debug) {
    154          PR_fprintf(debug, "closing ... ");
    155        }
    156        rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
    157        rv = PR_Close(clientSock);
    158        if (NULL != debug)
    159          PR_fprintf(debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad"));
    160        elapsed = PR_IntervalNow() - timein;
    161        if (elapsed < tmo_min) {
    162          tmo_min = elapsed;
    163        } else if (elapsed > tmo_max) {
    164          tmo_max = elapsed;
    165        }
    166        tmo_elapsed += elapsed;
    167        tmo_counted += 1;
    168      } else {
    169        if (NULL != debug)
    170          PR_fprintf(debug, "failed - retrying (%d, %d)\n", PR_GetError(),
    171                     PR_GetOSError());
    172        PR_Close(clientSock);
    173      }
    174    } else if (NULL != debug) {
    175      PR_fprintf(debug, "unable to create client socket\n");
    176      passed = PR_FALSE;
    177    }
    178  }
    179  if (NULL != debug) {
    180    if (0 == tmo_counted) {
    181      PR_fprintf(debug, "No connection made\n");
    182    } else {
    183      PR_fprintf(debug, "\nTimings: %d [%d] %d (microseconds)\n",
    184                 PR_IntervalToMicroseconds(tmo_min),
    185                 PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted),
    186                 PR_IntervalToMicroseconds(tmo_max));
    187    }
    188  }
    189 
    190  PR_DELETE(buffer);
    191  PR_DELETE(iov);
    192 
    193  PR_fprintf(PR_GetSpecialFD(PR_StandardError), "%s\n",
    194             (passed) ? "PASSED" : "FAILED");
    195  return (passed) ? 0 : 1;
    196 }
    197 
    198 int main(int argc, char** argv) {
    199  return (PR_VersionCheck(PR_VERSION)) ? PR_Initialize(Writev, argc, argv, 4)
    200                                       : -1;
    201 } /* main */
    202 
    203 /* writev.c */