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