LCOV - code coverage report
Current view: top level - nsprpub/pr/src/io - prlayer.c (source / functions) Hit Total Coverage
Test: output.info Lines: 95 331 28.7 %
Date: 2017-07-14 16:53:18 Functions: 4 33 12.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13