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