Back to index

lightning-sunbird  0.9+nobinonly
prlayer.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** File:        prlayer.c
00040 ** Description: Routines for handling pushable protocol modules on sockets.
00041 */
00042 
00043 #include "primpl.h"
00044 #include "prerror.h"
00045 #include "prmem.h"
00046 #include "prlock.h"
00047 #include "prlog.h"
00048 #include "prio.h"
00049 
00050 #include <string.h> /* for memset() */
00051 static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
00052 
00053 void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
00054 {
00055     PR_ASSERT(fd != NULL);
00056     if (NULL != fd->lower) fd->lower->higher = fd->higher;
00057     if (NULL != fd->higher) fd->higher->lower = fd->lower;
00058     PR_DELETE(fd);
00059 }
00060 
00061 /*
00062 ** Default methods that just call down to the next fd.
00063 */
00064 static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
00065 {
00066     PRFileDesc *top, *lower;
00067        PRStatus rv;
00068 
00069     PR_ASSERT(fd != NULL);
00070     PR_ASSERT(fd->lower != NULL);
00071     PR_ASSERT(fd->secret == NULL);
00072     PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
00073 
00074        if (PR_IO_LAYER_HEAD == fd->identity) {
00075               /*
00076                * new style stack; close all the layers, before deleting the
00077                * stack head
00078                */
00079               rv = fd->lower->methods->close(fd->lower);
00080               _PR_DestroyIOLayer(fd);
00081               return rv;
00082        } else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
00083               /*
00084                * lower layers of new style stack
00085                */
00086               lower = fd->lower;
00087               /*
00088                * pop and cleanup current layer
00089                */
00090        top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
00091               top->dtor(top);
00092               /*
00093                * then call lower layer
00094                */
00095               return (lower->methods->close(lower));
00096        } else {
00097               /* old style stack */
00098        top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
00099               top->dtor(top);
00100               return (fd->methods->close)(fd);
00101        }
00102 }
00103 
00104 static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
00105 {
00106     PR_ASSERT(fd != NULL);
00107     PR_ASSERT(fd->lower != NULL);
00108 
00109     return (fd->lower->methods->read)(fd->lower, buf, amount);
00110 }
00111 
00112 static PRInt32 PR_CALLBACK pl_DefWrite (
00113     PRFileDesc *fd, const void *buf, PRInt32 amount)
00114 {
00115     PR_ASSERT(fd != NULL);
00116     PR_ASSERT(fd->lower != NULL);
00117 
00118     return (fd->lower->methods->write)(fd->lower, buf, amount);
00119 }
00120 
00121 static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
00122 {
00123     PR_ASSERT(fd != NULL);
00124     PR_ASSERT(fd->lower != NULL);
00125 
00126     return (fd->lower->methods->available)(fd->lower);
00127 }
00128 
00129 static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
00130 {
00131     PR_ASSERT(fd != NULL);
00132     PR_ASSERT(fd->lower != NULL);
00133 
00134     return (fd->lower->methods->available64)(fd->lower);
00135 }
00136 
00137 static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
00138 {
00139     PR_ASSERT(fd != NULL);
00140     PR_ASSERT(fd->lower != NULL);
00141 
00142     return (fd->lower->methods->fsync)(fd->lower);
00143 }
00144 
00145 static PRInt32 PR_CALLBACK pl_DefSeek (
00146     PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
00147 {
00148     PR_ASSERT(fd != NULL);
00149     PR_ASSERT(fd->lower != NULL);
00150 
00151     return (fd->lower->methods->seek)(fd->lower, offset, how);
00152 }
00153 
00154 static PRInt64 PR_CALLBACK pl_DefSeek64 (
00155     PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
00156 {
00157     PR_ASSERT(fd != NULL);
00158     PR_ASSERT(fd->lower != NULL);
00159 
00160     return (fd->lower->methods->seek64)(fd->lower, offset, how);
00161 }
00162 
00163 static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
00164 {
00165     PR_ASSERT(fd != NULL);
00166     PR_ASSERT(fd->lower != NULL);
00167 
00168     return (fd->lower->methods->fileInfo)(fd->lower, info);
00169 }
00170 
00171 static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
00172 {
00173     PR_ASSERT(fd != NULL);
00174     PR_ASSERT(fd->lower != NULL);
00175 
00176     return (fd->lower->methods->fileInfo64)(fd->lower, info);
00177 }
00178 
00179 static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
00180     PRInt32 size, PRIntervalTime timeout)
00181 {
00182     PR_ASSERT(fd != NULL);
00183     PR_ASSERT(fd->lower != NULL);
00184 
00185     return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
00186 }
00187 
00188 static PRStatus PR_CALLBACK pl_DefConnect (
00189     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
00190 {
00191     PR_ASSERT(fd != NULL);
00192     PR_ASSERT(fd->lower != NULL);
00193 
00194     return (fd->lower->methods->connect)(fd->lower, addr, timeout);
00195 }
00196 
00197 static PRStatus PR_CALLBACK pl_DefConnectcontinue (
00198     PRFileDesc *fd, PRInt16 out_flags)
00199 {
00200     PR_ASSERT(fd != NULL);
00201     PR_ASSERT(fd->lower != NULL);
00202 
00203     return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
00204 }
00205 
00206 static PRFileDesc* PR_CALLBACK pl_TopAccept (
00207     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
00208 {
00209     PRStatus rv;
00210     PRFileDesc *newfd, *layer = fd;
00211     PRFileDesc *newstack;
00212        PRBool newstyle_stack = PR_FALSE;
00213 
00214     PR_ASSERT(fd != NULL);
00215     PR_ASSERT(fd->lower != NULL);
00216 
00217        /* test for new style stack */
00218        while (NULL != layer->higher)
00219               layer = layer->higher;
00220        newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
00221     newstack = PR_NEW(PRFileDesc);
00222     if (NULL == newstack)
00223     {
00224         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00225         return NULL;
00226     }
00227     *newstack = *fd;  /* make a copy of the accepting layer */
00228 
00229     newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
00230     if (NULL == newfd)
00231     {
00232         PR_DELETE(newstack);
00233         return NULL;
00234     }
00235 
00236     if (newstyle_stack) {
00237               newstack->lower = newfd;
00238               newfd->higher = newstack;
00239               return newstack;
00240        } else {
00241               /* this PR_PushIOLayer call cannot fail */
00242               rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
00243               PR_ASSERT(PR_SUCCESS == rv);
00244        return newfd;  /* that's it */
00245        }
00246 }
00247 
00248 static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
00249 {
00250     PR_ASSERT(fd != NULL);
00251     PR_ASSERT(fd->lower != NULL);
00252 
00253     return (fd->lower->methods->bind)(fd->lower, addr);
00254 }
00255 
00256 static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
00257 {
00258     PR_ASSERT(fd != NULL);
00259     PR_ASSERT(fd->lower != NULL);
00260 
00261     return (fd->lower->methods->listen)(fd->lower, backlog);
00262 }
00263 
00264 static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
00265 {
00266     PR_ASSERT(fd != NULL);
00267     PR_ASSERT(fd->lower != NULL);
00268 
00269     return (fd->lower->methods->shutdown)(fd->lower, how);
00270 }
00271 
00272 static PRInt32 PR_CALLBACK pl_DefRecv (
00273     PRFileDesc *fd, void *buf, PRInt32 amount,
00274     PRIntn flags, PRIntervalTime timeout)
00275 {
00276     PR_ASSERT(fd != NULL);
00277     PR_ASSERT(fd->lower != NULL);
00278 
00279     return (fd->lower->methods->recv)(
00280         fd->lower, buf, amount, flags, timeout);
00281 }
00282 
00283 static PRInt32 PR_CALLBACK pl_DefSend (
00284     PRFileDesc *fd, const void *buf,
00285     PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
00286 {
00287     PR_ASSERT(fd != NULL);
00288     PR_ASSERT(fd->lower != NULL);
00289 
00290     return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
00291 }
00292 
00293 static PRInt32 PR_CALLBACK pl_DefRecvfrom (
00294     PRFileDesc *fd, void *buf, PRInt32 amount,
00295     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
00296 {
00297     PR_ASSERT(fd != NULL);
00298     PR_ASSERT(fd->lower != NULL);
00299 
00300     return (fd->lower->methods->recvfrom)(
00301         fd->lower, buf, amount, flags, addr, timeout);
00302 }
00303 
00304 static PRInt32 PR_CALLBACK pl_DefSendto (
00305     PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00306     const PRNetAddr *addr, PRIntervalTime timeout)
00307 {
00308     PR_ASSERT(fd != NULL);
00309     PR_ASSERT(fd->lower != NULL);
00310 
00311     return (fd->lower->methods->sendto)(
00312         fd->lower, buf, amount, flags, addr, timeout);
00313 }
00314 
00315 static PRInt16 PR_CALLBACK pl_DefPoll (
00316     PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
00317 {
00318     PR_ASSERT(fd != NULL);
00319     PR_ASSERT(fd->lower != NULL);
00320 
00321     return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
00322 }
00323 
00324 static PRInt32 PR_CALLBACK pl_DefAcceptread (
00325     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
00326     PRInt32 amount, PRIntervalTime t)
00327 {
00328     PRInt32 nbytes;
00329     PRStatus rv;
00330     PRFileDesc *newstack;
00331     PRFileDesc *layer = sd;
00332        PRBool newstyle_stack = PR_FALSE;
00333 
00334     PR_ASSERT(sd != NULL);
00335     PR_ASSERT(sd->lower != NULL);
00336 
00337        /* test for new style stack */
00338        while (NULL != layer->higher)
00339               layer = layer->higher;
00340        newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
00341     newstack = PR_NEW(PRFileDesc);
00342     if (NULL == newstack)
00343     {
00344         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00345         return -1;
00346     }
00347     *newstack = *sd;  /* make a copy of the accepting layer */
00348 
00349     nbytes = sd->lower->methods->acceptread(
00350         sd->lower, nd, raddr, buf, amount, t);
00351     if (-1 == nbytes)
00352     {
00353         PR_DELETE(newstack);
00354         return nbytes;
00355     }
00356     if (newstyle_stack) {
00357               newstack->lower = *nd;
00358               (*nd)->higher = newstack;
00359               *nd = newstack;
00360               return nbytes;
00361        } else {
00362               /* this PR_PushIOLayer call cannot fail */
00363               rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
00364               PR_ASSERT(PR_SUCCESS == rv);
00365               return nbytes;
00366        }
00367 }
00368 
00369 static PRInt32 PR_CALLBACK pl_DefTransmitfile (
00370     PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
00371     PRTransmitFileFlags flags, PRIntervalTime t)
00372 {
00373     PR_ASSERT(sd != NULL);
00374     PR_ASSERT(sd->lower != NULL);
00375 
00376     return sd->lower->methods->transmitfile(
00377         sd->lower, fd, headers, hlen, flags, t);
00378 }
00379 
00380 static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
00381 {
00382     PR_ASSERT(fd != NULL);
00383     PR_ASSERT(fd->lower != NULL);
00384 
00385     return (fd->lower->methods->getsockname)(fd->lower, addr);
00386 }
00387 
00388 static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
00389 {
00390     PR_ASSERT(fd != NULL);
00391     PR_ASSERT(fd->lower != NULL);
00392 
00393     return (fd->lower->methods->getpeername)(fd->lower, addr);
00394 }
00395 
00396 static PRStatus PR_CALLBACK pl_DefGetsocketoption (
00397     PRFileDesc *fd, PRSocketOptionData *data)
00398 {
00399     PR_ASSERT(fd != NULL);
00400     PR_ASSERT(fd->lower != NULL);
00401 
00402     return (fd->lower->methods->getsocketoption)(fd->lower, data);
00403 }
00404 
00405 static PRStatus PR_CALLBACK pl_DefSetsocketoption (
00406     PRFileDesc *fd, const PRSocketOptionData *data)
00407 {
00408     PR_ASSERT(fd != NULL);
00409     PR_ASSERT(fd->lower != NULL);
00410 
00411     return (fd->lower->methods->setsocketoption)(fd->lower, data);
00412 }
00413 
00414 static PRInt32 PR_CALLBACK pl_DefSendfile (
00415        PRFileDesc *sd, PRSendFileData *sfd,
00416        PRTransmitFileFlags flags, PRIntervalTime timeout)
00417 {
00418     PR_ASSERT(sd != NULL);
00419     PR_ASSERT(sd->lower != NULL);
00420 
00421     return sd->lower->methods->sendfile(
00422         sd->lower, sfd, flags, timeout);
00423 }
00424 
00425 /* Methods for the top of the stack.  Just call down to the next fd. */
00426 static PRIOMethods pl_methods = {
00427     PR_DESC_LAYERED,
00428     pl_TopClose,
00429     pl_DefRead,
00430     pl_DefWrite,
00431     pl_DefAvailable,
00432     pl_DefAvailable64,
00433     pl_DefFsync,
00434     pl_DefSeek,
00435     pl_DefSeek64,
00436     pl_DefFileInfo,
00437     pl_DefFileInfo64,
00438     pl_DefWritev,
00439     pl_DefConnect,
00440     pl_TopAccept,
00441     pl_DefBind,
00442     pl_DefListen,
00443     pl_DefShutdown,
00444     pl_DefRecv,
00445     pl_DefSend,
00446     pl_DefRecvfrom,
00447     pl_DefSendto,
00448     pl_DefPoll,
00449     pl_DefAcceptread,
00450     pl_DefTransmitfile,
00451     pl_DefGetsockname,
00452     pl_DefGetpeername,
00453     (PRReservedFN)_PR_InvalidInt,
00454     (PRReservedFN)_PR_InvalidInt,
00455     pl_DefGetsocketoption,
00456     pl_DefSetsocketoption,
00457     pl_DefSendfile,
00458     pl_DefConnectcontinue,
00459     (PRReservedFN)_PR_InvalidInt,
00460     (PRReservedFN)_PR_InvalidInt,
00461     (PRReservedFN)_PR_InvalidInt,
00462     (PRReservedFN)_PR_InvalidInt
00463 };
00464 
00465 PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
00466 {
00467     return &pl_methods;
00468 }  /* PR_GetDefaultIOMethods */
00469 
00470 PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
00471     PRDescIdentity ident, const PRIOMethods *methods)
00472 {
00473     PRFileDesc *fd = NULL;
00474     PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
00475     if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
00476         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00477     else
00478     {
00479         fd = PR_NEWZAP(PRFileDesc);
00480         if (NULL == fd)
00481             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00482         else
00483         {
00484             fd->methods = methods;
00485             fd->dtor = pl_FDDestructor;
00486             fd->identity = ident;
00487         }
00488     }
00489     return fd;
00490 }  /* PR_CreateIOLayerStub */
00491 
00492 /*
00493  * PR_CreateIOLayer
00494  *            Create a new style stack, where the stack top is a dummy header.
00495  *            Unlike the old style stacks, the contents of the stack head
00496  *            are not modified when a layer is pushed onto or popped from a new
00497  *            style stack.
00498  */
00499 
00500 PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
00501 {
00502     PRFileDesc *fd = NULL;
00503 
00504        fd = PR_NEWZAP(PRFileDesc);
00505        if (NULL == fd)
00506               PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00507        else
00508        {
00509               fd->methods = &pl_methods;
00510               fd->dtor = pl_FDDestructor;
00511               fd->identity = PR_IO_LAYER_HEAD;
00512               fd->higher = NULL;
00513               fd->lower = top;
00514               top->higher = fd;
00515               top->lower = NULL;
00516        }
00517     return fd;
00518 }  /* PR_CreateIOLayer */
00519 
00520 /*
00521  * _PR_DestroyIOLayer
00522  *            Delete the stack head of a new style stack.
00523  */
00524 
00525 static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
00526 {
00527     if (NULL == stack)
00528         return PR_FAILURE;
00529     else {
00530         PR_DELETE(stack);
00531        return PR_SUCCESS;
00532     }
00533 }  /* _PR_DestroyIOLayer */
00534 
00535 PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
00536     PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
00537 {
00538     PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
00539 
00540     PR_ASSERT(fd != NULL);
00541     PR_ASSERT(stack != NULL);
00542     PR_ASSERT(insert != NULL);
00543     PR_ASSERT(PR_IO_LAYER_HEAD != id);
00544     if ((NULL == stack) || (NULL == fd) || (NULL == insert))
00545     {
00546         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00547         return PR_FAILURE;
00548     }
00549 
00550     if (stack == insert)
00551     {
00552               /* going on top of the stack */
00553               /* old-style stack */       
00554               PRFileDesc copy = *stack;
00555               *stack = *fd;
00556               *fd = copy;
00557               fd->higher = stack;
00558               stack->lower = fd;
00559               stack->higher = NULL;
00560        } else {
00561         /*
00562                * going somewhere in the middle of the stack for both old and new
00563                * style stacks, or going on top of stack for new style stack
00564                */
00565         fd->lower = insert;
00566         fd->higher = insert->higher;
00567 
00568         insert->higher->lower = fd;
00569         insert->higher = fd;
00570     }
00571 
00572     return PR_SUCCESS;
00573 }
00574 
00575 PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
00576 {
00577     PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
00578 
00579     PR_ASSERT(0 != id);
00580     PR_ASSERT(NULL != stack);
00581     PR_ASSERT(NULL != extract);
00582     if ((NULL == stack) || (0 == id) || (NULL == extract))
00583     {
00584         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00585         return NULL;
00586     }
00587 
00588     if (extract == stack) {
00589         /* popping top layer of the stack */
00590               /* old style stack */
00591         PRFileDesc copy = *stack;
00592         extract = stack->lower;
00593         *stack = *extract;
00594         *extract = copy;
00595         stack->higher = NULL;
00596        } else if ((PR_IO_LAYER_HEAD == stack->identity) &&
00597                                    (extract == stack->lower) && (extract->lower == NULL)) {
00598                      /*
00599                       * new style stack
00600                       * popping the only layer in the stack; delete the stack too
00601                       */
00602                      stack->lower = NULL;
00603                      _PR_DestroyIOLayer(stack);
00604        } else {
00605               /* for both kinds of stacks */
00606         extract->lower->higher = extract->higher;
00607         extract->higher->lower = extract->lower;
00608     }
00609     extract->higher = extract->lower = NULL;
00610     return extract;
00611 }  /* PR_PopIOLayer */
00612 
00613 #define ID_CACHE_INCREMENT 16
00614 typedef struct _PRIdentity_cache
00615 {
00616     PRLock *ml;
00617     char **name;
00618     PRIntn length;
00619     PRDescIdentity ident;
00620 } _PRIdentity_cache;
00621 
00622 static _PRIdentity_cache identity_cache;
00623 
00624 PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
00625 {
00626     PRDescIdentity identity, length;
00627     char **names = NULL, *name = NULL, **old = NULL;
00628 
00629     if (!_pr_initialized) _PR_ImplicitInitialization();
00630 
00631     PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
00632 
00633     if (NULL != layer_name)
00634     {
00635         name = (char*)PR_Malloc(strlen(layer_name) + 1);
00636         if (NULL == name)
00637         {
00638             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00639             return PR_INVALID_IO_LAYER;
00640         }
00641         strcpy(name, layer_name);
00642     }
00643 
00644     /* this initial code runs unsafe */
00645 retry:
00646     PR_ASSERT(NULL == names);
00647     length = identity_cache.length;
00648     if (length < (identity_cache.ident + 1))
00649     {
00650         length += ID_CACHE_INCREMENT;
00651         names = (char**)PR_CALLOC(length * sizeof(char*));
00652         if (NULL == names)
00653         {
00654             if (NULL != name) PR_DELETE(name);
00655             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00656             return PR_INVALID_IO_LAYER;
00657         }
00658     }
00659 
00660     /* now we get serious about thread safety */
00661     PR_Lock(identity_cache.ml);
00662     PR_ASSERT(identity_cache.ident <= identity_cache.length);
00663     identity = identity_cache.ident + 1;
00664     if (identity > identity_cache.length)  /* there's no room */
00665     {
00666         /* we have to do something - hopefully it's already done */
00667         if ((NULL != names) && (length >= identity))
00668         {
00669             /* what we did is still okay */
00670             memcpy(
00671                 names, identity_cache.name,
00672                 identity_cache.length * sizeof(char*));
00673             old = identity_cache.name;
00674             identity_cache.name = names;
00675             identity_cache.length = length;
00676             names = NULL;
00677         }
00678         else
00679         {
00680             PR_ASSERT(identity_cache.ident <= identity_cache.length);
00681             PR_Unlock(identity_cache.ml);
00682             if (NULL != names) PR_DELETE(names);
00683             goto retry;
00684         }
00685     }
00686     if (NULL != name) /* there's a name to be stored */
00687     {
00688         identity_cache.name[identity] = name;
00689     }
00690     identity_cache.ident = identity;
00691     PR_ASSERT(identity_cache.ident <= identity_cache.length);
00692     PR_Unlock(identity_cache.ml);
00693 
00694     if (NULL != old) PR_DELETE(old);
00695     if (NULL != names) PR_DELETE(names);
00696 
00697     return identity;
00698 }  /* PR_GetUniqueIdentity */
00699 
00700 PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
00701 {
00702     if (!_pr_initialized) _PR_ImplicitInitialization();
00703 
00704     if (PR_TOP_IO_LAYER == ident) return NULL;
00705 
00706     PR_ASSERT(ident <= identity_cache.ident);
00707     return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
00708 }  /* PR_GetNameForIdentity */
00709 
00710 PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
00711 {
00712     PR_ASSERT(NULL != fd);
00713     if (PR_IO_LAYER_HEAD == fd->identity) {
00714        PR_ASSERT(NULL != fd->lower);
00715        return fd->lower->identity;
00716        } else
00717        return fd->identity;
00718 }  /* PR_GetLayersIdentity */
00719 
00720 PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
00721 {
00722     PRFileDesc *layer = fd;
00723 
00724     if (PR_TOP_IO_LAYER == id) {
00725        if (PR_IO_LAYER_HEAD == fd->identity)
00726                      return fd->lower;
00727               else 
00728                      return fd;
00729        }
00730 
00731     for (layer = fd; layer != NULL; layer = layer->lower)
00732     {
00733         if (id == layer->identity) return layer;
00734     }
00735     for (layer = fd; layer != NULL; layer = layer->higher)
00736     {
00737         if (id == layer->identity) return layer;
00738     }
00739     return NULL;
00740 }  /* PR_GetIdentitiesLayer */
00741 
00742 void _PR_InitLayerCache(void)
00743 {
00744     memset(&identity_cache, 0, sizeof(identity_cache));
00745     identity_cache.ml = PR_NewLock();
00746     PR_ASSERT(NULL != identity_cache.ml);
00747 }  /* _PR_InitLayerCache */
00748 
00749 void _PR_CleanupLayerCache(void)
00750 {
00751     if (identity_cache.ml)
00752     {
00753         PR_DestroyLock(identity_cache.ml);
00754         identity_cache.ml = NULL;
00755     }
00756 
00757     if (identity_cache.name)
00758     {
00759         PRDescIdentity ident;
00760 
00761         for (ident = 0; ident <= identity_cache.ident; ident++)
00762             PR_DELETE(identity_cache.name[ident]);
00763 
00764         PR_DELETE(identity_cache.name);
00765     }
00766 }  /* _PR_CleanupLayerCache */
00767 
00768 /* prlayer.c */