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