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