tor-browser

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

nblayer.c (22872B)


      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 "prmem.h"
      8 #include "prprf.h"
      9 #include "prlog.h"
     10 #include "prerror.h"
     11 #include "prnetdb.h"
     12 #include "prthread.h"
     13 
     14 #include "plerror.h"
     15 #include "plgetopt.h"
     16 
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 /*
     21 ** Testing layering of I/O
     22 **
     23 **      The layered server
     24 ** A thread that acts as a server. It creates a TCP listener with a dummy
     25 ** layer pushed on top. Then listens for incoming connections. Each connection
     26 ** request for connection will be layered as well, accept one request, echo
     27 ** it back and close.
     28 **
     29 **      The layered client
     30 ** Pretty much what you'd expect.
     31 */
     32 
     33 static PRFileDesc* logFile;
     34 static PRDescIdentity identity;
     35 static PRNetAddr server_address;
     36 
     37 static PRIOMethods myMethods;
     38 
     39 typedef enum { rcv_get_debit, rcv_send_credit, rcv_data } RcvState;
     40 typedef enum { xmt_send_debit, xmt_recv_credit, xmt_data } XmtState;
     41 
     42 struct PRFilePrivate {
     43  RcvState rcvstate;
     44  XmtState xmtstate;
     45  PRInt32 rcvreq, rcvinprogress;
     46  PRInt32 xmtreq, xmtinprogress;
     47 };
     48 
     49 typedef enum Verbosity { silent, quiet, chatty, noisy } Verbosity;
     50 
     51 static PRIntn minor_iterations = 5;
     52 static PRIntn major_iterations = 1;
     53 static Verbosity verbosity = quiet;
     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 static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264;
     67 
     68 static PRFileDesc* PushLayer(PRFileDesc* stack) {
     69  PRStatus rv;
     70  PRFileDesc* layer = PR_CreateIOLayerStub(identity, &myMethods);
     71  layer->secret = PR_NEWZAP(PRFilePrivate);
     72  rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
     73  PR_ASSERT(PR_SUCCESS == rv);
     74  if (verbosity > quiet) {
     75    PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
     76  }
     77  return stack;
     78 } /* PushLayer */
     79 
     80 static PRFileDesc* PopLayer(PRFileDesc* stack) {
     81  PRFileDesc* popped = PR_PopIOLayer(stack, identity);
     82  if (verbosity > quiet) {
     83    PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
     84  }
     85  PR_DELETE(popped->secret);
     86  popped->dtor(popped);
     87  return stack;
     88 } /* PopLayer */
     89 
     90 static void PR_CALLBACK Client(void* arg) {
     91  PRStatus rv;
     92  PRIntn mits;
     93  PRInt32 ready;
     94  PRUint8 buffer[100];
     95  PRPollDesc polldesc;
     96  PRIntn empty_flags = 0;
     97  PRIntn bytes_read, bytes_sent;
     98  PRFileDesc* stack = (PRFileDesc*)arg;
     99 
    100  /* Initialize the buffer so that Purify won't complain */
    101  memset(buffer, 0, sizeof(buffer));
    102 
    103  rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
    104  if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError())) {
    105    if (verbosity > quiet) {
    106      PR_fprintf(logFile, "Client connect 'in progress'\n");
    107    }
    108    do {
    109      polldesc.fd = stack;
    110      polldesc.out_flags = 0;
    111      polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
    112      ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    113      if ((1 != ready) /* if not 1, then we're dead */
    114          || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    115        PR_NOT_REACHED("Whoa!");
    116        break;
    117      }
    118      if (verbosity > quiet)
    119        PR_fprintf(logFile, "Client connect 'in progress' [0x%x]\n",
    120                   polldesc.out_flags);
    121      rv = PR_GetConnectStatus(&polldesc);
    122      if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR != PR_GetError())) {
    123        break;
    124      }
    125    } while (PR_FAILURE == rv);
    126  }
    127  PR_ASSERT(PR_SUCCESS == rv);
    128  if (verbosity > chatty) {
    129    PR_fprintf(logFile, "Client created connection\n");
    130  }
    131 
    132  for (mits = 0; mits < minor_iterations; ++mits) {
    133    bytes_sent = 0;
    134    if (verbosity > quiet) {
    135      PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer));
    136    }
    137    do {
    138      if (verbosity > chatty)
    139        PR_fprintf(logFile, "Client sending %d bytes\n",
    140                   sizeof(buffer) - bytes_sent);
    141      ready = PR_Send(stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent,
    142                      empty_flags, PR_INTERVAL_NO_TIMEOUT);
    143      if (verbosity > chatty) {
    144        PR_fprintf(logFile, "Client send status [%d]\n", ready);
    145      }
    146      if (0 < ready) {
    147        bytes_sent += ready;
    148      } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    149        polldesc.fd = stack;
    150        polldesc.out_flags = 0;
    151        polldesc.in_flags = PR_POLL_WRITE;
    152        ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    153        if ((1 != ready) /* if not 1, then we're dead */
    154            || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    155          PR_NOT_REACHED("Whoa!");
    156          break;
    157        }
    158      } else {
    159        break;
    160      }
    161    } while (bytes_sent < sizeof(buffer));
    162    PR_ASSERT(sizeof(buffer) == bytes_sent);
    163 
    164    bytes_read = 0;
    165    do {
    166      if (verbosity > chatty)
    167        PR_fprintf(logFile, "Client receiving %d bytes\n",
    168                   bytes_sent - bytes_read);
    169      ready = PR_Recv(stack, buffer + bytes_read, bytes_sent - bytes_read,
    170                      empty_flags, PR_INTERVAL_NO_TIMEOUT);
    171      if (verbosity > chatty)
    172        PR_fprintf(logFile, "Client receive status [%d]\n", ready);
    173      if (0 < ready) {
    174        bytes_read += ready;
    175      } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    176        polldesc.fd = stack;
    177        polldesc.out_flags = 0;
    178        polldesc.in_flags = PR_POLL_READ;
    179        ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    180        if ((1 != ready) /* if not 1, then we're dead */
    181            || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    182          PR_NOT_REACHED("Whoa!");
    183          break;
    184        }
    185      } else {
    186        break;
    187      }
    188    } while (bytes_read < bytes_sent);
    189    if (verbosity > chatty) {
    190      PR_fprintf(logFile, "Client received %d bytes\n", bytes_read);
    191    }
    192    PR_ASSERT(bytes_read == bytes_sent);
    193  }
    194 
    195  if (verbosity > quiet) {
    196    PR_fprintf(logFile, "Client shutting down stack\n");
    197  }
    198 
    199  rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH);
    200  PR_ASSERT(PR_SUCCESS == rv);
    201 } /* Client */
    202 
    203 static void PR_CALLBACK Server(void* arg) {
    204  PRStatus rv;
    205  PRInt32 ready;
    206  PRUint8 buffer[100];
    207  PRFileDesc* service;
    208  PRUintn empty_flags = 0;
    209  struct PRPollDesc polldesc;
    210  PRIntn bytes_read, bytes_sent;
    211  PRFileDesc* stack = (PRFileDesc*)arg;
    212  PRNetAddr client_address;
    213 
    214  do {
    215    if (verbosity > chatty) {
    216      PR_fprintf(logFile, "Server accepting connection\n");
    217    }
    218    service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
    219    if (verbosity > chatty) {
    220      PR_fprintf(logFile, "Server accept status [0x%p]\n", service);
    221    }
    222    if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    223      polldesc.fd = stack;
    224      polldesc.out_flags = 0;
    225      polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
    226      ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    227      if ((1 != ready) /* if not 1, then we're dead */
    228          || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    229        PR_NOT_REACHED("Whoa!");
    230        break;
    231      }
    232    }
    233  } while (NULL == service);
    234  PR_ASSERT(NULL != service);
    235 
    236  if (verbosity > quiet) {
    237    PR_fprintf(logFile, "Server accepting connection\n");
    238  }
    239 
    240  do {
    241    bytes_read = 0;
    242    do {
    243      if (verbosity > chatty)
    244        PR_fprintf(logFile, "Server receiving %d bytes\n",
    245                   sizeof(buffer) - bytes_read);
    246      ready = PR_Recv(service, buffer + bytes_read, sizeof(buffer) - bytes_read,
    247                      empty_flags, PR_INTERVAL_NO_TIMEOUT);
    248      if (verbosity > chatty) {
    249        PR_fprintf(logFile, "Server receive status [%d]\n", ready);
    250      }
    251      if (0 < ready) {
    252        bytes_read += ready;
    253      } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    254        polldesc.fd = service;
    255        polldesc.out_flags = 0;
    256        polldesc.in_flags = PR_POLL_READ;
    257        ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    258        if ((1 != ready) /* if not 1, then we're dead */
    259            || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    260          PR_NOT_REACHED("Whoa!");
    261          break;
    262        }
    263      } else {
    264        break;
    265      }
    266    } while (bytes_read < sizeof(buffer));
    267 
    268    if (0 != bytes_read) {
    269      if (verbosity > chatty) {
    270        PR_fprintf(logFile, "Server received %d bytes\n", bytes_read);
    271      }
    272      PR_ASSERT(bytes_read > 0);
    273 
    274      bytes_sent = 0;
    275      do {
    276        ready = PR_Send(service, buffer + bytes_sent, bytes_read - bytes_sent,
    277                        empty_flags, PR_INTERVAL_NO_TIMEOUT);
    278        if (0 < ready) {
    279          bytes_sent += ready;
    280        } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    281          polldesc.fd = service;
    282          polldesc.out_flags = 0;
    283          polldesc.in_flags = PR_POLL_WRITE;
    284          ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
    285          if ((1 != ready) /* if not 1, then we're dead */
    286              || (0 == (polldesc.in_flags & polldesc.out_flags))) {
    287            PR_NOT_REACHED("Whoa!");
    288            break;
    289          }
    290        } else {
    291          break;
    292        }
    293      } while (bytes_sent < bytes_read);
    294      PR_ASSERT(bytes_read == bytes_sent);
    295      if (verbosity > chatty) {
    296        PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
    297      }
    298    }
    299  } while (0 != bytes_read);
    300 
    301  if (verbosity > quiet) {
    302    PR_fprintf(logFile, "Server shutting down stack\n");
    303  }
    304  rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH);
    305  PR_ASSERT(PR_SUCCESS == rv);
    306  rv = PR_Close(service);
    307  PR_ASSERT(PR_SUCCESS == rv);
    308 
    309 } /* Server */
    310 
    311 static PRStatus PR_CALLBACK MyClose(PRFileDesc* fd) {
    312  PR_DELETE(fd->secret); /* manage my secret file object */
    313  return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */
    314 } /* MyClose */
    315 
    316 static PRInt16 PR_CALLBACK MyPoll(PRFileDesc* fd, PRInt16 in_flags,
    317                                  PRInt16* out_flags) {
    318  PRInt16 my_flags, new_flags;
    319  PRFilePrivate* mine = (PRFilePrivate*)fd->secret;
    320  if (0 != (PR_POLL_READ & in_flags)) {
    321    /* client thinks he's reading */
    322    switch (mine->rcvstate) {
    323      case rcv_send_credit:
    324        my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE;
    325        break;
    326      case rcv_data:
    327      case rcv_get_debit:
    328        my_flags = in_flags;
    329      default:
    330        break;
    331    }
    332  } else if (0 != (PR_POLL_WRITE & in_flags)) {
    333    /* client thinks he's writing */
    334    switch (mine->xmtstate) {
    335      case xmt_recv_credit:
    336        my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ;
    337        break;
    338      case xmt_send_debit:
    339      case xmt_data:
    340        my_flags = in_flags;
    341      default:
    342        break;
    343    }
    344  } else {
    345    PR_NOT_REACHED("How'd I get here?");
    346  }
    347  new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags);
    348  if (verbosity > chatty)
    349    PR_fprintf(logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", in_flags,
    350               my_flags, *out_flags, new_flags);
    351  return new_flags;
    352 } /* MyPoll */
    353 
    354 static PRFileDesc* PR_CALLBACK MyAccept(PRFileDesc* fd, PRNetAddr* addr,
    355                                        PRIntervalTime timeout) {
    356  PRStatus rv;
    357  PRFileDesc *newfd, *layer = fd;
    358  PRFileDesc* newstack;
    359  PRFilePrivate* newsecret;
    360 
    361  PR_ASSERT(fd != NULL);
    362  PR_ASSERT(fd->lower != NULL);
    363 
    364  newstack = PR_NEW(PRFileDesc);
    365  if (NULL == newstack) {
    366    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    367    return NULL;
    368  }
    369  newsecret = PR_NEW(PRFilePrivate);
    370  if (NULL == newsecret) {
    371    PR_DELETE(newstack);
    372    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    373    return NULL;
    374  }
    375  *newstack = *fd; /* make a copy of the accepting layer */
    376  *newsecret = *fd->secret;
    377  newstack->secret = newsecret;
    378 
    379  newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
    380  if (NULL == newfd) {
    381    PR_DELETE(newsecret);
    382    PR_DELETE(newstack);
    383    return NULL;
    384  }
    385 
    386  /* this PR_PushIOLayer call cannot fail */
    387  rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
    388  PR_ASSERT(PR_SUCCESS == rv);
    389  return newfd; /* that's it */
    390 }
    391 
    392 static PRInt32 PR_CALLBACK MyRecv(PRFileDesc* fd, void* buf, PRInt32 amount,
    393                                  PRIntn flags, PRIntervalTime timeout) {
    394  char* b;
    395  PRInt32 rv;
    396  PRFileDesc* lo = fd->lower;
    397  PRFilePrivate* mine = (PRFilePrivate*)fd->secret;
    398 
    399  do {
    400    switch (mine->rcvstate) {
    401      case rcv_get_debit:
    402        b = (char*)&mine->rcvreq;
    403        mine->rcvreq = amount;
    404        rv = lo->methods->recv(lo, b + mine->rcvinprogress,
    405                               sizeof(mine->rcvreq) - mine->rcvinprogress,
    406                               flags, timeout);
    407        if (0 == rv) {
    408          goto closed;
    409        }
    410        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    411          break;
    412        }
    413        mine->rcvinprogress += rv; /* accumulate the read */
    414        if (mine->rcvinprogress < sizeof(mine->rcvreq)) {
    415          break; /* loop */
    416        }
    417        mine->rcvstate = rcv_send_credit;
    418        mine->rcvinprogress = 0;
    419      case rcv_send_credit:
    420        b = (char*)&mine->rcvreq;
    421        rv = lo->methods->send(lo, b + mine->rcvinprogress,
    422                               sizeof(mine->rcvreq) - mine->rcvinprogress,
    423                               flags, timeout);
    424        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    425          break;
    426        }
    427        mine->rcvinprogress += rv; /* accumulate the read */
    428        if (mine->rcvinprogress < sizeof(mine->rcvreq)) {
    429          break; /* loop */
    430        }
    431        mine->rcvstate = rcv_data;
    432        mine->rcvinprogress = 0;
    433      case rcv_data:
    434        b = (char*)buf;
    435        rv = lo->methods->recv(lo, b + mine->rcvinprogress,
    436                               mine->rcvreq - mine->rcvinprogress, flags,
    437                               timeout);
    438        if (0 == rv) {
    439          goto closed;
    440        }
    441        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    442          break;
    443        }
    444        mine->rcvinprogress += rv; /* accumulate the read */
    445        if (mine->rcvinprogress < amount) {
    446          break; /* loop */
    447        }
    448        mine->rcvstate = rcv_get_debit;
    449        mine->rcvinprogress = 0;
    450        return mine->rcvreq; /* << -- that's it! */
    451      default:
    452        break;
    453    }
    454  } while (-1 != rv);
    455  return rv;
    456 closed:
    457  mine->rcvinprogress = 0;
    458  mine->rcvstate = rcv_get_debit;
    459  return 0;
    460 } /* MyRecv */
    461 
    462 static PRInt32 PR_CALLBACK MySend(PRFileDesc* fd, const void* buf,
    463                                  PRInt32 amount, PRIntn flags,
    464                                  PRIntervalTime timeout) {
    465  char* b;
    466  PRInt32 rv;
    467  PRFileDesc* lo = fd->lower;
    468  PRFilePrivate* mine = (PRFilePrivate*)fd->secret;
    469 
    470  do {
    471    switch (mine->xmtstate) {
    472      case xmt_send_debit:
    473        b = (char*)&mine->xmtreq;
    474        mine->xmtreq = amount;
    475        rv = lo->methods->send(lo, b - mine->xmtinprogress,
    476                               sizeof(mine->xmtreq) - mine->xmtinprogress,
    477                               flags, timeout);
    478        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    479          break;
    480        }
    481        mine->xmtinprogress += rv;
    482        if (mine->xmtinprogress < sizeof(mine->xmtreq)) {
    483          break;
    484        }
    485        mine->xmtstate = xmt_recv_credit;
    486        mine->xmtinprogress = 0;
    487      case xmt_recv_credit:
    488        b = (char*)&mine->xmtreq;
    489        rv = lo->methods->recv(lo, b + mine->xmtinprogress,
    490                               sizeof(mine->xmtreq) - mine->xmtinprogress,
    491                               flags, timeout);
    492        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    493          break;
    494        }
    495        mine->xmtinprogress += rv;
    496        if (mine->xmtinprogress < sizeof(mine->xmtreq)) {
    497          break;
    498        }
    499        mine->xmtstate = xmt_data;
    500        mine->xmtinprogress = 0;
    501      case xmt_data:
    502        b = (char*)buf;
    503        rv = lo->methods->send(lo, b + mine->xmtinprogress,
    504                               mine->xmtreq - mine->xmtinprogress, flags,
    505                               timeout);
    506        if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
    507          break;
    508        }
    509        mine->xmtinprogress += rv;
    510        if (mine->xmtinprogress < amount) {
    511          break;
    512        }
    513        mine->xmtstate = xmt_send_debit;
    514        mine->xmtinprogress = 0;
    515        return mine->xmtreq; /* <<-- That's the one! */
    516      default:
    517        break;
    518    }
    519  } while (-1 != rv);
    520  return rv;
    521 } /* MySend */
    522 
    523 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) {
    524  PRIntn verbage = (PRIntn)verbosity + delta;
    525  if (verbage < (PRIntn)silent) {
    526    verbage = (PRIntn)silent;
    527  } else if (verbage > (PRIntn)noisy) {
    528    verbage = (PRIntn)noisy;
    529  }
    530  return (Verbosity)verbage;
    531 } /* ChangeVerbosity */
    532 
    533 int main(int argc, char** argv) {
    534  PRStatus rv;
    535  PLOptStatus os;
    536  PRFileDesc *client, *service;
    537  PRNetAddr any_address;
    538  const char* server_name = NULL;
    539  const PRIOMethods* stubMethods;
    540  PRThread *client_thread, *server_thread;
    541  PRThreadScope thread_scope = PR_LOCAL_THREAD;
    542  PRSocketOptionData socket_noblock, socket_nodelay;
    543  PLOptState* opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
    544  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    545    if (PL_OPT_BAD == os) {
    546      continue;
    547    }
    548    switch (opt->option) {
    549      case 0:
    550        server_name = opt->value;
    551        break;
    552      case 'd': /* debug mode */
    553        if (verbosity < noisy) {
    554          verbosity = ChangeVerbosity(verbosity, 1);
    555        }
    556        break;
    557      case 'q': /* debug mode */
    558        if (verbosity > silent) {
    559          verbosity = ChangeVerbosity(verbosity, -1);
    560        }
    561        break;
    562      case 'G': /* use global threads */
    563        thread_scope = PR_GLOBAL_THREAD;
    564        break;
    565      case 'C': /* number of threads waiting */
    566        major_iterations = atoi(opt->value);
    567        break;
    568      case 'c': /* number of client threads */
    569        minor_iterations = atoi(opt->value);
    570        break;
    571      case 'p': /* default port */
    572        default_port = atoi(opt->value);
    573        break;
    574      default:
    575        break;
    576    }
    577  }
    578  PL_DestroyOptState(opt);
    579 
    580  logFile = PR_GetSpecialFD(PR_StandardError);
    581  identity = PR_GetUniqueIdentity("Dummy");
    582  stubMethods = PR_GetDefaultIOMethods();
    583 
    584  /*
    585  ** The protocol we're going to implement is one where in order to initiate
    586  ** a send, the sender must first solicit permission. Therefore, every
    587  ** send is really a send - receive - send sequence.
    588  */
    589  myMethods = *stubMethods;    /* first get the entire batch */
    590  myMethods.accept = MyAccept; /* then override the ones we care about */
    591  myMethods.recv = MyRecv;     /* then override the ones we care about */
    592  myMethods.send = MySend;     /* then override the ones we care about */
    593  myMethods.close = MyClose;   /* then override the ones we care about */
    594  myMethods.poll = MyPoll;     /* then override the ones we care about */
    595 
    596  if (NULL == server_name)
    597    rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
    598  else {
    599    rv = PR_StringToNetAddr(server_name, &server_address);
    600    PR_ASSERT(PR_SUCCESS == rv);
    601    rv = PR_InitializeNetAddr(PR_IpAddrNull, default_port, &server_address);
    602  }
    603  PR_ASSERT(PR_SUCCESS == rv);
    604 
    605  socket_noblock.value.non_blocking = PR_TRUE;
    606  socket_noblock.option = PR_SockOpt_Nonblocking;
    607  socket_nodelay.value.no_delay = PR_TRUE;
    608  socket_nodelay.option = PR_SockOpt_NoDelay;
    609 
    610  /* one type w/o layering */
    611 
    612  while (major_iterations-- > 0) {
    613    if (verbosity > silent) {
    614      PR_fprintf(logFile, "Beginning non-layered test\n");
    615    }
    616 
    617    client = PR_NewTCPSocket();
    618    PR_ASSERT(NULL != client);
    619    service = PR_NewTCPSocket();
    620    PR_ASSERT(NULL != service);
    621 
    622    rv = PR_SetSocketOption(client, &socket_noblock);
    623    PR_ASSERT(PR_SUCCESS == rv);
    624    rv = PR_SetSocketOption(service, &socket_noblock);
    625    PR_ASSERT(PR_SUCCESS == rv);
    626    rv = PR_SetSocketOption(client, &socket_nodelay);
    627    PR_ASSERT(PR_SUCCESS == rv);
    628    rv = PR_SetSocketOption(service, &socket_nodelay);
    629    PR_ASSERT(PR_SUCCESS == rv);
    630 
    631    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
    632    PR_ASSERT(PR_SUCCESS == rv);
    633    rv = PR_Bind(service, &any_address);
    634    PR_ASSERT(PR_SUCCESS == rv);
    635    rv = PR_Listen(service, 10);
    636    PR_ASSERT(PR_SUCCESS == rv);
    637 
    638    server_thread =
    639        PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH,
    640                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    641    PR_ASSERT(NULL != server_thread);
    642 
    643    client_thread =
    644        PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL,
    645                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    646    PR_ASSERT(NULL != client_thread);
    647 
    648    rv = PR_JoinThread(client_thread);
    649    PR_ASSERT(PR_SUCCESS == rv);
    650    rv = PR_JoinThread(server_thread);
    651    PR_ASSERT(PR_SUCCESS == rv);
    652 
    653    rv = PR_Close(client);
    654    PR_ASSERT(PR_SUCCESS == rv);
    655    rv = PR_Close(service);
    656    PR_ASSERT(PR_SUCCESS == rv);
    657    if (verbosity > silent) {
    658      PR_fprintf(logFile, "Ending non-layered test\n");
    659    }
    660 
    661    /* with layering */
    662    if (verbosity > silent) {
    663      PR_fprintf(logFile, "Beginning layered test\n");
    664    }
    665    client = PR_NewTCPSocket();
    666    PR_ASSERT(NULL != client);
    667    service = PR_NewTCPSocket();
    668    PR_ASSERT(NULL != service);
    669 
    670    rv = PR_SetSocketOption(client, &socket_noblock);
    671    PR_ASSERT(PR_SUCCESS == rv);
    672    rv = PR_SetSocketOption(service, &socket_noblock);
    673    PR_ASSERT(PR_SUCCESS == rv);
    674    rv = PR_SetSocketOption(client, &socket_nodelay);
    675    PR_ASSERT(PR_SUCCESS == rv);
    676    rv = PR_SetSocketOption(service, &socket_nodelay);
    677    PR_ASSERT(PR_SUCCESS == rv);
    678 
    679    PushLayer(client);
    680    PushLayer(service);
    681 
    682    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
    683    PR_ASSERT(PR_SUCCESS == rv);
    684    rv = PR_Bind(service, &any_address);
    685    PR_ASSERT(PR_SUCCESS == rv);
    686    rv = PR_Listen(service, 10);
    687    PR_ASSERT(PR_SUCCESS == rv);
    688 
    689    server_thread =
    690        PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH,
    691                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    692    PR_ASSERT(NULL != server_thread);
    693 
    694    client_thread =
    695        PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL,
    696                        thread_scope, PR_JOINABLE_THREAD, 16 * 1024);
    697    PR_ASSERT(NULL != client_thread);
    698 
    699    rv = PR_JoinThread(client_thread);
    700    PR_ASSERT(PR_SUCCESS == rv);
    701    rv = PR_JoinThread(server_thread);
    702    PR_ASSERT(PR_SUCCESS == rv);
    703 
    704    rv = PR_Close(PopLayer(client));
    705    PR_ASSERT(PR_SUCCESS == rv);
    706    rv = PR_Close(PopLayer(service));
    707    PR_ASSERT(PR_SUCCESS == rv);
    708    if (verbosity > silent) {
    709      PR_fprintf(logFile, "Ending layered test\n");
    710    }
    711  }
    712  return 0;
    713 } /* main */
    714 
    715 /* nblayer.c */