tor-browser

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

prlayer.c (21437B)


      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 ** File:        prlayer.c
      8 ** Description: Routines for handling pushable protocol modules on sockets.
      9 */
     10 
     11 #include "primpl.h"
     12 #include "prerror.h"
     13 #include "prmem.h"
     14 #include "prlock.h"
     15 #include "prlog.h"
     16 #include "prio.h"
     17 
     18 #include <string.h> /* for memset() */
     19 static PRStatus _PR_DestroyIOLayer(PRFileDesc* stack);
     20 
     21 void PR_CALLBACK pl_FDDestructor(PRFileDesc* fd) {
     22  PR_ASSERT(fd != NULL);
     23  if (NULL != fd->lower) {
     24    fd->lower->higher = fd->higher;
     25  }
     26  if (NULL != fd->higher) {
     27    fd->higher->lower = fd->lower;
     28  }
     29  PR_DELETE(fd);
     30 }
     31 
     32 /*
     33 ** Default methods that just call down to the next fd.
     34 */
     35 static PRStatus PR_CALLBACK pl_TopClose(PRFileDesc* fd) {
     36  PRFileDesc *top, *lower;
     37  PRStatus rv;
     38 
     39  PR_ASSERT(fd != NULL);
     40  PR_ASSERT(fd->lower != NULL);
     41  PR_ASSERT(fd->secret == NULL);
     42  PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
     43 
     44  if (PR_IO_LAYER_HEAD == fd->identity) {
     45    /*
     46     * new style stack; close all the layers, before deleting the
     47     * stack head
     48     */
     49    rv = fd->lower->methods->close(fd->lower);
     50    _PR_DestroyIOLayer(fd);
     51    return rv;
     52  }
     53  if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
     54    /*
     55     * lower layers of new style stack
     56     */
     57    lower = fd->lower;
     58    /*
     59     * pop and cleanup current layer
     60     */
     61    top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
     62    top->dtor(top);
     63    /*
     64     * then call lower layer
     65     */
     66    return (lower->methods->close(lower));
     67  } else {
     68    /* old style stack */
     69    top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
     70    top->dtor(top);
     71    return (fd->methods->close)(fd);
     72  }
     73 }
     74 
     75 static PRInt32 PR_CALLBACK pl_DefRead(PRFileDesc* fd, void* buf,
     76                                      PRInt32 amount) {
     77  PR_ASSERT(fd != NULL);
     78  PR_ASSERT(fd->lower != NULL);
     79 
     80  return (fd->lower->methods->read)(fd->lower, buf, amount);
     81 }
     82 
     83 static PRInt32 PR_CALLBACK pl_DefWrite(PRFileDesc* fd, const void* buf,
     84                                       PRInt32 amount) {
     85  PR_ASSERT(fd != NULL);
     86  PR_ASSERT(fd->lower != NULL);
     87 
     88  return (fd->lower->methods->write)(fd->lower, buf, amount);
     89 }
     90 
     91 static PRInt32 PR_CALLBACK pl_DefAvailable(PRFileDesc* fd) {
     92  PR_ASSERT(fd != NULL);
     93  PR_ASSERT(fd->lower != NULL);
     94 
     95  return (fd->lower->methods->available)(fd->lower);
     96 }
     97 
     98 static PRInt64 PR_CALLBACK pl_DefAvailable64(PRFileDesc* fd) {
     99  PR_ASSERT(fd != NULL);
    100  PR_ASSERT(fd->lower != NULL);
    101 
    102  return (fd->lower->methods->available64)(fd->lower);
    103 }
    104 
    105 static PRStatus PR_CALLBACK pl_DefFsync(PRFileDesc* fd) {
    106  PR_ASSERT(fd != NULL);
    107  PR_ASSERT(fd->lower != NULL);
    108 
    109  return (fd->lower->methods->fsync)(fd->lower);
    110 }
    111 
    112 static PRInt32 PR_CALLBACK pl_DefSeek(PRFileDesc* fd, PRInt32 offset,
    113                                      PRSeekWhence how) {
    114  PR_ASSERT(fd != NULL);
    115  PR_ASSERT(fd->lower != NULL);
    116 
    117  return (fd->lower->methods->seek)(fd->lower, offset, how);
    118 }
    119 
    120 static PRInt64 PR_CALLBACK pl_DefSeek64(PRFileDesc* fd, PRInt64 offset,
    121                                        PRSeekWhence how) {
    122  PR_ASSERT(fd != NULL);
    123  PR_ASSERT(fd->lower != NULL);
    124 
    125  return (fd->lower->methods->seek64)(fd->lower, offset, how);
    126 }
    127 
    128 static PRStatus PR_CALLBACK pl_DefFileInfo(PRFileDesc* fd, PRFileInfo* info) {
    129  PR_ASSERT(fd != NULL);
    130  PR_ASSERT(fd->lower != NULL);
    131 
    132  return (fd->lower->methods->fileInfo)(fd->lower, info);
    133 }
    134 
    135 static PRStatus PR_CALLBACK pl_DefFileInfo64(PRFileDesc* fd,
    136                                             PRFileInfo64* info) {
    137  PR_ASSERT(fd != NULL);
    138  PR_ASSERT(fd->lower != NULL);
    139 
    140  return (fd->lower->methods->fileInfo64)(fd->lower, info);
    141 }
    142 
    143 static PRInt32 PR_CALLBACK pl_DefWritev(PRFileDesc* fd, const PRIOVec* iov,
    144                                        PRInt32 size, PRIntervalTime timeout) {
    145  PR_ASSERT(fd != NULL);
    146  PR_ASSERT(fd->lower != NULL);
    147 
    148  return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
    149 }
    150 
    151 static PRStatus PR_CALLBACK pl_DefConnect(PRFileDesc* fd, const PRNetAddr* addr,
    152                                          PRIntervalTime timeout) {
    153  PR_ASSERT(fd != NULL);
    154  PR_ASSERT(fd->lower != NULL);
    155 
    156  return (fd->lower->methods->connect)(fd->lower, addr, timeout);
    157 }
    158 
    159 static PRStatus PR_CALLBACK pl_DefConnectcontinue(PRFileDesc* fd,
    160                                                  PRInt16 out_flags) {
    161  PR_ASSERT(fd != NULL);
    162  PR_ASSERT(fd->lower != NULL);
    163 
    164  return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
    165 }
    166 
    167 static PRFileDesc* PR_CALLBACK pl_TopAccept(PRFileDesc* fd, PRNetAddr* addr,
    168                                            PRIntervalTime timeout) {
    169  PRStatus rv;
    170  PRFileDesc *newfd, *layer = fd;
    171  PRFileDesc* newstack;
    172  PRBool newstyle_stack = PR_FALSE;
    173 
    174  PR_ASSERT(fd != NULL);
    175  PR_ASSERT(fd->lower != NULL);
    176 
    177  /* test for new style stack */
    178  while (NULL != layer->higher) {
    179    layer = layer->higher;
    180  }
    181  newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
    182  newstack = PR_NEW(PRFileDesc);
    183  if (NULL == newstack) {
    184    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    185    return NULL;
    186  }
    187  *newstack = *fd; /* make a copy of the accepting layer */
    188 
    189  newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
    190  if (NULL == newfd) {
    191    PR_DELETE(newstack);
    192    return NULL;
    193  }
    194 
    195  if (newstyle_stack) {
    196    newstack->lower = newfd;
    197    newfd->higher = newstack;
    198    return newstack;
    199  }
    200  /* this PR_PushIOLayer call cannot fail */
    201  rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
    202  PR_ASSERT(PR_SUCCESS == rv);
    203  return newfd; /* that's it */
    204 }
    205 
    206 static PRStatus PR_CALLBACK pl_DefBind(PRFileDesc* fd, const PRNetAddr* addr) {
    207  PR_ASSERT(fd != NULL);
    208  PR_ASSERT(fd->lower != NULL);
    209 
    210  return (fd->lower->methods->bind)(fd->lower, addr);
    211 }
    212 
    213 static PRStatus PR_CALLBACK pl_DefListen(PRFileDesc* fd, PRIntn backlog) {
    214  PR_ASSERT(fd != NULL);
    215  PR_ASSERT(fd->lower != NULL);
    216 
    217  return (fd->lower->methods->listen)(fd->lower, backlog);
    218 }
    219 
    220 static PRStatus PR_CALLBACK pl_DefShutdown(PRFileDesc* fd, PRIntn how) {
    221  PR_ASSERT(fd != NULL);
    222  PR_ASSERT(fd->lower != NULL);
    223 
    224  return (fd->lower->methods->shutdown)(fd->lower, how);
    225 }
    226 
    227 static PRInt32 PR_CALLBACK pl_DefRecv(PRFileDesc* fd, void* buf, PRInt32 amount,
    228                                      PRIntn flags, PRIntervalTime timeout) {
    229  PR_ASSERT(fd != NULL);
    230  PR_ASSERT(fd->lower != NULL);
    231 
    232  return (fd->lower->methods->recv)(fd->lower, buf, amount, flags, timeout);
    233 }
    234 
    235 static PRInt32 PR_CALLBACK pl_DefSend(PRFileDesc* fd, const void* buf,
    236                                      PRInt32 amount, PRIntn flags,
    237                                      PRIntervalTime timeout) {
    238  PR_ASSERT(fd != NULL);
    239  PR_ASSERT(fd->lower != NULL);
    240 
    241  return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
    242 }
    243 
    244 static PRInt32 PR_CALLBACK pl_DefRecvfrom(PRFileDesc* fd, void* buf,
    245                                          PRInt32 amount, PRIntn flags,
    246                                          PRNetAddr* addr,
    247                                          PRIntervalTime timeout) {
    248  PR_ASSERT(fd != NULL);
    249  PR_ASSERT(fd->lower != NULL);
    250 
    251  return (fd->lower->methods->recvfrom)(fd->lower, buf, amount, flags, addr,
    252                                        timeout);
    253 }
    254 
    255 static PRInt32 PR_CALLBACK pl_DefSendto(PRFileDesc* fd, const void* buf,
    256                                        PRInt32 amount, PRIntn flags,
    257                                        const PRNetAddr* addr,
    258                                        PRIntervalTime timeout) {
    259  PR_ASSERT(fd != NULL);
    260  PR_ASSERT(fd->lower != NULL);
    261 
    262  return (fd->lower->methods->sendto)(fd->lower, buf, amount, flags, addr,
    263                                      timeout);
    264 }
    265 
    266 static PRInt16 PR_CALLBACK pl_DefPoll(PRFileDesc* fd, PRInt16 in_flags,
    267                                      PRInt16* out_flags) {
    268  PR_ASSERT(fd != NULL);
    269  PR_ASSERT(fd->lower != NULL);
    270 
    271  return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
    272 }
    273 
    274 static PRInt32 PR_CALLBACK pl_DefAcceptread(PRFileDesc* sd, PRFileDesc** nd,
    275                                            PRNetAddr** raddr, void* buf,
    276                                            PRInt32 amount, PRIntervalTime t) {
    277  PRInt32 nbytes;
    278  PRStatus rv;
    279  PRFileDesc* newstack;
    280  PRFileDesc* layer = sd;
    281  PRBool newstyle_stack = PR_FALSE;
    282 
    283  PR_ASSERT(sd != NULL);
    284  PR_ASSERT(sd->lower != NULL);
    285 
    286  /* test for new style stack */
    287  while (NULL != layer->higher) {
    288    layer = layer->higher;
    289  }
    290  newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
    291  newstack = PR_NEW(PRFileDesc);
    292  if (NULL == newstack) {
    293    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    294    return -1;
    295  }
    296  *newstack = *sd; /* make a copy of the accepting layer */
    297 
    298  nbytes = sd->lower->methods->acceptread(sd->lower, nd, raddr, buf, amount, t);
    299  if (-1 == nbytes) {
    300    PR_DELETE(newstack);
    301    return nbytes;
    302  }
    303  if (newstyle_stack) {
    304    newstack->lower = *nd;
    305    (*nd)->higher = newstack;
    306    *nd = newstack;
    307    return nbytes;
    308  }
    309  /* this PR_PushIOLayer call cannot fail */
    310  rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
    311  PR_ASSERT(PR_SUCCESS == rv);
    312  return nbytes;
    313 }
    314 
    315 static PRInt32 PR_CALLBACK pl_DefTransmitfile(PRFileDesc* sd, PRFileDesc* fd,
    316                                              const void* headers, PRInt32 hlen,
    317                                              PRTransmitFileFlags flags,
    318                                              PRIntervalTime t) {
    319  PR_ASSERT(sd != NULL);
    320  PR_ASSERT(sd->lower != NULL);
    321 
    322  return sd->lower->methods->transmitfile(sd->lower, fd, headers, hlen, flags,
    323                                          t);
    324 }
    325 
    326 static PRStatus PR_CALLBACK pl_DefGetsockname(PRFileDesc* fd, PRNetAddr* addr) {
    327  PR_ASSERT(fd != NULL);
    328  PR_ASSERT(fd->lower != NULL);
    329 
    330  return (fd->lower->methods->getsockname)(fd->lower, addr);
    331 }
    332 
    333 static PRStatus PR_CALLBACK pl_DefGetpeername(PRFileDesc* fd, PRNetAddr* addr) {
    334  PR_ASSERT(fd != NULL);
    335  PR_ASSERT(fd->lower != NULL);
    336 
    337  return (fd->lower->methods->getpeername)(fd->lower, addr);
    338 }
    339 
    340 static PRStatus PR_CALLBACK pl_DefGetsocketoption(PRFileDesc* fd,
    341                                                  PRSocketOptionData* data) {
    342  PR_ASSERT(fd != NULL);
    343  PR_ASSERT(fd->lower != NULL);
    344 
    345  return (fd->lower->methods->getsocketoption)(fd->lower, data);
    346 }
    347 
    348 static PRStatus PR_CALLBACK
    349 pl_DefSetsocketoption(PRFileDesc* fd, const PRSocketOptionData* data) {
    350  PR_ASSERT(fd != NULL);
    351  PR_ASSERT(fd->lower != NULL);
    352 
    353  return (fd->lower->methods->setsocketoption)(fd->lower, data);
    354 }
    355 
    356 static PRInt32 PR_CALLBACK pl_DefSendfile(PRFileDesc* sd, PRSendFileData* sfd,
    357                                          PRTransmitFileFlags flags,
    358                                          PRIntervalTime timeout) {
    359  PR_ASSERT(sd != NULL);
    360  PR_ASSERT(sd->lower != NULL);
    361 
    362  return sd->lower->methods->sendfile(sd->lower, sfd, flags, timeout);
    363 }
    364 
    365 /* Methods for the top of the stack.  Just call down to the next fd. */
    366 static PRIOMethods pl_methods = {PR_DESC_LAYERED,
    367                                 pl_TopClose,
    368                                 pl_DefRead,
    369                                 pl_DefWrite,
    370                                 pl_DefAvailable,
    371                                 pl_DefAvailable64,
    372                                 pl_DefFsync,
    373                                 pl_DefSeek,
    374                                 pl_DefSeek64,
    375                                 pl_DefFileInfo,
    376                                 pl_DefFileInfo64,
    377                                 pl_DefWritev,
    378                                 pl_DefConnect,
    379                                 pl_TopAccept,
    380                                 pl_DefBind,
    381                                 pl_DefListen,
    382                                 pl_DefShutdown,
    383                                 pl_DefRecv,
    384                                 pl_DefSend,
    385                                 pl_DefRecvfrom,
    386                                 pl_DefSendto,
    387                                 pl_DefPoll,
    388                                 pl_DefAcceptread,
    389                                 pl_DefTransmitfile,
    390                                 pl_DefGetsockname,
    391                                 pl_DefGetpeername,
    392                                 (PRReservedFN)_PR_InvalidInt,
    393                                 (PRReservedFN)_PR_InvalidInt,
    394                                 pl_DefGetsocketoption,
    395                                 pl_DefSetsocketoption,
    396                                 pl_DefSendfile,
    397                                 pl_DefConnectcontinue,
    398                                 (PRReservedFN)_PR_InvalidInt,
    399                                 (PRReservedFN)_PR_InvalidInt,
    400                                 (PRReservedFN)_PR_InvalidInt,
    401                                 (PRReservedFN)_PR_InvalidInt};
    402 
    403 PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void) {
    404  return &pl_methods;
    405 } /* PR_GetDefaultIOMethods */
    406 
    407 PR_IMPLEMENT(PRFileDesc*)
    408 PR_CreateIOLayerStub(PRDescIdentity ident, const PRIOMethods* methods) {
    409  PRFileDesc* fd = NULL;
    410  PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
    411  if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident)) {
    412    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    413  } else {
    414    fd = PR_NEWZAP(PRFileDesc);
    415    if (NULL == fd) {
    416      PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    417    } else {
    418      fd->methods = methods;
    419      fd->dtor = pl_FDDestructor;
    420      fd->identity = ident;
    421    }
    422  }
    423  return fd;
    424 } /* PR_CreateIOLayerStub */
    425 
    426 /*
    427 * PR_CreateIOLayer
    428 *      Create a new style stack, where the stack top is a dummy header.
    429 *      Unlike the old style stacks, the contents of the stack head
    430 *      are not modified when a layer is pushed onto or popped from a new
    431 *      style stack.
    432 */
    433 
    434 PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* top) {
    435  PRFileDesc* fd = NULL;
    436 
    437  fd = PR_NEWZAP(PRFileDesc);
    438  if (NULL == fd) {
    439    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    440  } else {
    441    fd->methods = &pl_methods;
    442    fd->dtor = pl_FDDestructor;
    443    fd->identity = PR_IO_LAYER_HEAD;
    444    fd->higher = NULL;
    445    fd->lower = top;
    446    top->higher = fd;
    447    top->lower = NULL;
    448  }
    449  return fd;
    450 } /* PR_CreateIOLayer */
    451 
    452 /*
    453 * _PR_DestroyIOLayer
    454 *      Delete the stack head of a new style stack.
    455 */
    456 
    457 static PRStatus _PR_DestroyIOLayer(PRFileDesc* stack) {
    458  if (NULL == stack) {
    459    return PR_FAILURE;
    460  }
    461 
    462  PR_DELETE(stack);
    463  return PR_SUCCESS;
    464 } /* _PR_DestroyIOLayer */
    465 
    466 PR_IMPLEMENT(PRStatus)
    467 PR_PushIOLayer(PRFileDesc* stack, PRDescIdentity id, PRFileDesc* fd) {
    468  PRFileDesc* insert = PR_GetIdentitiesLayer(stack, id);
    469 
    470  PR_ASSERT(fd != NULL);
    471  PR_ASSERT(stack != NULL);
    472  PR_ASSERT(insert != NULL);
    473  PR_ASSERT(PR_IO_LAYER_HEAD != id);
    474  if ((NULL == stack) || (NULL == fd) || (NULL == insert)) {
    475    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    476    return PR_FAILURE;
    477  }
    478 
    479  if (stack == insert) {
    480    /* going on top of the stack */
    481    /* old-style stack */
    482    PRFileDesc copy = *stack;
    483    *stack = *fd;
    484    *fd = copy;
    485    fd->higher = stack;
    486    if (fd->lower) {
    487      PR_ASSERT(fd->lower->higher == stack);
    488      fd->lower->higher = fd;
    489    }
    490    stack->lower = fd;
    491    stack->higher = NULL;
    492  } else {
    493    /*
    494     * going somewhere in the middle of the stack for both old and new
    495     * style stacks, or going on top of stack for new style stack
    496     */
    497    fd->lower = insert;
    498    fd->higher = insert->higher;
    499 
    500    insert->higher->lower = fd;
    501    insert->higher = fd;
    502  }
    503 
    504  return PR_SUCCESS;
    505 }
    506 
    507 PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc* stack, PRDescIdentity id) {
    508  PRFileDesc* extract = PR_GetIdentitiesLayer(stack, id);
    509 
    510  PR_ASSERT(0 != id);
    511  PR_ASSERT(NULL != stack);
    512  PR_ASSERT(NULL != extract);
    513  if ((NULL == stack) || (0 == id) || (NULL == extract)) {
    514    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    515    return NULL;
    516  }
    517 
    518  if (extract == stack) {
    519    /* popping top layer of the stack */
    520    /* old style stack */
    521    PRFileDesc copy = *stack;
    522    extract = stack->lower;
    523    *stack = *extract;
    524    *extract = copy;
    525    stack->higher = NULL;
    526    if (stack->lower) {
    527      PR_ASSERT(stack->lower->higher == extract);
    528      stack->lower->higher = stack;
    529    }
    530  } else if ((PR_IO_LAYER_HEAD == stack->identity) &&
    531             (extract == stack->lower) && (extract->lower == NULL)) {
    532    /*
    533     * new style stack
    534     * popping the only layer in the stack; delete the stack too
    535     */
    536    stack->lower = NULL;
    537    _PR_DestroyIOLayer(stack);
    538  } else {
    539    /* for both kinds of stacks */
    540    extract->lower->higher = extract->higher;
    541    extract->higher->lower = extract->lower;
    542  }
    543  extract->higher = extract->lower = NULL;
    544  return extract;
    545 } /* PR_PopIOLayer */
    546 
    547 #define ID_CACHE_INCREMENT 16
    548 typedef struct _PRIdentity_cache {
    549  PRLock* ml;
    550  char** name;
    551  PRIntn length;
    552  PRDescIdentity ident;
    553 } _PRIdentity_cache;
    554 
    555 static _PRIdentity_cache identity_cache;
    556 
    557 PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char* layer_name) {
    558  PRDescIdentity identity, length;
    559  char **names = NULL, *name = NULL, **old = NULL;
    560 
    561  if (!_pr_initialized) {
    562    _PR_ImplicitInitialization();
    563  }
    564 
    565  PR_ASSERT((PRDescIdentity)((1UL << ((sizeof(PRDescIdentity) * 8) - 1)) - 1)
    566            > identity_cache.ident);
    567 
    568  if (NULL != layer_name) {
    569    name = (char*)PR_Malloc(strlen(layer_name) + 1);
    570    if (NULL == name) {
    571      PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    572      return PR_INVALID_IO_LAYER;
    573    }
    574    strcpy(name, layer_name);
    575  }
    576 
    577  /* this initial code runs unsafe */
    578 retry:
    579  PR_ASSERT(NULL == names);
    580  /*
    581   * In the initial round, both identity_cache.ident and
    582   * identity_cache.length are 0, so (identity_cache.ident + 1) is greater
    583   * than length.  In later rounds, identity_cache.ident is always less
    584   * than length, so (identity_cache.ident + 1) can be equal to but cannot
    585   * be greater than length.
    586   */
    587  length = identity_cache.length;
    588  if ((identity_cache.ident + 1) >= length) {
    589    length += ID_CACHE_INCREMENT;
    590    names = (char**)PR_CALLOC(length * sizeof(char*));
    591    if (NULL == names) {
    592      if (NULL != name) {
    593        PR_DELETE(name);
    594      }
    595      PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    596      return PR_INVALID_IO_LAYER;
    597    }
    598  }
    599 
    600  /* now we get serious about thread safety */
    601  PR_Lock(identity_cache.ml);
    602  PR_ASSERT(identity_cache.length == 0 ||
    603            identity_cache.ident < identity_cache.length);
    604  identity = identity_cache.ident + 1;
    605  if (identity >= identity_cache.length) /* there's no room */
    606  {
    607    /* we have to do something - hopefully it's already done */
    608    if ((NULL != names) && (identity < length)) {
    609      /* what we did is still okay */
    610      if (identity_cache.length != 0) {
    611        memcpy(names, identity_cache.name,
    612               identity_cache.length * sizeof(char*));
    613      }
    614      old = identity_cache.name;
    615      identity_cache.name = names;
    616      identity_cache.length = length;
    617      names = NULL;
    618    } else {
    619      PR_Unlock(identity_cache.ml);
    620      if (NULL != names) {
    621        PR_DELETE(names);
    622      }
    623      goto retry;
    624    }
    625  }
    626  if (NULL != name) /* there's a name to be stored */
    627  {
    628    identity_cache.name[identity] = name;
    629  }
    630  identity_cache.ident = identity;
    631  PR_ASSERT(identity_cache.ident < identity_cache.length);
    632  PR_Unlock(identity_cache.ml);
    633 
    634  if (NULL != old) {
    635    PR_DELETE(old);
    636  }
    637  if (NULL != names) {
    638    PR_DELETE(names);
    639  }
    640 
    641  return identity;
    642 } /* PR_GetUniqueIdentity */
    643 
    644 PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident) {
    645  const char* rv = NULL;
    646  if (!_pr_initialized) {
    647    _PR_ImplicitInitialization();
    648  }
    649 
    650  if ((PR_TOP_IO_LAYER != ident) && (ident >= 0)) {
    651    PR_Lock(identity_cache.ml);
    652    PR_ASSERT(ident <= identity_cache.ident);
    653    rv = (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
    654    PR_Unlock(identity_cache.ml);
    655  }
    656 
    657  return rv;
    658 } /* PR_GetNameForIdentity */
    659 
    660 PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd) {
    661  PR_ASSERT(NULL != fd);
    662  if (PR_IO_LAYER_HEAD == fd->identity) {
    663    PR_ASSERT(NULL != fd->lower);
    664    return fd->lower->identity;
    665  }
    666  return fd->identity;
    667 } /* PR_GetLayersIdentity */
    668 
    669 PR_IMPLEMENT(PRFileDesc*)
    670 PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id) {
    671  PRFileDesc* layer = fd;
    672 
    673  if (PR_TOP_IO_LAYER == id) {
    674    if (PR_IO_LAYER_HEAD == fd->identity) {
    675      return fd->lower;
    676    }
    677    return fd;
    678  }
    679 
    680  for (layer = fd; layer != NULL; layer = layer->lower) {
    681    if (id == layer->identity) {
    682      return layer;
    683    }
    684  }
    685  for (layer = fd; layer != NULL; layer = layer->higher) {
    686    if (id == layer->identity) {
    687      return layer;
    688    }
    689  }
    690  return NULL;
    691 } /* PR_GetIdentitiesLayer */
    692 
    693 void _PR_InitLayerCache(void) {
    694  memset(&identity_cache, 0, sizeof(identity_cache));
    695  identity_cache.ml = PR_NewLock();
    696  PR_ASSERT(NULL != identity_cache.ml);
    697 } /* _PR_InitLayerCache */
    698 
    699 void _PR_CleanupLayerCache(void) {
    700  if (identity_cache.ml) {
    701    PR_DestroyLock(identity_cache.ml);
    702    identity_cache.ml = NULL;
    703  }
    704 
    705  if (identity_cache.name) {
    706    PRDescIdentity ident;
    707 
    708    for (ident = 0; ident <= identity_cache.ident; ident++) {
    709      PR_DELETE(identity_cache.name[ident]);
    710    }
    711 
    712    PR_DELETE(identity_cache.name);
    713  }
    714 } /* _PR_CleanupLayerCache */
    715 
    716 /* prlayer.c */