Coverage Report

Created: 2025-07-01 06:25

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