nsprpub/pr/src/io/prlayer.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial