| /* -*- 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 */ |