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