/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 */ |