~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/io/prlayer.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

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