tor-browser

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

y2ktmo.c (16221B)


      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 * Test: y2ktmo
      8 *
      9 * Description:
     10 *   This test tests the interval time facilities in NSPR for Y2K
     11 *   compliance.  All the functions that take a timeout argument
     12 *   are tested: PR_Sleep, socket I/O (PR_Accept is taken as a
     13 *   representative), PR_Poll, PR_WaitCondVar, PR_Wait, and
     14 *   PR_CWait.  A thread of each thread scope (local, global, and
     15 *   global bound) is created to call each of these functions.
     16 *   The test should be started at the specified number of seconds
     17 *   (called the lead time) before a Y2K rollover test date.  The
     18 *   timeout values for these threads will span over the rollover
     19 *   date by at least the specified number of seconds.  For
     20 *   example, if the lead time is 5 seconds, the test should
     21 *   be started at time (D - 5), where D is a rollover date, and
     22 *   the threads will time out at or after time (D + 5).  The
     23 *   timeout values for the threads are spaced one second apart.
     24 *
     25 *   When a thread times out, it calls PR_IntervalNow() to verify
     26 *   that it did wait for the specified time.  In addition, it
     27 *   calls a platform-native function to verify the actual elapsed
     28 *   time again, to rule out the possibility that PR_IntervalNow()
     29 *   is broken.  We allow the actual elapsed time to deviate from
     30 *   the specified timeout by a certain tolerance (in milliseconds).
     31 */
     32 
     33 #include "nspr.h"
     34 #include "plgetopt.h"
     35 
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #if defined(XP_UNIX)
     40 #  include <sys/time.h> /* for gettimeofday */
     41 #endif
     42 #if defined(WIN32)
     43 #  if defined(WINCE)
     44 #    include <windows.h>
     45 #  else
     46 #    include <sys/types.h>
     47 #    include <sys/timeb.h> /* for _ftime */
     48 #  endif
     49 #endif
     50 
     51 #define DEFAULT_LEAD_TIME_SECS 5
     52 #define DEFAULT_TOLERANCE_MSECS 500
     53 
     54 static PRBool debug_mode = PR_FALSE;
     55 static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
     56 static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
     57 static PRIntervalTime start_time;
     58 static PRIntervalTime tolerance;
     59 
     60 #if defined(XP_UNIX)
     61 static struct timeval start_time_tv;
     62 #endif
     63 #if defined(WIN32)
     64 #  if defined(WINCE)
     65 static DWORD start_time_tick;
     66 #  else
     67 static struct _timeb start_time_tb;
     68 #  endif
     69 #endif
     70 
     71 static void SleepThread(void* arg) {
     72  PRIntervalTime timeout = (PRIntervalTime)arg;
     73  PRIntervalTime elapsed;
     74 #if defined(XP_UNIX) || defined(WIN32)
     75  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
     76  PRInt32 elapsed_msecs;
     77 #endif
     78 #if defined(XP_UNIX)
     79  struct timeval end_time_tv;
     80 #endif
     81 #if defined(WIN32) && !defined(WINCE)
     82  struct _timeb end_time_tb;
     83 #endif
     84 
     85  if (PR_Sleep(timeout) == PR_FAILURE) {
     86    fprintf(stderr, "PR_Sleep failed\n");
     87    exit(1);
     88  }
     89  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
     90  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
     91    fprintf(stderr, "timeout wrong\n");
     92    exit(1);
     93  }
     94 #if defined(XP_UNIX)
     95  gettimeofday(&end_time_tv, NULL);
     96  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
     97                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
     98 #endif
     99 #if defined(WIN32)
    100 #  if defined(WINCE)
    101  elapsed_msecs = GetTickCount() - start_time_tick;
    102 #  else
    103  _ftime(&end_time_tb);
    104  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    105                  (end_time_tb.millitm - start_time_tb.millitm);
    106 #  endif
    107 #endif
    108 #if defined(XP_UNIX) || defined(WIN32)
    109  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    110      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    111    fprintf(stderr, "timeout wrong\n");
    112    exit(1);
    113  }
    114 #endif
    115  if (debug_mode) {
    116    fprintf(stderr, "Sleep thread (scope %d) done\n",
    117            PR_GetThreadScope(PR_GetCurrentThread()));
    118  }
    119 }
    120 
    121 static void AcceptThread(void* arg) {
    122  PRIntervalTime timeout = (PRIntervalTime)arg;
    123  PRIntervalTime elapsed;
    124 #if defined(XP_UNIX) || defined(WIN32)
    125  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    126  PRInt32 elapsed_msecs;
    127 #endif
    128 #if defined(XP_UNIX)
    129  struct timeval end_time_tv;
    130 #endif
    131 #if defined(WIN32) && !defined(WINCE)
    132  struct _timeb end_time_tb;
    133 #endif
    134  PRFileDesc* sock;
    135  PRNetAddr addr;
    136  PRFileDesc* accepted;
    137 
    138  sock = PR_NewTCPSocket();
    139  if (sock == NULL) {
    140    fprintf(stderr, "PR_NewTCPSocket failed\n");
    141    exit(1);
    142  }
    143  memset(&addr, 0, sizeof(addr));
    144  addr.inet.family = PR_AF_INET;
    145  addr.inet.port = 0;
    146  addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    147  if (PR_Bind(sock, &addr) == PR_FAILURE) {
    148    fprintf(stderr, "PR_Bind failed\n");
    149    exit(1);
    150  }
    151  if (PR_Listen(sock, 5) == PR_FAILURE) {
    152    fprintf(stderr, "PR_Listen failed\n");
    153    exit(1);
    154  }
    155  accepted = PR_Accept(sock, NULL, timeout);
    156  if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
    157    fprintf(stderr, "PR_Accept did not time out\n");
    158    exit(1);
    159  }
    160  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    161  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    162    fprintf(stderr, "timeout wrong\n");
    163    exit(1);
    164  }
    165 #if defined(XP_UNIX)
    166  gettimeofday(&end_time_tv, NULL);
    167  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
    168                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
    169 #endif
    170 #if defined(WIN32)
    171 #  if defined(WINCE)
    172  elapsed_msecs = GetTickCount() - start_time_tick;
    173 #  else
    174  _ftime(&end_time_tb);
    175  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    176                  (end_time_tb.millitm - start_time_tb.millitm);
    177 #  endif
    178 #endif
    179 #if defined(XP_UNIX) || defined(WIN32)
    180  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    181      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    182    fprintf(stderr, "timeout wrong\n");
    183    exit(1);
    184  }
    185 #endif
    186  if (PR_Close(sock) == PR_FAILURE) {
    187    fprintf(stderr, "PR_Close failed\n");
    188    exit(1);
    189  }
    190  if (debug_mode) {
    191    fprintf(stderr, "Accept thread (scope %d) done\n",
    192            PR_GetThreadScope(PR_GetCurrentThread()));
    193  }
    194 }
    195 
    196 static void PollThread(void* arg) {
    197  PRIntervalTime timeout = (PRIntervalTime)arg;
    198  PRIntervalTime elapsed;
    199 #if defined(XP_UNIX) || defined(WIN32)
    200  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    201  PRInt32 elapsed_msecs;
    202 #endif
    203 #if defined(XP_UNIX)
    204  struct timeval end_time_tv;
    205 #endif
    206 #if defined(WIN32) && !defined(WINCE)
    207  struct _timeb end_time_tb;
    208 #endif
    209  PRFileDesc* sock;
    210  PRNetAddr addr;
    211  PRPollDesc pd;
    212  PRIntn rv;
    213 
    214  sock = PR_NewTCPSocket();
    215  if (sock == NULL) {
    216    fprintf(stderr, "PR_NewTCPSocket failed\n");
    217    exit(1);
    218  }
    219  memset(&addr, 0, sizeof(addr));
    220  addr.inet.family = PR_AF_INET;
    221  addr.inet.port = 0;
    222  addr.inet.ip = PR_htonl(PR_INADDR_ANY);
    223  if (PR_Bind(sock, &addr) == PR_FAILURE) {
    224    fprintf(stderr, "PR_Bind failed\n");
    225    exit(1);
    226  }
    227  if (PR_Listen(sock, 5) == PR_FAILURE) {
    228    fprintf(stderr, "PR_Listen failed\n");
    229    exit(1);
    230  }
    231  pd.fd = sock;
    232  pd.in_flags = PR_POLL_READ;
    233  rv = PR_Poll(&pd, 1, timeout);
    234  if (rv != 0) {
    235    fprintf(stderr, "PR_Poll did not time out\n");
    236    exit(1);
    237  }
    238  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    239  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    240    fprintf(stderr, "timeout wrong\n");
    241    exit(1);
    242  }
    243 #if defined(XP_UNIX)
    244  gettimeofday(&end_time_tv, NULL);
    245  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
    246                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
    247 #endif
    248 #if defined(WIN32)
    249 #  if defined(WINCE)
    250  elapsed_msecs = GetTickCount() - start_time_tick;
    251 #  else
    252  _ftime(&end_time_tb);
    253  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    254                  (end_time_tb.millitm - start_time_tb.millitm);
    255 #  endif
    256 #endif
    257 #if defined(XP_UNIX) || defined(WIN32)
    258  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    259      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    260    fprintf(stderr, "timeout wrong\n");
    261    exit(1);
    262  }
    263 #endif
    264  if (PR_Close(sock) == PR_FAILURE) {
    265    fprintf(stderr, "PR_Close failed\n");
    266    exit(1);
    267  }
    268  if (debug_mode) {
    269    fprintf(stderr, "Poll thread (scope %d) done\n",
    270            PR_GetThreadScope(PR_GetCurrentThread()));
    271  }
    272 }
    273 
    274 static void WaitCondVarThread(void* arg) {
    275  PRIntervalTime timeout = (PRIntervalTime)arg;
    276  PRIntervalTime elapsed;
    277 #if defined(XP_UNIX) || defined(WIN32)
    278  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    279  PRInt32 elapsed_msecs;
    280 #endif
    281 #if defined(XP_UNIX)
    282  struct timeval end_time_tv;
    283 #endif
    284 #if defined(WIN32) && !defined(WINCE)
    285  struct _timeb end_time_tb;
    286 #endif
    287  PRLock* ml;
    288  PRCondVar* cv;
    289 
    290  ml = PR_NewLock();
    291  if (ml == NULL) {
    292    fprintf(stderr, "PR_NewLock failed\n");
    293    exit(1);
    294  }
    295  cv = PR_NewCondVar(ml);
    296  if (cv == NULL) {
    297    fprintf(stderr, "PR_NewCondVar failed\n");
    298    exit(1);
    299  }
    300  PR_Lock(ml);
    301  PR_WaitCondVar(cv, timeout);
    302  PR_Unlock(ml);
    303  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    304  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    305    fprintf(stderr, "timeout wrong\n");
    306    exit(1);
    307  }
    308 #if defined(XP_UNIX)
    309  gettimeofday(&end_time_tv, NULL);
    310  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
    311                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
    312 #endif
    313 #if defined(WIN32)
    314 #  if defined(WINCE)
    315  elapsed_msecs = GetTickCount() - start_time_tick;
    316 #  else
    317  _ftime(&end_time_tb);
    318  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    319                  (end_time_tb.millitm - start_time_tb.millitm);
    320 #  endif
    321 #endif
    322 #if defined(XP_UNIX) || defined(WIN32)
    323  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    324      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    325    fprintf(stderr, "timeout wrong\n");
    326    exit(1);
    327  }
    328 #endif
    329  PR_DestroyCondVar(cv);
    330  PR_DestroyLock(ml);
    331  if (debug_mode) {
    332    fprintf(stderr, "wait cond var thread (scope %d) done\n",
    333            PR_GetThreadScope(PR_GetCurrentThread()));
    334  }
    335 }
    336 
    337 static void WaitMonitorThread(void* arg) {
    338  PRIntervalTime timeout = (PRIntervalTime)arg;
    339  PRIntervalTime elapsed;
    340 #if defined(XP_UNIX) || defined(WIN32)
    341  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    342  PRInt32 elapsed_msecs;
    343 #endif
    344 #if defined(XP_UNIX)
    345  struct timeval end_time_tv;
    346 #endif
    347 #if defined(WIN32) && !defined(WINCE)
    348  struct _timeb end_time_tb;
    349 #endif
    350  PRMonitor* mon;
    351 
    352  mon = PR_NewMonitor();
    353  if (mon == NULL) {
    354    fprintf(stderr, "PR_NewMonitor failed\n");
    355    exit(1);
    356  }
    357  PR_EnterMonitor(mon);
    358  PR_Wait(mon, timeout);
    359  PR_ExitMonitor(mon);
    360  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    361  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    362    fprintf(stderr, "timeout wrong\n");
    363    exit(1);
    364  }
    365 #if defined(XP_UNIX)
    366  gettimeofday(&end_time_tv, NULL);
    367  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
    368                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
    369 #endif
    370 #if defined(WIN32)
    371 #  if defined(WINCE)
    372  elapsed_msecs = GetTickCount() - start_time_tick;
    373 #  else
    374  _ftime(&end_time_tb);
    375  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    376                  (end_time_tb.millitm - start_time_tb.millitm);
    377 #  endif
    378 #endif
    379 #if defined(XP_UNIX) || defined(WIN32)
    380  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    381      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    382    fprintf(stderr, "timeout wrong\n");
    383    exit(1);
    384  }
    385 #endif
    386  PR_DestroyMonitor(mon);
    387  if (debug_mode) {
    388    fprintf(stderr, "wait monitor thread (scope %d) done\n",
    389            PR_GetThreadScope(PR_GetCurrentThread()));
    390  }
    391 }
    392 
    393 static void WaitCMonitorThread(void* arg) {
    394  PRIntervalTime timeout = (PRIntervalTime)arg;
    395  PRIntervalTime elapsed;
    396 #if defined(XP_UNIX) || defined(WIN32)
    397  PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    398  PRInt32 elapsed_msecs;
    399 #endif
    400 #if defined(XP_UNIX)
    401  struct timeval end_time_tv;
    402 #endif
    403 #if defined(WIN32) && !defined(WINCE)
    404  struct _timeb end_time_tb;
    405 #endif
    406  int dummy;
    407 
    408  PR_CEnterMonitor(&dummy);
    409  PR_CWait(&dummy, timeout);
    410  PR_CExitMonitor(&dummy);
    411  elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    412  if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    413    fprintf(stderr, "timeout wrong\n");
    414    exit(1);
    415  }
    416 #if defined(XP_UNIX)
    417  gettimeofday(&end_time_tv, NULL);
    418  elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) +
    419                  (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000;
    420 #endif
    421 #if defined(WIN32)
    422 #  if defined(WINCE)
    423  elapsed_msecs = GetTickCount() - start_time_tick;
    424 #  else
    425  _ftime(&end_time_tb);
    426  elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) +
    427                  (end_time_tb.millitm - start_time_tb.millitm);
    428 #  endif
    429 #endif
    430 #if defined(XP_UNIX) || defined(WIN32)
    431  if (elapsed_msecs + tolerance_msecs < timeout_msecs ||
    432      elapsed_msecs > timeout_msecs + tolerance_msecs) {
    433    fprintf(stderr, "timeout wrong\n");
    434    exit(1);
    435  }
    436 #endif
    437  if (debug_mode) {
    438    fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
    439            PR_GetThreadScope(PR_GetCurrentThread()));
    440  }
    441 }
    442 
    443 typedef void (*NSPRThreadFunc)(void*);
    444 
    445 static NSPRThreadFunc threadFuncs[] = {SleepThread,       AcceptThread,
    446                                       PollThread,        WaitCondVarThread,
    447                                       WaitMonitorThread, WaitCMonitorThread};
    448 
    449 static PRThreadScope threadScopes[] = {PR_LOCAL_THREAD, PR_GLOBAL_THREAD,
    450                                       PR_GLOBAL_BOUND_THREAD};
    451 
    452 static void Help(void) {
    453  fprintf(stderr, "y2ktmo test program usage:\n");
    454  fprintf(stderr, "\t-d           debug mode         (FALSE)\n");
    455  fprintf(stderr, "\t-l <secs>    lead time          (%d)\n",
    456          DEFAULT_LEAD_TIME_SECS);
    457  fprintf(stderr, "\t-t <msecs>   tolerance          (%d)\n",
    458          DEFAULT_TOLERANCE_MSECS);
    459  fprintf(stderr, "\t-h           this message\n");
    460 } /* Help */
    461 
    462 int main(int argc, char** argv) {
    463  PRThread** threads;
    464  int num_thread_funcs = sizeof(threadFuncs) / sizeof(NSPRThreadFunc);
    465  int num_thread_scopes = sizeof(threadScopes) / sizeof(PRThreadScope);
    466  int i, j;
    467  int idx;
    468  PRInt32 secs;
    469  PLOptStatus os;
    470  PLOptState* opt = PL_CreateOptState(argc, argv, "dl:t:h");
    471 
    472  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    473    if (PL_OPT_BAD == os) {
    474      continue;
    475    }
    476    switch (opt->option) {
    477      case 'd': /* debug mode */
    478        debug_mode = PR_TRUE;
    479        break;
    480      case 'l': /* lead time */
    481        lead_time_secs = atoi(opt->value);
    482        break;
    483      case 't': /* tolerance */
    484        tolerance_msecs = atoi(opt->value);
    485        break;
    486      case 'h':
    487      default:
    488        Help();
    489        return 2;
    490    }
    491  }
    492  PL_DestroyOptState(opt);
    493 
    494  if (debug_mode) {
    495    fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
    496    fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
    497  }
    498 
    499  start_time = PR_IntervalNow();
    500 #if defined(XP_UNIX)
    501  gettimeofday(&start_time_tv, NULL);
    502 #endif
    503 #if defined(WIN32)
    504 #  ifdef WINCE
    505  start_time_tick = GetTickCount();
    506 #  else
    507  _ftime(&start_time_tb);
    508 #  endif
    509 #endif
    510  tolerance = PR_MillisecondsToInterval(tolerance_msecs);
    511 
    512  threads = PR_Malloc(num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
    513  if (threads == NULL) {
    514    fprintf(stderr, "PR_Malloc failed\n");
    515    exit(1);
    516  }
    517 
    518  /* start to time out 5 seconds after a rollover date */
    519  secs = lead_time_secs + 5;
    520  idx = 0;
    521  for (i = 0; i < num_thread_scopes; i++) {
    522    for (j = 0; j < num_thread_funcs; j++) {
    523      threads[idx] = PR_CreateThread(
    524          PR_USER_THREAD, threadFuncs[j], (void*)PR_SecondsToInterval(secs),
    525          PR_PRIORITY_NORMAL, threadScopes[i], PR_JOINABLE_THREAD, 0);
    526      if (threads[idx] == NULL) {
    527        fprintf(stderr, "PR_CreateThread failed\n");
    528        exit(1);
    529      }
    530      secs++;
    531      idx++;
    532    }
    533  }
    534  for (idx = 0; idx < num_thread_scopes * num_thread_funcs; idx++) {
    535    if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
    536      fprintf(stderr, "PR_JoinThread failed\n");
    537      exit(1);
    538    }
    539  }
    540  PR_Free(threads);
    541  printf("PASS\n");
    542  return 0;
    543 }