summaryrefslogtreecommitdiff
path: root/pr/src/io/prlayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'pr/src/io/prlayer.c')
-rw-r--r--pr/src/io/prlayer.c768
1 files changed, 768 insertions, 0 deletions
diff --git a/pr/src/io/prlayer.c b/pr/src/io/prlayer.c
new file mode 100644
index 0000000..cf48d23
--- /dev/null
+++ b/pr/src/io/prlayer.c
@@ -0,0 +1,768 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File: prlayer.c
+** Description: Routines for handling pushable protocol modules on sockets.
+*/
+
+#include "primpl.h"
+#include "prerror.h"
+#include "prmem.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prio.h"
+
+#include <string.h> /* for memset() */
+static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
+
+void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
+{
+ PR_ASSERT(fd != NULL);
+ if (NULL != fd->lower) fd->lower->higher = fd->higher;
+ if (NULL != fd->higher) fd->higher->lower = fd->lower;
+ PR_DELETE(fd);
+}
+
+/*
+** Default methods that just call down to the next fd.
+*/
+static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
+{
+ PRFileDesc *top, *lower;
+ PRStatus rv;
+
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+ PR_ASSERT(fd->secret == NULL);
+ PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
+
+ if (PR_IO_LAYER_HEAD == fd->identity) {
+ /*
+ * new style stack; close all the layers, before deleting the
+ * stack head
+ */
+ rv = fd->lower->methods->close(fd->lower);
+ _PR_DestroyIOLayer(fd);
+ return rv;
+ } else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
+ /*
+ * lower layers of new style stack
+ */
+ lower = fd->lower;
+ /*
+ * pop and cleanup current layer
+ */
+ top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
+ top->dtor(top);
+ /*
+ * then call lower layer
+ */
+ return (lower->methods->close(lower));
+ } else {
+ /* old style stack */
+ top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+ top->dtor(top);
+ return (fd->methods->close)(fd);
+ }
+}
+
+static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->read)(fd->lower, buf, amount);
+}
+
+static PRInt32 PR_CALLBACK pl_DefWrite (
+ PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->write)(fd->lower, buf, amount);
+}
+
+static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->available)(fd->lower);
+}
+
+static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->available64)(fd->lower);
+}
+
+static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->fsync)(fd->lower);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSeek (
+ PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->seek)(fd->lower, offset, how);
+}
+
+static PRInt64 PR_CALLBACK pl_DefSeek64 (
+ PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->seek64)(fd->lower, offset, how);
+}
+
+static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->fileInfo)(fd->lower, info);
+}
+
+static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->fileInfo64)(fd->lower, info);
+}
+
+static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
+ PRInt32 size, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
+}
+
+static PRStatus PR_CALLBACK pl_DefConnect (
+ PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->connect)(fd->lower, addr, timeout);
+}
+
+static PRStatus PR_CALLBACK pl_DefConnectcontinue (
+ PRFileDesc *fd, PRInt16 out_flags)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
+}
+
+static PRFileDesc* PR_CALLBACK pl_TopAccept (
+ PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PRStatus rv;
+ PRFileDesc *newfd, *layer = fd;
+ PRFileDesc *newstack;
+ PRBool newstyle_stack = PR_FALSE;
+
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ /* test for new style stack */
+ while (NULL != layer->higher)
+ layer = layer->higher;
+ newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
+ newstack = PR_NEW(PRFileDesc);
+ if (NULL == newstack)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+ *newstack = *fd; /* make a copy of the accepting layer */
+
+ newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
+ if (NULL == newfd)
+ {
+ PR_DELETE(newstack);
+ return NULL;
+ }
+
+ if (newstyle_stack) {
+ newstack->lower = newfd;
+ newfd->higher = newstack;
+ return newstack;
+ } else {
+ /* this PR_PushIOLayer call cannot fail */
+ rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
+ PR_ASSERT(PR_SUCCESS == rv);
+ return newfd; /* that's it */
+ }
+}
+
+static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->bind)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->listen)(fd->lower, backlog);
+}
+
+static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->shutdown)(fd->lower, how);
+}
+
+static PRInt32 PR_CALLBACK pl_DefRecv (
+ PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->recv)(
+ fd->lower, buf, amount, flags, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSend (
+ PRFileDesc *fd, const void *buf,
+ PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefRecvfrom (
+ PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->recvfrom)(
+ fd->lower, buf, amount, flags, addr, timeout);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSendto (
+ PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+ const PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->sendto)(
+ fd->lower, buf, amount, flags, addr, timeout);
+}
+
+static PRInt16 PR_CALLBACK pl_DefPoll (
+ PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
+}
+
+static PRInt32 PR_CALLBACK pl_DefAcceptread (
+ PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
+ PRInt32 amount, PRIntervalTime t)
+{
+ PRInt32 nbytes;
+ PRStatus rv;
+ PRFileDesc *newstack;
+ PRFileDesc *layer = sd;
+ PRBool newstyle_stack = PR_FALSE;
+
+ PR_ASSERT(sd != NULL);
+ PR_ASSERT(sd->lower != NULL);
+
+ /* test for new style stack */
+ while (NULL != layer->higher)
+ layer = layer->higher;
+ newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
+ newstack = PR_NEW(PRFileDesc);
+ if (NULL == newstack)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return -1;
+ }
+ *newstack = *sd; /* make a copy of the accepting layer */
+
+ nbytes = sd->lower->methods->acceptread(
+ sd->lower, nd, raddr, buf, amount, t);
+ if (-1 == nbytes)
+ {
+ PR_DELETE(newstack);
+ return nbytes;
+ }
+ if (newstyle_stack) {
+ newstack->lower = *nd;
+ (*nd)->higher = newstack;
+ *nd = newstack;
+ return nbytes;
+ } else {
+ /* this PR_PushIOLayer call cannot fail */
+ rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
+ PR_ASSERT(PR_SUCCESS == rv);
+ return nbytes;
+ }
+}
+
+static PRInt32 PR_CALLBACK pl_DefTransmitfile (
+ PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
+ PRTransmitFileFlags flags, PRIntervalTime t)
+{
+ PR_ASSERT(sd != NULL);
+ PR_ASSERT(sd->lower != NULL);
+
+ return sd->lower->methods->transmitfile(
+ sd->lower, fd, headers, hlen, flags, t);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->getsockname)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->getpeername)(fd->lower, addr);
+}
+
+static PRStatus PR_CALLBACK pl_DefGetsocketoption (
+ PRFileDesc *fd, PRSocketOptionData *data)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->getsocketoption)(fd->lower, data);
+}
+
+static PRStatus PR_CALLBACK pl_DefSetsocketoption (
+ PRFileDesc *fd, const PRSocketOptionData *data)
+{
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ return (fd->lower->methods->setsocketoption)(fd->lower, data);
+}
+
+static PRInt32 PR_CALLBACK pl_DefSendfile (
+ PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ PR_ASSERT(sd != NULL);
+ PR_ASSERT(sd->lower != NULL);
+
+ return sd->lower->methods->sendfile(
+ sd->lower, sfd, flags, timeout);
+}
+
+/* Methods for the top of the stack. Just call down to the next fd. */
+static PRIOMethods pl_methods = {
+ PR_DESC_LAYERED,
+ pl_TopClose,
+ pl_DefRead,
+ pl_DefWrite,
+ pl_DefAvailable,
+ pl_DefAvailable64,
+ pl_DefFsync,
+ pl_DefSeek,
+ pl_DefSeek64,
+ pl_DefFileInfo,
+ pl_DefFileInfo64,
+ pl_DefWritev,
+ pl_DefConnect,
+ pl_TopAccept,
+ pl_DefBind,
+ pl_DefListen,
+ pl_DefShutdown,
+ pl_DefRecv,
+ pl_DefSend,
+ pl_DefRecvfrom,
+ pl_DefSendto,
+ pl_DefPoll,
+ pl_DefAcceptread,
+ pl_DefTransmitfile,
+ pl_DefGetsockname,
+ pl_DefGetpeername,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ pl_DefGetsocketoption,
+ pl_DefSetsocketoption,
+ pl_DefSendfile,
+ pl_DefConnectcontinue,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt,
+ (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
+{
+ return &pl_methods;
+} /* PR_GetDefaultIOMethods */
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
+ PRDescIdentity ident, const PRIOMethods *methods)
+{
+ PRFileDesc *fd = NULL;
+ PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
+ if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ else
+ {
+ fd = PR_NEWZAP(PRFileDesc);
+ if (NULL == fd)
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ else
+ {
+ fd->methods = methods;
+ fd->dtor = pl_FDDestructor;
+ fd->identity = ident;
+ }
+ }
+ return fd;
+} /* PR_CreateIOLayerStub */
+
+/*
+ * PR_CreateIOLayer
+ * Create a new style stack, where the stack top is a dummy header.
+ * Unlike the old style stacks, the contents of the stack head
+ * are not modified when a layer is pushed onto or popped from a new
+ * style stack.
+ */
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
+{
+ PRFileDesc *fd = NULL;
+
+ fd = PR_NEWZAP(PRFileDesc);
+ if (NULL == fd)
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ else
+ {
+ fd->methods = &pl_methods;
+ fd->dtor = pl_FDDestructor;
+ fd->identity = PR_IO_LAYER_HEAD;
+ fd->higher = NULL;
+ fd->lower = top;
+ top->higher = fd;
+ top->lower = NULL;
+ }
+ return fd;
+} /* PR_CreateIOLayer */
+
+/*
+ * _PR_DestroyIOLayer
+ * Delete the stack head of a new style stack.
+ */
+
+static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
+{
+ if (NULL == stack)
+ return PR_FAILURE;
+ else {
+ PR_DELETE(stack);
+ return PR_SUCCESS;
+ }
+} /* _PR_DestroyIOLayer */
+
+PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
+ PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
+{
+ PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
+
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(stack != NULL);
+ PR_ASSERT(insert != NULL);
+ PR_ASSERT(PR_IO_LAYER_HEAD != id);
+ if ((NULL == stack) || (NULL == fd) || (NULL == insert))
+ {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ if (stack == insert)
+ {
+ /* going on top of the stack */
+ /* old-style stack */
+ PRFileDesc copy = *stack;
+ *stack = *fd;
+ *fd = copy;
+ fd->higher = stack;
+ stack->lower = fd;
+ stack->higher = NULL;
+ } else {
+ /*
+ * going somewhere in the middle of the stack for both old and new
+ * style stacks, or going on top of stack for new style stack
+ */
+ fd->lower = insert;
+ fd->higher = insert->higher;
+
+ insert->higher->lower = fd;
+ insert->higher = fd;
+ }
+
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
+{
+ PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
+
+ PR_ASSERT(0 != id);
+ PR_ASSERT(NULL != stack);
+ PR_ASSERT(NULL != extract);
+ if ((NULL == stack) || (0 == id) || (NULL == extract))
+ {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ if (extract == stack) {
+ /* popping top layer of the stack */
+ /* old style stack */
+ PRFileDesc copy = *stack;
+ extract = stack->lower;
+ *stack = *extract;
+ *extract = copy;
+ stack->higher = NULL;
+ } else if ((PR_IO_LAYER_HEAD == stack->identity) &&
+ (extract == stack->lower) && (extract->lower == NULL)) {
+ /*
+ * new style stack
+ * popping the only layer in the stack; delete the stack too
+ */
+ stack->lower = NULL;
+ _PR_DestroyIOLayer(stack);
+ } else {
+ /* for both kinds of stacks */
+ extract->lower->higher = extract->higher;
+ extract->higher->lower = extract->lower;
+ }
+ extract->higher = extract->lower = NULL;
+ return extract;
+} /* PR_PopIOLayer */
+
+#define ID_CACHE_INCREMENT 16
+typedef struct _PRIdentity_cache
+{
+ PRLock *ml;
+ char **name;
+ PRIntn length;
+ PRDescIdentity ident;
+} _PRIdentity_cache;
+
+static _PRIdentity_cache identity_cache;
+
+PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
+{
+ PRDescIdentity identity, length;
+ char **names = NULL, *name = NULL, **old = NULL;
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
+
+ if (NULL != layer_name)
+ {
+ name = (char*)PR_Malloc(strlen(layer_name) + 1);
+ if (NULL == name)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return PR_INVALID_IO_LAYER;
+ }
+ strcpy(name, layer_name);
+ }
+
+ /* this initial code runs unsafe */
+retry:
+ PR_ASSERT(NULL == names);
+ length = identity_cache.length;
+ if (length < (identity_cache.ident + 1))
+ {
+ length += ID_CACHE_INCREMENT;
+ names = (char**)PR_CALLOC(length * sizeof(char*));
+ if (NULL == names)
+ {
+ if (NULL != name) PR_DELETE(name);
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return PR_INVALID_IO_LAYER;
+ }
+ }
+
+ /* now we get serious about thread safety */
+ PR_Lock(identity_cache.ml);
+ PR_ASSERT(identity_cache.ident <= identity_cache.length);
+ identity = identity_cache.ident + 1;
+ if (identity > identity_cache.length) /* there's no room */
+ {
+ /* we have to do something - hopefully it's already done */
+ if ((NULL != names) && (length >= identity))
+ {
+ /* what we did is still okay */
+ memcpy(
+ names, identity_cache.name,
+ identity_cache.length * sizeof(char*));
+ old = identity_cache.name;
+ identity_cache.name = names;
+ identity_cache.length = length;
+ names = NULL;
+ }
+ else
+ {
+ PR_ASSERT(identity_cache.ident <= identity_cache.length);
+ PR_Unlock(identity_cache.ml);
+ if (NULL != names) PR_DELETE(names);
+ goto retry;
+ }
+ }
+ if (NULL != name) /* there's a name to be stored */
+ {
+ identity_cache.name[identity] = name;
+ }
+ identity_cache.ident = identity;
+ PR_ASSERT(identity_cache.ident <= identity_cache.length);
+ PR_Unlock(identity_cache.ml);
+
+ if (NULL != old) PR_DELETE(old);
+ if (NULL != names) PR_DELETE(names);
+
+ return identity;
+} /* PR_GetUniqueIdentity */
+
+PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
+{
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ if (PR_TOP_IO_LAYER == ident) return NULL;
+
+ PR_ASSERT(ident <= identity_cache.ident);
+ return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
+} /* PR_GetNameForIdentity */
+
+PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
+{
+ PR_ASSERT(NULL != fd);
+ if (PR_IO_LAYER_HEAD == fd->identity) {
+ PR_ASSERT(NULL != fd->lower);
+ return fd->lower->identity;
+ } else
+ return fd->identity;
+} /* PR_GetLayersIdentity */
+
+PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
+{
+ PRFileDesc *layer = fd;
+
+ if (PR_TOP_IO_LAYER == id) {
+ if (PR_IO_LAYER_HEAD == fd->identity)
+ return fd->lower;
+ else
+ return fd;
+ }
+
+ for (layer = fd; layer != NULL; layer = layer->lower)
+ {
+ if (id == layer->identity) return layer;
+ }
+ for (layer = fd; layer != NULL; layer = layer->higher)
+ {
+ if (id == layer->identity) return layer;
+ }
+ return NULL;
+} /* PR_GetIdentitiesLayer */
+
+void _PR_InitLayerCache(void)
+{
+ memset(&identity_cache, 0, sizeof(identity_cache));
+ identity_cache.ml = PR_NewLock();
+ PR_ASSERT(NULL != identity_cache.ml);
+} /* _PR_InitLayerCache */
+
+void _PR_CleanupLayerCache(void)
+{
+ if (identity_cache.ml)
+ {
+ PR_DestroyLock(identity_cache.ml);
+ identity_cache.ml = NULL;
+ }
+
+ if (identity_cache.name)
+ {
+ PRDescIdentity ident;
+
+ for (ident = 0; ident <= identity_cache.ident; ident++)
+ PR_DELETE(identity_cache.name[ident]);
+
+ PR_DELETE(identity_cache.name);
+ }
+} /* _PR_CleanupLayerCache */
+
+/* prlayer.c */