nsprpub/pr/src/io/prlayer.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/io/prlayer.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,752 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** File:        prlayer.c
    1.11 +** Description: Routines for handling pushable protocol modules on sockets.
    1.12 +*/
    1.13 +
    1.14 +#include "primpl.h"
    1.15 +#include "prerror.h"
    1.16 +#include "prmem.h"
    1.17 +#include "prlock.h"
    1.18 +#include "prlog.h"
    1.19 +#include "prio.h"
    1.20 +
    1.21 +#include <string.h> /* for memset() */
    1.22 +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
    1.23 +
    1.24 +void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
    1.25 +{
    1.26 +    PR_ASSERT(fd != NULL);
    1.27 +    if (NULL != fd->lower) fd->lower->higher = fd->higher;
    1.28 +    if (NULL != fd->higher) fd->higher->lower = fd->lower;
    1.29 +    PR_DELETE(fd);
    1.30 +}
    1.31 +
    1.32 +/*
    1.33 +** Default methods that just call down to the next fd.
    1.34 +*/
    1.35 +static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
    1.36 +{
    1.37 +    PRFileDesc *top, *lower;
    1.38 +	PRStatus rv;
    1.39 +
    1.40 +    PR_ASSERT(fd != NULL);
    1.41 +    PR_ASSERT(fd->lower != NULL);
    1.42 +    PR_ASSERT(fd->secret == NULL);
    1.43 +    PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
    1.44 +
    1.45 +	if (PR_IO_LAYER_HEAD == fd->identity) {
    1.46 +		/*
    1.47 +		 * new style stack; close all the layers, before deleting the
    1.48 +		 * stack head
    1.49 +		 */
    1.50 +		rv = fd->lower->methods->close(fd->lower);
    1.51 +		_PR_DestroyIOLayer(fd);
    1.52 +		return rv;
    1.53 +	} else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
    1.54 +		/*
    1.55 +		 * lower layers of new style stack
    1.56 +		 */
    1.57 +		lower = fd->lower;
    1.58 +		/*
    1.59 +		 * pop and cleanup current layer
    1.60 +		 */
    1.61 +    	top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
    1.62 +		top->dtor(top);
    1.63 +		/*
    1.64 +		 * then call lower layer
    1.65 +		 */
    1.66 +		return (lower->methods->close(lower));
    1.67 +	} else {
    1.68 +		/* old style stack */
    1.69 +    	top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
    1.70 +		top->dtor(top);
    1.71 +		return (fd->methods->close)(fd);
    1.72 +	}
    1.73 +}
    1.74 +
    1.75 +static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
    1.76 +{
    1.77 +    PR_ASSERT(fd != NULL);
    1.78 +    PR_ASSERT(fd->lower != NULL);
    1.79 +
    1.80 +    return (fd->lower->methods->read)(fd->lower, buf, amount);
    1.81 +}
    1.82 +
    1.83 +static PRInt32 PR_CALLBACK pl_DefWrite (
    1.84 +    PRFileDesc *fd, const void *buf, PRInt32 amount)
    1.85 +{
    1.86 +    PR_ASSERT(fd != NULL);
    1.87 +    PR_ASSERT(fd->lower != NULL);
    1.88 +
    1.89 +    return (fd->lower->methods->write)(fd->lower, buf, amount);
    1.90 +}
    1.91 +
    1.92 +static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
    1.93 +{
    1.94 +    PR_ASSERT(fd != NULL);
    1.95 +    PR_ASSERT(fd->lower != NULL);
    1.96 +
    1.97 +    return (fd->lower->methods->available)(fd->lower);
    1.98 +}
    1.99 +
   1.100 +static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
   1.101 +{
   1.102 +    PR_ASSERT(fd != NULL);
   1.103 +    PR_ASSERT(fd->lower != NULL);
   1.104 +
   1.105 +    return (fd->lower->methods->available64)(fd->lower);
   1.106 +}
   1.107 +
   1.108 +static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
   1.109 +{
   1.110 +    PR_ASSERT(fd != NULL);
   1.111 +    PR_ASSERT(fd->lower != NULL);
   1.112 +
   1.113 +    return (fd->lower->methods->fsync)(fd->lower);
   1.114 +}
   1.115 +
   1.116 +static PRInt32 PR_CALLBACK pl_DefSeek (
   1.117 +    PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
   1.118 +{
   1.119 +    PR_ASSERT(fd != NULL);
   1.120 +    PR_ASSERT(fd->lower != NULL);
   1.121 +
   1.122 +    return (fd->lower->methods->seek)(fd->lower, offset, how);
   1.123 +}
   1.124 +
   1.125 +static PRInt64 PR_CALLBACK pl_DefSeek64 (
   1.126 +    PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
   1.127 +{
   1.128 +    PR_ASSERT(fd != NULL);
   1.129 +    PR_ASSERT(fd->lower != NULL);
   1.130 +
   1.131 +    return (fd->lower->methods->seek64)(fd->lower, offset, how);
   1.132 +}
   1.133 +
   1.134 +static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
   1.135 +{
   1.136 +    PR_ASSERT(fd != NULL);
   1.137 +    PR_ASSERT(fd->lower != NULL);
   1.138 +
   1.139 +    return (fd->lower->methods->fileInfo)(fd->lower, info);
   1.140 +}
   1.141 +
   1.142 +static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
   1.143 +{
   1.144 +    PR_ASSERT(fd != NULL);
   1.145 +    PR_ASSERT(fd->lower != NULL);
   1.146 +
   1.147 +    return (fd->lower->methods->fileInfo64)(fd->lower, info);
   1.148 +}
   1.149 +
   1.150 +static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
   1.151 +    PRInt32 size, PRIntervalTime timeout)
   1.152 +{
   1.153 +    PR_ASSERT(fd != NULL);
   1.154 +    PR_ASSERT(fd->lower != NULL);
   1.155 +
   1.156 +    return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
   1.157 +}
   1.158 +
   1.159 +static PRStatus PR_CALLBACK pl_DefConnect (
   1.160 +    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
   1.161 +{
   1.162 +    PR_ASSERT(fd != NULL);
   1.163 +    PR_ASSERT(fd->lower != NULL);
   1.164 +
   1.165 +    return (fd->lower->methods->connect)(fd->lower, addr, timeout);
   1.166 +}
   1.167 +
   1.168 +static PRStatus PR_CALLBACK pl_DefConnectcontinue (
   1.169 +    PRFileDesc *fd, PRInt16 out_flags)
   1.170 +{
   1.171 +    PR_ASSERT(fd != NULL);
   1.172 +    PR_ASSERT(fd->lower != NULL);
   1.173 +
   1.174 +    return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
   1.175 +}
   1.176 +
   1.177 +static PRFileDesc* PR_CALLBACK pl_TopAccept (
   1.178 +    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
   1.179 +{
   1.180 +    PRStatus rv;
   1.181 +    PRFileDesc *newfd, *layer = fd;
   1.182 +    PRFileDesc *newstack;
   1.183 +	PRBool newstyle_stack = PR_FALSE;
   1.184 +
   1.185 +    PR_ASSERT(fd != NULL);
   1.186 +    PR_ASSERT(fd->lower != NULL);
   1.187 +
   1.188 +	/* test for new style stack */
   1.189 +	while (NULL != layer->higher)
   1.190 +		layer = layer->higher;
   1.191 +	newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
   1.192 +    newstack = PR_NEW(PRFileDesc);
   1.193 +    if (NULL == newstack)
   1.194 +    {
   1.195 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.196 +        return NULL;
   1.197 +    }
   1.198 +    *newstack = *fd;  /* make a copy of the accepting layer */
   1.199 +
   1.200 +    newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
   1.201 +    if (NULL == newfd)
   1.202 +    {
   1.203 +        PR_DELETE(newstack);
   1.204 +        return NULL;
   1.205 +    }
   1.206 +
   1.207 +    if (newstyle_stack) {
   1.208 +		newstack->lower = newfd;
   1.209 +		newfd->higher = newstack;
   1.210 +		return newstack;
   1.211 +	} else {
   1.212 +		/* this PR_PushIOLayer call cannot fail */
   1.213 +		rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
   1.214 +		PR_ASSERT(PR_SUCCESS == rv);
   1.215 +    	return newfd;  /* that's it */
   1.216 +	}
   1.217 +}
   1.218 +
   1.219 +static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
   1.220 +{
   1.221 +    PR_ASSERT(fd != NULL);
   1.222 +    PR_ASSERT(fd->lower != NULL);
   1.223 +
   1.224 +    return (fd->lower->methods->bind)(fd->lower, addr);
   1.225 +}
   1.226 +
   1.227 +static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
   1.228 +{
   1.229 +    PR_ASSERT(fd != NULL);
   1.230 +    PR_ASSERT(fd->lower != NULL);
   1.231 +
   1.232 +    return (fd->lower->methods->listen)(fd->lower, backlog);
   1.233 +}
   1.234 +
   1.235 +static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
   1.236 +{
   1.237 +    PR_ASSERT(fd != NULL);
   1.238 +    PR_ASSERT(fd->lower != NULL);
   1.239 +
   1.240 +    return (fd->lower->methods->shutdown)(fd->lower, how);
   1.241 +}
   1.242 +
   1.243 +static PRInt32 PR_CALLBACK pl_DefRecv (
   1.244 +    PRFileDesc *fd, void *buf, PRInt32 amount,
   1.245 +    PRIntn flags, PRIntervalTime timeout)
   1.246 +{
   1.247 +    PR_ASSERT(fd != NULL);
   1.248 +    PR_ASSERT(fd->lower != NULL);
   1.249 +
   1.250 +    return (fd->lower->methods->recv)(
   1.251 +        fd->lower, buf, amount, flags, timeout);
   1.252 +}
   1.253 +
   1.254 +static PRInt32 PR_CALLBACK pl_DefSend (
   1.255 +    PRFileDesc *fd, const void *buf,
   1.256 +    PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
   1.257 +{
   1.258 +    PR_ASSERT(fd != NULL);
   1.259 +    PR_ASSERT(fd->lower != NULL);
   1.260 +
   1.261 +    return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
   1.262 +}
   1.263 +
   1.264 +static PRInt32 PR_CALLBACK pl_DefRecvfrom (
   1.265 +    PRFileDesc *fd, void *buf, PRInt32 amount,
   1.266 +    PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
   1.267 +{
   1.268 +    PR_ASSERT(fd != NULL);
   1.269 +    PR_ASSERT(fd->lower != NULL);
   1.270 +
   1.271 +    return (fd->lower->methods->recvfrom)(
   1.272 +        fd->lower, buf, amount, flags, addr, timeout);
   1.273 +}
   1.274 +
   1.275 +static PRInt32 PR_CALLBACK pl_DefSendto (
   1.276 +    PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
   1.277 +    const PRNetAddr *addr, PRIntervalTime timeout)
   1.278 +{
   1.279 +    PR_ASSERT(fd != NULL);
   1.280 +    PR_ASSERT(fd->lower != NULL);
   1.281 +
   1.282 +    return (fd->lower->methods->sendto)(
   1.283 +        fd->lower, buf, amount, flags, addr, timeout);
   1.284 +}
   1.285 +
   1.286 +static PRInt16 PR_CALLBACK pl_DefPoll (
   1.287 +    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
   1.288 +{
   1.289 +    PR_ASSERT(fd != NULL);
   1.290 +    PR_ASSERT(fd->lower != NULL);
   1.291 +
   1.292 +    return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
   1.293 +}
   1.294 +
   1.295 +static PRInt32 PR_CALLBACK pl_DefAcceptread (
   1.296 +    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
   1.297 +    PRInt32 amount, PRIntervalTime t)
   1.298 +{
   1.299 +    PRInt32 nbytes;
   1.300 +    PRStatus rv;
   1.301 +    PRFileDesc *newstack;
   1.302 +    PRFileDesc *layer = sd;
   1.303 +	PRBool newstyle_stack = PR_FALSE;
   1.304 +
   1.305 +    PR_ASSERT(sd != NULL);
   1.306 +    PR_ASSERT(sd->lower != NULL);
   1.307 +
   1.308 +	/* test for new style stack */
   1.309 +	while (NULL != layer->higher)
   1.310 +		layer = layer->higher;
   1.311 +	newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
   1.312 +    newstack = PR_NEW(PRFileDesc);
   1.313 +    if (NULL == newstack)
   1.314 +    {
   1.315 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.316 +        return -1;
   1.317 +    }
   1.318 +    *newstack = *sd;  /* make a copy of the accepting layer */
   1.319 +
   1.320 +    nbytes = sd->lower->methods->acceptread(
   1.321 +        sd->lower, nd, raddr, buf, amount, t);
   1.322 +    if (-1 == nbytes)
   1.323 +    {
   1.324 +        PR_DELETE(newstack);
   1.325 +        return nbytes;
   1.326 +    }
   1.327 +    if (newstyle_stack) {
   1.328 +		newstack->lower = *nd;
   1.329 +		(*nd)->higher = newstack;
   1.330 +		*nd = newstack;
   1.331 +		return nbytes;
   1.332 +	} else {
   1.333 +		/* this PR_PushIOLayer call cannot fail */
   1.334 +		rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
   1.335 +		PR_ASSERT(PR_SUCCESS == rv);
   1.336 +		return nbytes;
   1.337 +	}
   1.338 +}
   1.339 +
   1.340 +static PRInt32 PR_CALLBACK pl_DefTransmitfile (
   1.341 +    PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
   1.342 +    PRTransmitFileFlags flags, PRIntervalTime t)
   1.343 +{
   1.344 +    PR_ASSERT(sd != NULL);
   1.345 +    PR_ASSERT(sd->lower != NULL);
   1.346 +
   1.347 +    return sd->lower->methods->transmitfile(
   1.348 +        sd->lower, fd, headers, hlen, flags, t);
   1.349 +}
   1.350 +
   1.351 +static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
   1.352 +{
   1.353 +    PR_ASSERT(fd != NULL);
   1.354 +    PR_ASSERT(fd->lower != NULL);
   1.355 +
   1.356 +    return (fd->lower->methods->getsockname)(fd->lower, addr);
   1.357 +}
   1.358 +
   1.359 +static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
   1.360 +{
   1.361 +    PR_ASSERT(fd != NULL);
   1.362 +    PR_ASSERT(fd->lower != NULL);
   1.363 +
   1.364 +    return (fd->lower->methods->getpeername)(fd->lower, addr);
   1.365 +}
   1.366 +
   1.367 +static PRStatus PR_CALLBACK pl_DefGetsocketoption (
   1.368 +    PRFileDesc *fd, PRSocketOptionData *data)
   1.369 +{
   1.370 +    PR_ASSERT(fd != NULL);
   1.371 +    PR_ASSERT(fd->lower != NULL);
   1.372 +
   1.373 +    return (fd->lower->methods->getsocketoption)(fd->lower, data);
   1.374 +}
   1.375 +
   1.376 +static PRStatus PR_CALLBACK pl_DefSetsocketoption (
   1.377 +    PRFileDesc *fd, const PRSocketOptionData *data)
   1.378 +{
   1.379 +    PR_ASSERT(fd != NULL);
   1.380 +    PR_ASSERT(fd->lower != NULL);
   1.381 +
   1.382 +    return (fd->lower->methods->setsocketoption)(fd->lower, data);
   1.383 +}
   1.384 +
   1.385 +static PRInt32 PR_CALLBACK pl_DefSendfile (
   1.386 +	PRFileDesc *sd, PRSendFileData *sfd,
   1.387 +	PRTransmitFileFlags flags, PRIntervalTime timeout)
   1.388 +{
   1.389 +    PR_ASSERT(sd != NULL);
   1.390 +    PR_ASSERT(sd->lower != NULL);
   1.391 +
   1.392 +    return sd->lower->methods->sendfile(
   1.393 +        sd->lower, sfd, flags, timeout);
   1.394 +}
   1.395 +
   1.396 +/* Methods for the top of the stack.  Just call down to the next fd. */
   1.397 +static PRIOMethods pl_methods = {
   1.398 +    PR_DESC_LAYERED,
   1.399 +    pl_TopClose,
   1.400 +    pl_DefRead,
   1.401 +    pl_DefWrite,
   1.402 +    pl_DefAvailable,
   1.403 +    pl_DefAvailable64,
   1.404 +    pl_DefFsync,
   1.405 +    pl_DefSeek,
   1.406 +    pl_DefSeek64,
   1.407 +    pl_DefFileInfo,
   1.408 +    pl_DefFileInfo64,
   1.409 +    pl_DefWritev,
   1.410 +    pl_DefConnect,
   1.411 +    pl_TopAccept,
   1.412 +    pl_DefBind,
   1.413 +    pl_DefListen,
   1.414 +    pl_DefShutdown,
   1.415 +    pl_DefRecv,
   1.416 +    pl_DefSend,
   1.417 +    pl_DefRecvfrom,
   1.418 +    pl_DefSendto,
   1.419 +    pl_DefPoll,
   1.420 +    pl_DefAcceptread,
   1.421 +    pl_DefTransmitfile,
   1.422 +    pl_DefGetsockname,
   1.423 +    pl_DefGetpeername,
   1.424 +    (PRReservedFN)_PR_InvalidInt,
   1.425 +    (PRReservedFN)_PR_InvalidInt,
   1.426 +    pl_DefGetsocketoption,
   1.427 +    pl_DefSetsocketoption,
   1.428 +    pl_DefSendfile,
   1.429 +    pl_DefConnectcontinue,
   1.430 +    (PRReservedFN)_PR_InvalidInt,
   1.431 +    (PRReservedFN)_PR_InvalidInt,
   1.432 +    (PRReservedFN)_PR_InvalidInt,
   1.433 +    (PRReservedFN)_PR_InvalidInt
   1.434 +};
   1.435 +
   1.436 +PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
   1.437 +{
   1.438 +    return &pl_methods;
   1.439 +}  /* PR_GetDefaultIOMethods */
   1.440 +
   1.441 +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
   1.442 +    PRDescIdentity ident, const PRIOMethods *methods)
   1.443 +{
   1.444 +    PRFileDesc *fd = NULL;
   1.445 +    PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
   1.446 +    if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
   1.447 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.448 +    else
   1.449 +    {
   1.450 +        fd = PR_NEWZAP(PRFileDesc);
   1.451 +        if (NULL == fd)
   1.452 +            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.453 +        else
   1.454 +        {
   1.455 +            fd->methods = methods;
   1.456 +            fd->dtor = pl_FDDestructor;
   1.457 +            fd->identity = ident;
   1.458 +        }
   1.459 +    }
   1.460 +    return fd;
   1.461 +}  /* PR_CreateIOLayerStub */
   1.462 +
   1.463 +/*
   1.464 + * PR_CreateIOLayer
   1.465 + *		Create a new style stack, where the stack top is a dummy header.
   1.466 + *		Unlike the old style stacks, the contents of the stack head
   1.467 + *		are not modified when a layer is pushed onto or popped from a new
   1.468 + *		style stack.
   1.469 + */
   1.470 +
   1.471 +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
   1.472 +{
   1.473 +    PRFileDesc *fd = NULL;
   1.474 +
   1.475 +	fd = PR_NEWZAP(PRFileDesc);
   1.476 +	if (NULL == fd)
   1.477 +		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.478 +	else
   1.479 +	{
   1.480 +		fd->methods = &pl_methods;
   1.481 +		fd->dtor = pl_FDDestructor;
   1.482 +		fd->identity = PR_IO_LAYER_HEAD;
   1.483 +		fd->higher = NULL;
   1.484 +		fd->lower = top;
   1.485 +		top->higher = fd;
   1.486 +		top->lower = NULL;
   1.487 +	}
   1.488 +    return fd;
   1.489 +}  /* PR_CreateIOLayer */
   1.490 +
   1.491 +/*
   1.492 + * _PR_DestroyIOLayer
   1.493 + *		Delete the stack head of a new style stack.
   1.494 + */
   1.495 +
   1.496 +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
   1.497 +{
   1.498 +    if (NULL == stack)
   1.499 +        return PR_FAILURE;
   1.500 +    else {
   1.501 +        PR_DELETE(stack);
   1.502 +    	return PR_SUCCESS;
   1.503 +    }
   1.504 +}  /* _PR_DestroyIOLayer */
   1.505 +
   1.506 +PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
   1.507 +    PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
   1.508 +{
   1.509 +    PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
   1.510 +
   1.511 +    PR_ASSERT(fd != NULL);
   1.512 +    PR_ASSERT(stack != NULL);
   1.513 +    PR_ASSERT(insert != NULL);
   1.514 +    PR_ASSERT(PR_IO_LAYER_HEAD != id);
   1.515 +    if ((NULL == stack) || (NULL == fd) || (NULL == insert))
   1.516 +    {
   1.517 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.518 +        return PR_FAILURE;
   1.519 +    }
   1.520 +
   1.521 +    if (stack == insert)
   1.522 +    {
   1.523 +		/* going on top of the stack */
   1.524 +		/* old-style stack */	
   1.525 +		PRFileDesc copy = *stack;
   1.526 +		*stack = *fd;
   1.527 +		*fd = copy;
   1.528 +		fd->higher = stack;
   1.529 +		if (fd->lower)
   1.530 +		{
   1.531 +			PR_ASSERT(fd->lower->higher == stack);
   1.532 +			fd->lower->higher = fd;
   1.533 +		}
   1.534 +		stack->lower = fd;
   1.535 +		stack->higher = NULL;
   1.536 +	} else {
   1.537 +        /*
   1.538 +		 * going somewhere in the middle of the stack for both old and new
   1.539 +		 * style stacks, or going on top of stack for new style stack
   1.540 +		 */
   1.541 +        fd->lower = insert;
   1.542 +        fd->higher = insert->higher;
   1.543 +
   1.544 +        insert->higher->lower = fd;
   1.545 +        insert->higher = fd;
   1.546 +    }
   1.547 +
   1.548 +    return PR_SUCCESS;
   1.549 +}
   1.550 +
   1.551 +PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
   1.552 +{
   1.553 +    PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
   1.554 +
   1.555 +    PR_ASSERT(0 != id);
   1.556 +    PR_ASSERT(NULL != stack);
   1.557 +    PR_ASSERT(NULL != extract);
   1.558 +    if ((NULL == stack) || (0 == id) || (NULL == extract))
   1.559 +    {
   1.560 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.561 +        return NULL;
   1.562 +    }
   1.563 +
   1.564 +    if (extract == stack) {
   1.565 +        /* popping top layer of the stack */
   1.566 +		/* old style stack */
   1.567 +        PRFileDesc copy = *stack;
   1.568 +        extract = stack->lower;
   1.569 +        *stack = *extract;
   1.570 +        *extract = copy;
   1.571 +        stack->higher = NULL;
   1.572 +        if (stack->lower) {
   1.573 +            PR_ASSERT(stack->lower->higher == extract);
   1.574 +            stack->lower->higher = stack;
   1.575 +        }
   1.576 +	} else if ((PR_IO_LAYER_HEAD == stack->identity) &&
   1.577 +					(extract == stack->lower) && (extract->lower == NULL)) {
   1.578 +			/*
   1.579 +			 * new style stack
   1.580 +			 * popping the only layer in the stack; delete the stack too
   1.581 +			 */
   1.582 +			stack->lower = NULL;
   1.583 +			_PR_DestroyIOLayer(stack);
   1.584 +	} else {
   1.585 +		/* for both kinds of stacks */
   1.586 +        extract->lower->higher = extract->higher;
   1.587 +        extract->higher->lower = extract->lower;
   1.588 +    }
   1.589 +    extract->higher = extract->lower = NULL;
   1.590 +    return extract;
   1.591 +}  /* PR_PopIOLayer */
   1.592 +
   1.593 +#define ID_CACHE_INCREMENT 16
   1.594 +typedef struct _PRIdentity_cache
   1.595 +{
   1.596 +    PRLock *ml;
   1.597 +    char **name;
   1.598 +    PRIntn length;
   1.599 +    PRDescIdentity ident;
   1.600 +} _PRIdentity_cache;
   1.601 +
   1.602 +static _PRIdentity_cache identity_cache;
   1.603 +
   1.604 +PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
   1.605 +{
   1.606 +    PRDescIdentity identity, length;
   1.607 +    char **names = NULL, *name = NULL, **old = NULL;
   1.608 +
   1.609 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.610 +
   1.611 +    PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
   1.612 +
   1.613 +    if (NULL != layer_name)
   1.614 +    {
   1.615 +        name = (char*)PR_Malloc(strlen(layer_name) + 1);
   1.616 +        if (NULL == name)
   1.617 +        {
   1.618 +            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.619 +            return PR_INVALID_IO_LAYER;
   1.620 +        }
   1.621 +        strcpy(name, layer_name);
   1.622 +    }
   1.623 +
   1.624 +    /* this initial code runs unsafe */
   1.625 +retry:
   1.626 +    PR_ASSERT(NULL == names);
   1.627 +    /*
   1.628 +     * In the initial round, both identity_cache.ident and
   1.629 +     * identity_cache.length are 0, so (identity_cache.ident + 1) is greater
   1.630 +     * than length.  In later rounds, identity_cache.ident is always less
   1.631 +     * than length, so (identity_cache.ident + 1) can be equal to but cannot
   1.632 +     * be greater than length.
   1.633 +     */
   1.634 +    length = identity_cache.length;
   1.635 +    if ((identity_cache.ident + 1) >= length)
   1.636 +    {
   1.637 +        length += ID_CACHE_INCREMENT;
   1.638 +        names = (char**)PR_CALLOC(length * sizeof(char*));
   1.639 +        if (NULL == names)
   1.640 +        {
   1.641 +            if (NULL != name) PR_DELETE(name);
   1.642 +            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.643 +            return PR_INVALID_IO_LAYER;
   1.644 +        }
   1.645 +    }
   1.646 +
   1.647 +    /* now we get serious about thread safety */
   1.648 +    PR_Lock(identity_cache.ml);
   1.649 +    PR_ASSERT(identity_cache.length == 0 ||
   1.650 +              identity_cache.ident < identity_cache.length);
   1.651 +    identity = identity_cache.ident + 1;
   1.652 +    if (identity >= identity_cache.length)  /* there's no room */
   1.653 +    {
   1.654 +        /* we have to do something - hopefully it's already done */
   1.655 +        if ((NULL != names) && (identity < length))
   1.656 +        {
   1.657 +            /* what we did is still okay */
   1.658 +            memcpy(
   1.659 +                names, identity_cache.name,
   1.660 +                identity_cache.length * sizeof(char*));
   1.661 +            old = identity_cache.name;
   1.662 +            identity_cache.name = names;
   1.663 +            identity_cache.length = length;
   1.664 +            names = NULL;
   1.665 +        }
   1.666 +        else
   1.667 +        {
   1.668 +            PR_Unlock(identity_cache.ml);
   1.669 +            if (NULL != names) PR_DELETE(names);
   1.670 +            goto retry;
   1.671 +        }
   1.672 +    }
   1.673 +    if (NULL != name) /* there's a name to be stored */
   1.674 +    {
   1.675 +        identity_cache.name[identity] = name;
   1.676 +    }
   1.677 +    identity_cache.ident = identity;
   1.678 +    PR_ASSERT(identity_cache.ident < identity_cache.length);
   1.679 +    PR_Unlock(identity_cache.ml);
   1.680 +
   1.681 +    if (NULL != old) PR_DELETE(old);
   1.682 +    if (NULL != names) PR_DELETE(names);
   1.683 +
   1.684 +    return identity;
   1.685 +}  /* PR_GetUniqueIdentity */
   1.686 +
   1.687 +PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
   1.688 +{
   1.689 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.690 +
   1.691 +    if (PR_TOP_IO_LAYER == ident) return NULL;
   1.692 +
   1.693 +    PR_ASSERT(ident <= identity_cache.ident);
   1.694 +    return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
   1.695 +}  /* PR_GetNameForIdentity */
   1.696 +
   1.697 +PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
   1.698 +{
   1.699 +    PR_ASSERT(NULL != fd);
   1.700 +    if (PR_IO_LAYER_HEAD == fd->identity) {
   1.701 +    	PR_ASSERT(NULL != fd->lower);
   1.702 +    	return fd->lower->identity;
   1.703 +	} else
   1.704 +    	return fd->identity;
   1.705 +}  /* PR_GetLayersIdentity */
   1.706 +
   1.707 +PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
   1.708 +{
   1.709 +    PRFileDesc *layer = fd;
   1.710 +
   1.711 +    if (PR_TOP_IO_LAYER == id) {
   1.712 +    	if (PR_IO_LAYER_HEAD == fd->identity)
   1.713 +			return fd->lower;
   1.714 +		else 
   1.715 +			return fd;
   1.716 +	}
   1.717 +
   1.718 +    for (layer = fd; layer != NULL; layer = layer->lower)
   1.719 +    {
   1.720 +        if (id == layer->identity) return layer;
   1.721 +    }
   1.722 +    for (layer = fd; layer != NULL; layer = layer->higher)
   1.723 +    {
   1.724 +        if (id == layer->identity) return layer;
   1.725 +    }
   1.726 +    return NULL;
   1.727 +}  /* PR_GetIdentitiesLayer */
   1.728 +
   1.729 +void _PR_InitLayerCache(void)
   1.730 +{
   1.731 +    memset(&identity_cache, 0, sizeof(identity_cache));
   1.732 +    identity_cache.ml = PR_NewLock();
   1.733 +    PR_ASSERT(NULL != identity_cache.ml);
   1.734 +}  /* _PR_InitLayerCache */
   1.735 +
   1.736 +void _PR_CleanupLayerCache(void)
   1.737 +{
   1.738 +    if (identity_cache.ml)
   1.739 +    {
   1.740 +        PR_DestroyLock(identity_cache.ml);
   1.741 +        identity_cache.ml = NULL;
   1.742 +    }
   1.743 +
   1.744 +    if (identity_cache.name)
   1.745 +    {
   1.746 +        PRDescIdentity ident;
   1.747 +
   1.748 +        for (ident = 0; ident <= identity_cache.ident; ident++)
   1.749 +            PR_DELETE(identity_cache.name[ident]);
   1.750 +
   1.751 +        PR_DELETE(identity_cache.name);
   1.752 +    }
   1.753 +}  /* _PR_CleanupLayerCache */
   1.754 +
   1.755 +/* prlayer.c */

mercurial