1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
37
** Description: Routines for handling pushable protocol modules on sockets.
47
#include <string.h> /* for memset() */
48
static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack);
50
void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
52
PR_ASSERT(fd != NULL);
53
if (NULL != fd->lower) fd->lower->higher = fd->higher;
54
if (NULL != fd->higher) fd->higher->lower = fd->lower;
59
** Default methods that just call down to the next fd.
61
static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
63
PRFileDesc *top, *lower;
66
PR_ASSERT(fd != NULL);
67
PR_ASSERT(fd->lower != NULL);
68
PR_ASSERT(fd->secret == NULL);
69
PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
71
if (PR_IO_LAYER_HEAD == fd->identity) {
73
* new style stack; close all the layers, before deleting the
76
rv = fd->lower->methods->close(fd->lower);
77
_PR_DestroyIOLayer(fd);
79
} else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) {
81
* lower layers of new style stack
85
* pop and cleanup current layer
87
top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER);
90
* then call lower layer
92
return (lower->methods->close(lower));
95
top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
97
return (fd->methods->close)(fd);
101
static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
103
PR_ASSERT(fd != NULL);
104
PR_ASSERT(fd->lower != NULL);
106
return (fd->lower->methods->read)(fd->lower, buf, amount);
109
static PRInt32 PR_CALLBACK pl_DefWrite (
110
PRFileDesc *fd, const void *buf, PRInt32 amount)
112
PR_ASSERT(fd != NULL);
113
PR_ASSERT(fd->lower != NULL);
115
return (fd->lower->methods->write)(fd->lower, buf, amount);
118
static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
120
PR_ASSERT(fd != NULL);
121
PR_ASSERT(fd->lower != NULL);
123
return (fd->lower->methods->available)(fd->lower);
126
static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
128
PR_ASSERT(fd != NULL);
129
PR_ASSERT(fd->lower != NULL);
131
return (fd->lower->methods->available64)(fd->lower);
134
static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
136
PR_ASSERT(fd != NULL);
137
PR_ASSERT(fd->lower != NULL);
139
return (fd->lower->methods->fsync)(fd->lower);
142
static PRInt32 PR_CALLBACK pl_DefSeek (
143
PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
145
PR_ASSERT(fd != NULL);
146
PR_ASSERT(fd->lower != NULL);
148
return (fd->lower->methods->seek)(fd->lower, offset, how);
151
static PRInt64 PR_CALLBACK pl_DefSeek64 (
152
PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
154
PR_ASSERT(fd != NULL);
155
PR_ASSERT(fd->lower != NULL);
157
return (fd->lower->methods->seek64)(fd->lower, offset, how);
160
static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
162
PR_ASSERT(fd != NULL);
163
PR_ASSERT(fd->lower != NULL);
165
return (fd->lower->methods->fileInfo)(fd->lower, info);
168
static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
170
PR_ASSERT(fd != NULL);
171
PR_ASSERT(fd->lower != NULL);
173
return (fd->lower->methods->fileInfo64)(fd->lower, info);
176
static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov,
177
PRInt32 size, PRIntervalTime timeout)
179
PR_ASSERT(fd != NULL);
180
PR_ASSERT(fd->lower != NULL);
182
return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
185
static PRStatus PR_CALLBACK pl_DefConnect (
186
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
188
PR_ASSERT(fd != NULL);
189
PR_ASSERT(fd->lower != NULL);
191
return (fd->lower->methods->connect)(fd->lower, addr, timeout);
194
static PRStatus PR_CALLBACK pl_DefConnectcontinue (
195
PRFileDesc *fd, PRInt16 out_flags)
197
PR_ASSERT(fd != NULL);
198
PR_ASSERT(fd->lower != NULL);
200
return (fd->lower->methods->connectcontinue)(fd->lower, out_flags);
203
static PRFileDesc* PR_CALLBACK pl_TopAccept (
204
PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
207
PRFileDesc *newfd, *layer = fd;
208
PRFileDesc *newstack;
209
PRBool newstyle_stack = PR_FALSE;
211
PR_ASSERT(fd != NULL);
212
PR_ASSERT(fd->lower != NULL);
214
/* test for new style stack */
215
while (NULL != layer->higher)
216
layer = layer->higher;
217
newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
218
newstack = PR_NEW(PRFileDesc);
219
if (NULL == newstack)
221
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
224
*newstack = *fd; /* make a copy of the accepting layer */
226
newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
233
if (newstyle_stack) {
234
newstack->lower = newfd;
235
newfd->higher = newstack;
238
/* this PR_PushIOLayer call cannot fail */
239
rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
240
PR_ASSERT(PR_SUCCESS == rv);
241
return newfd; /* that's it */
245
static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
247
PR_ASSERT(fd != NULL);
248
PR_ASSERT(fd->lower != NULL);
250
return (fd->lower->methods->bind)(fd->lower, addr);
253
static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
255
PR_ASSERT(fd != NULL);
256
PR_ASSERT(fd->lower != NULL);
258
return (fd->lower->methods->listen)(fd->lower, backlog);
261
static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
263
PR_ASSERT(fd != NULL);
264
PR_ASSERT(fd->lower != NULL);
266
return (fd->lower->methods->shutdown)(fd->lower, how);
269
static PRInt32 PR_CALLBACK pl_DefRecv (
270
PRFileDesc *fd, void *buf, PRInt32 amount,
271
PRIntn flags, PRIntervalTime timeout)
273
PR_ASSERT(fd != NULL);
274
PR_ASSERT(fd->lower != NULL);
276
return (fd->lower->methods->recv)(
277
fd->lower, buf, amount, flags, timeout);
280
static PRInt32 PR_CALLBACK pl_DefSend (
281
PRFileDesc *fd, const void *buf,
282
PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
284
PR_ASSERT(fd != NULL);
285
PR_ASSERT(fd->lower != NULL);
287
return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
290
static PRInt32 PR_CALLBACK pl_DefRecvfrom (
291
PRFileDesc *fd, void *buf, PRInt32 amount,
292
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
294
PR_ASSERT(fd != NULL);
295
PR_ASSERT(fd->lower != NULL);
297
return (fd->lower->methods->recvfrom)(
298
fd->lower, buf, amount, flags, addr, timeout);
301
static PRInt32 PR_CALLBACK pl_DefSendto (
302
PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
303
const PRNetAddr *addr, PRIntervalTime timeout)
305
PR_ASSERT(fd != NULL);
306
PR_ASSERT(fd->lower != NULL);
308
return (fd->lower->methods->sendto)(
309
fd->lower, buf, amount, flags, addr, timeout);
312
static PRInt16 PR_CALLBACK pl_DefPoll (
313
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
315
PR_ASSERT(fd != NULL);
316
PR_ASSERT(fd->lower != NULL);
318
return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
321
static PRInt32 PR_CALLBACK pl_DefAcceptread (
322
PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
323
PRInt32 amount, PRIntervalTime t)
327
PRFileDesc *newstack;
328
PRFileDesc *layer = sd;
329
PRBool newstyle_stack = PR_FALSE;
331
PR_ASSERT(sd != NULL);
332
PR_ASSERT(sd->lower != NULL);
334
/* test for new style stack */
335
while (NULL != layer->higher)
336
layer = layer->higher;
337
newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE;
338
newstack = PR_NEW(PRFileDesc);
339
if (NULL == newstack)
341
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
344
*newstack = *sd; /* make a copy of the accepting layer */
346
nbytes = sd->lower->methods->acceptread(
347
sd->lower, nd, raddr, buf, amount, t);
353
if (newstyle_stack) {
354
newstack->lower = *nd;
355
(*nd)->higher = newstack;
359
/* this PR_PushIOLayer call cannot fail */
360
rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
361
PR_ASSERT(PR_SUCCESS == rv);
366
static PRInt32 PR_CALLBACK pl_DefTransmitfile (
367
PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
368
PRTransmitFileFlags flags, PRIntervalTime t)
370
PR_ASSERT(sd != NULL);
371
PR_ASSERT(sd->lower != NULL);
373
return sd->lower->methods->transmitfile(
374
sd->lower, fd, headers, hlen, flags, t);
377
static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
379
PR_ASSERT(fd != NULL);
380
PR_ASSERT(fd->lower != NULL);
382
return (fd->lower->methods->getsockname)(fd->lower, addr);
385
static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
387
PR_ASSERT(fd != NULL);
388
PR_ASSERT(fd->lower != NULL);
390
return (fd->lower->methods->getpeername)(fd->lower, addr);
393
static PRStatus PR_CALLBACK pl_DefGetsocketoption (
394
PRFileDesc *fd, PRSocketOptionData *data)
396
PR_ASSERT(fd != NULL);
397
PR_ASSERT(fd->lower != NULL);
399
return (fd->lower->methods->getsocketoption)(fd->lower, data);
402
static PRStatus PR_CALLBACK pl_DefSetsocketoption (
403
PRFileDesc *fd, const PRSocketOptionData *data)
405
PR_ASSERT(fd != NULL);
406
PR_ASSERT(fd->lower != NULL);
408
return (fd->lower->methods->setsocketoption)(fd->lower, data);
411
static PRInt32 PR_CALLBACK pl_DefSendfile (
412
PRFileDesc *sd, PRSendFileData *sfd,
413
PRTransmitFileFlags flags, PRIntervalTime timeout)
415
PR_ASSERT(sd != NULL);
416
PR_ASSERT(sd->lower != NULL);
418
return sd->lower->methods->sendfile(
419
sd->lower, sfd, flags, timeout);
422
/* Methods for the top of the stack. Just call down to the next fd. */
423
static PRIOMethods pl_methods = {
450
(PRReservedFN)_PR_InvalidInt,
451
(PRReservedFN)_PR_InvalidInt,
452
pl_DefGetsocketoption,
453
pl_DefSetsocketoption,
455
pl_DefConnectcontinue,
456
(PRReservedFN)_PR_InvalidInt,
457
(PRReservedFN)_PR_InvalidInt,
458
(PRReservedFN)_PR_InvalidInt,
459
(PRReservedFN)_PR_InvalidInt
462
PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void)
465
} /* PR_GetDefaultIOMethods */
467
PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
468
PRDescIdentity ident, const PRIOMethods *methods)
470
PRFileDesc *fd = NULL;
471
PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
472
if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
473
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
476
fd = PR_NEWZAP(PRFileDesc);
478
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
481
fd->methods = methods;
482
fd->dtor = pl_FDDestructor;
483
fd->identity = ident;
487
} /* PR_CreateIOLayerStub */
491
* Create a new style stack, where the stack top is a dummy header.
492
* Unlike the old style stacks, the contents of the stack head
493
* are not modified when a layer is pushed onto or popped from a new
497
PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top)
499
PRFileDesc *fd = NULL;
501
fd = PR_NEWZAP(PRFileDesc);
503
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
506
fd->methods = &pl_methods;
507
fd->dtor = pl_FDDestructor;
508
fd->identity = PR_IO_LAYER_HEAD;
515
} /* PR_CreateIOLayer */
519
* Delete the stack head of a new style stack.
522
static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack)
530
} /* _PR_DestroyIOLayer */
532
PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
533
PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
535
PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
537
PR_ASSERT(fd != NULL);
538
PR_ASSERT(stack != NULL);
539
PR_ASSERT(insert != NULL);
540
PR_ASSERT(PR_IO_LAYER_HEAD != id);
541
if ((NULL == stack) || (NULL == fd) || (NULL == insert))
543
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
549
/* going on top of the stack */
550
/* old-style stack */
551
PRFileDesc copy = *stack;
556
stack->higher = NULL;
559
* going somewhere in the middle of the stack for both old and new
560
* style stacks, or going on top of stack for new style stack
563
fd->higher = insert->higher;
565
insert->higher->lower = fd;
572
PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
574
PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
577
PR_ASSERT(NULL != stack);
578
PR_ASSERT(NULL != extract);
579
if ((NULL == stack) || (0 == id) || (NULL == extract))
581
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
585
if (extract == stack) {
586
/* popping top layer of the stack */
587
/* old style stack */
588
PRFileDesc copy = *stack;
589
extract = stack->lower;
592
stack->higher = NULL;
593
} else if ((PR_IO_LAYER_HEAD == stack->identity) &&
594
(extract == stack->lower) && (extract->lower == NULL)) {
597
* popping the only layer in the stack; delete the stack too
600
_PR_DestroyIOLayer(stack);
602
/* for both kinds of stacks */
603
extract->lower->higher = extract->higher;
604
extract->higher->lower = extract->lower;
606
extract->higher = extract->lower = NULL;
608
} /* PR_PopIOLayer */
610
#define ID_CACHE_INCREMENT 16
611
typedef struct _PRIdentity_cache
616
PRDescIdentity ident;
619
static _PRIdentity_cache identity_cache;
621
PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
623
PRDescIdentity identity, length;
624
char **names = NULL, *name = NULL, **old = NULL;
626
if (!_pr_initialized) _PR_ImplicitInitialization();
628
PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
630
if (NULL != layer_name)
632
name = (char*)PR_Malloc(strlen(layer_name) + 1);
635
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
636
return PR_INVALID_IO_LAYER;
638
strcpy(name, layer_name);
641
/* this initial code runs unsafe */
643
PR_ASSERT(NULL == names);
644
length = identity_cache.length;
645
if (length < (identity_cache.ident + 1))
647
length += ID_CACHE_INCREMENT;
648
names = (char**)PR_CALLOC(length * sizeof(char*));
651
if (NULL != name) PR_DELETE(name);
652
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
653
return PR_INVALID_IO_LAYER;
657
/* now we get serious about thread safety */
658
PR_Lock(identity_cache.ml);
659
PR_ASSERT(identity_cache.ident <= identity_cache.length);
660
identity = identity_cache.ident + 1;
661
if (identity > identity_cache.length) /* there's no room */
663
/* we have to do something - hopefully it's already done */
664
if ((NULL != names) && (length >= identity))
666
/* what we did is still okay */
668
names, identity_cache.name,
669
identity_cache.length * sizeof(char*));
670
old = identity_cache.name;
671
identity_cache.name = names;
672
identity_cache.length = length;
677
PR_ASSERT(identity_cache.ident <= identity_cache.length);
678
PR_Unlock(identity_cache.ml);
679
if (NULL != names) PR_DELETE(names);
683
if (NULL != name) /* there's a name to be stored */
685
identity_cache.name[identity] = name;
687
identity_cache.ident = identity;
688
PR_ASSERT(identity_cache.ident <= identity_cache.length);
689
PR_Unlock(identity_cache.ml);
691
if (NULL != old) PR_DELETE(old);
692
if (NULL != names) PR_DELETE(names);
695
} /* PR_GetUniqueIdentity */
697
PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
699
if (!_pr_initialized) _PR_ImplicitInitialization();
701
if (PR_TOP_IO_LAYER == ident) return NULL;
703
PR_ASSERT(ident <= identity_cache.ident);
704
return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
705
} /* PR_GetNameForIdentity */
707
PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
709
PR_ASSERT(NULL != fd);
710
if (PR_IO_LAYER_HEAD == fd->identity) {
711
PR_ASSERT(NULL != fd->lower);
712
return fd->lower->identity;
715
} /* PR_GetLayersIdentity */
717
PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
719
PRFileDesc *layer = fd;
721
if (PR_TOP_IO_LAYER == id) {
722
if (PR_IO_LAYER_HEAD == fd->identity)
728
for (layer = fd; layer != NULL; layer = layer->lower)
730
if (id == layer->identity) return layer;
732
for (layer = fd; layer != NULL; layer = layer->higher)
734
if (id == layer->identity) return layer;
737
} /* PR_GetIdentitiesLayer */
739
void _PR_InitLayerCache(void)
741
memset(&identity_cache, 0, sizeof(identity_cache));
742
identity_cache.ml = PR_NewLock();
743
PR_ASSERT(NULL != identity_cache.ml);
744
} /* _PR_InitLayerCache */
746
void _PR_CleanupLayerCache(void)
748
if (identity_cache.ml)
750
PR_DestroyLock(identity_cache.ml);
751
identity_cache.ml = NULL;
754
if (identity_cache.name)
756
PRDescIdentity ident;
758
for (ident = 0; ident <= identity_cache.ident; ident++)
759
PR_DELETE(identity_cache.name[ident]);
761
PR_DELETE(identity_cache.name);
763
} /* _PR_CleanupLayerCache */