OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * pkix_pl_socket.c | |
6 * | |
7 * Socket Function Definitions | |
8 * | |
9 */ | |
10 | |
11 /* | |
12 * If Socket Tracing is active, messages sent and received will be | |
13 * timestamped and dumped (to stdout) in standard hex-dump format. E.g., | |
14 * | |
15 * 1116612359156140: | |
16 * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!. | |
17 * | |
18 * The timestamp is not formatted to be meaningful except as an increasing | |
19 * value of seconds.microseconds, which is good enough to correlate two | |
20 * sides of a message exchange and to figure durations. | |
21 * | |
22 * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE | |
23 * is defined, but that doesn't mean socket tracing is active. Tracing also | |
24 * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is | |
25 * the default value, but it can be overridden by using the debugger to | |
26 * change its value -- allowing tracing to be turned on and off at various | |
27 * breakpoints -- or by setting the environment variable SOCKETTRACE. A | |
28 * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other | |
29 * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment | |
30 * value is checked during system initialization. | |
31 */ | |
32 #ifndef BUILD_OPT | |
33 #define PKIX_SOCKETTRACE 1 | |
34 #endif | |
35 | |
36 #ifdef PKIX_SOCKETDEBUG | |
37 #define PKIX_SOCKETTRACE 1 | |
38 #endif | |
39 | |
40 #include "pkix_pl_socket.h" | |
41 | |
42 /* --Private-Socket-Functions---------------------------------- */ | |
43 | |
44 #ifdef PKIX_SOCKETTRACE | |
45 static PKIX_Boolean socketTraceFlag = PKIX_FALSE; | |
46 | |
47 /* | |
48 * FUNCTION: pkix_pl_socket_timestamp | |
49 * DESCRIPTION: | |
50 * | |
51 * This functions prints to stdout the time of day, as obtained from the | |
52 * system function gettimeofday, as seconds.microseconds. Its resolution | |
53 * is whatever the system call provides. | |
54 * | |
55 * PARAMETERS: | |
56 * none | |
57 * THREAD SAFETY: | |
58 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
59 * RETURNS: | |
60 * none | |
61 */ | |
62 static void pkix_pl_socket_timestamp() { | |
63 PRInt64 prTime; | |
64 prTime = PR_Now(); | |
65 /* We shouldn't use PR_ALTERNATE_INT64_TYPEDEF, but nor can we use PRId64 */ | |
66 #if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) | |
67 printf("%ld:\n", prTime); | |
68 #else | |
69 printf("%lld:\n", prTime); | |
70 #endif | |
71 } | |
72 | |
73 /* | |
74 * FUNCTION: pkix_pl_socket_hexDigit | |
75 * DESCRIPTION: | |
76 * | |
77 * This functions prints to stdout the byte "byteVal" as two hex digits. | |
78 * | |
79 * PARAMETERS: | |
80 * "byteVal" | |
81 * The value to be printed. | |
82 * THREAD SAFETY: | |
83 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
84 * RETURNS: | |
85 * none | |
86 */ | |
87 static void pkix_pl_socket_hexDigit(char byteVal) { | |
88 int n = 0; | |
89 char cHi = '\0'; | |
90 char cLow = '\0'; | |
91 n = ((byteVal >> 4) & 0xf); | |
92 if (n > 9) { | |
93 cHi = (char) ((n - 10) + 'A'); | |
94 } else { | |
95 cHi = (char) (n + '0'); | |
96 } | |
97 n = byteVal & 0xf; | |
98 if (n > 9) { | |
99 cLow = (char) ((n - 10) + 'A'); | |
100 } else { | |
101 cLow = (char) (n + '0'); | |
102 } | |
103 (void) printf("%c%c", cHi, cLow); | |
104 } | |
105 | |
106 /* | |
107 * FUNCTION: pkix_pl_socket_linePrefix | |
108 * DESCRIPTION: | |
109 * | |
110 * This functions prints to stdout the address provided by "addr" as four | |
111 * hexadecimal digits followed by a colon and a space. | |
112 * | |
113 * PARAMETERS: | |
114 * "addr" | |
115 * The address to be printed | |
116 * none | |
117 * THREAD SAFETY: | |
118 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
119 * RETURNS: | |
120 * none | |
121 */ | |
122 static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) { | |
123 pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff)); | |
124 pkix_pl_socket_hexDigit((char)(addr & 0xff)); | |
125 (void) printf(": "); | |
126 } | |
127 | |
128 /* | |
129 * FUNCTION: pkix_pl_socket_traceLine | |
130 * DESCRIPTION: | |
131 * | |
132 * This functions prints to stdout the sixteen bytes beginning at the | |
133 * address pointed to by "ptr". The bytes are printed as sixteen pairs | |
134 * of hexadecimal characters followed by an ascii interpretation, in which | |
135 * characters from 0x20 to 0x7d are shown as their ascii equivalents, and | |
136 * other values are represented as periods. | |
137 * | |
138 * PARAMETERS: | |
139 * "ptr" | |
140 * The address of the first of the bytes to be printed | |
141 * THREAD SAFETY: | |
142 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
143 * RETURNS: | |
144 * none | |
145 */ | |
146 static void pkix_pl_socket_traceLine(char *ptr) { | |
147 PKIX_UInt32 i = 0; | |
148 pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL)); | |
149 for (i = 0; i < 16; i++) { | |
150 printf(" "); | |
151 pkix_pl_socket_hexDigit(ptr[i]); | |
152 if (i == 7) { | |
153 printf(" "); | |
154 } | |
155 } | |
156 printf(" "); | |
157 for (i = 0; i < 16; i++) { | |
158 if ((ptr[i] < ' ') || (ptr[i] > '}')) { | |
159 printf("."); | |
160 } else { | |
161 printf("%c", ptr[i]); | |
162 } | |
163 } | |
164 printf("\n"); | |
165 } | |
166 | |
167 /* | |
168 * FUNCTION: pkix_pl_socket_tracePartialLine | |
169 * DESCRIPTION: | |
170 * | |
171 * This functions prints to stdout the number of bytes given by "nBytes", | |
172 * beginning at the address pointed to by "ptr". The bytes are printed as | |
173 * pairs of hexadecimal characters followed by an ascii interpretation, in | |
174 * which characters from 0x20 to 0x7d are shown as their ascii equivalents, | |
175 * and other values are represented as periods. | |
176 * | |
177 * PARAMETERS: | |
178 * "ptr" | |
179 * The address of the first of the bytes to be printed | |
180 * "nBytes" | |
181 * The Int32 value giving the number of bytes to be printed. If "nBytes" | |
182 * is greater than sixteen, the results will be unattractive. | |
183 * none | |
184 * THREAD SAFETY: | |
185 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
186 * RETURNS: | |
187 * none | |
188 */ | |
189 static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) { | |
190 PKIX_UInt32 i = 0; | |
191 if (nBytes > 0) { | |
192 pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NU
LL)); | |
193 } | |
194 for (i = 0; i < nBytes; i++) { | |
195 printf(" "); | |
196 pkix_pl_socket_hexDigit(ptr[i]); | |
197 if (i == 7) { | |
198 printf(" "); | |
199 } | |
200 } | |
201 for (i = nBytes; i < 16; i++) { | |
202 printf(" "); | |
203 if (i == 7) { | |
204 printf(" "); | |
205 } | |
206 } | |
207 printf(" "); | |
208 for (i = 0; i < nBytes; i++) { | |
209 if ((ptr[i] < ' ') || (ptr[i] > '}')) { | |
210 printf("."); | |
211 } else { | |
212 printf("%c", ptr[i]); | |
213 } | |
214 } | |
215 printf("\n"); | |
216 } | |
217 | |
218 /* | |
219 * FUNCTION: pkix_pl_socket_tracebuff | |
220 * DESCRIPTION: | |
221 * | |
222 * This functions prints to stdout the number of bytes given by "nBytes", | |
223 * beginning with the byte pointed to by "buf". The output is preceded by | |
224 * a timestamp, and each group of sixteen (and a remainder, if any) is | |
225 * preceded by its address. The contents are shown in hexadecimal and as | |
226 * ascii characters. If "nBytes" is zero, the timestamp and starting | |
227 * address are displayed. | |
228 * | |
229 * PARAMETERS: | |
230 * "buf" | |
231 * The starting address of the bytes to be printed | |
232 * "nBytes" | |
233 * The number of bytes to be printed | |
234 * THREAD SAFETY: | |
235 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
236 * RETURNS: | |
237 * none | |
238 */ | |
239 void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) { | |
240 PKIX_UInt32 bytesRemaining = nBytes; | |
241 PKIX_UInt32 offset = 0; | |
242 char *bufptr = (char *)buf; | |
243 | |
244 if (socketTraceFlag == PKIX_FALSE) return; | |
245 | |
246 pkix_pl_socket_timestamp(); | |
247 /* | |
248 * Special case: if called with length of zero, just do address | |
249 */ | |
250 if (nBytes == 0) { | |
251 pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)buf - (char *)NU
LL)); | |
252 printf("\n"); | |
253 } else { | |
254 while (bytesRemaining >= 16) { | |
255 pkix_pl_socket_traceLine(&bufptr[offset]); | |
256 bytesRemaining -= 16; | |
257 offset += 16; | |
258 } | |
259 pkix_pl_socket_tracePartialLine | |
260 (&bufptr[offset], bytesRemaining); | |
261 } | |
262 } | |
263 | |
264 #endif | |
265 | |
266 /* | |
267 * FUNCTION: pkix_pl_Socket_SetNonBlocking | |
268 * DESCRIPTION: | |
269 * | |
270 * This functions sets the socket represented by the PRFileDesc "fileDesc" | |
271 * to nonblocking mode. | |
272 * | |
273 * PARAMETERS: | |
274 * "fileDesc" | |
275 * The address of the PRFileDesc whose I/O mode is to be set | |
276 * non-blocking. Must be non-NULL. | |
277 * "plContext" | |
278 * Platform-specific context pointer | |
279 * THREAD SAFETY: | |
280 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
281 * RETURNS: | |
282 * none | |
283 */ | |
284 static PKIX_Error * | |
285 pkix_pl_Socket_SetNonBlocking( | |
286 PRFileDesc *fileDesc, | |
287 void *plContext) | |
288 { | |
289 PRStatus rv = PR_FAILURE; | |
290 PRSocketOptionData sockOptionData; | |
291 | |
292 PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking"); | |
293 PKIX_NULLCHECK_ONE(fileDesc); | |
294 | |
295 sockOptionData.option = PR_SockOpt_Nonblocking; | |
296 sockOptionData.value.non_blocking = PR_TRUE; | |
297 | |
298 PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption, | |
299 (fileDesc, &sockOptionData)); | |
300 | |
301 if (rv != PR_SUCCESS) { | |
302 PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING); | |
303 } | |
304 cleanup: | |
305 | |
306 PKIX_RETURN(SOCKET); | |
307 } | |
308 | |
309 /* | |
310 * FUNCTION: pkix_pl_Socket_CreateClient | |
311 * DESCRIPTION: | |
312 * | |
313 * This functions creates a client socket for the PKIX_PL_Socket pointed to | |
314 * by "socket". If "socket" was created with a timeout value of zero, the | |
315 * client socket is set to use nonblocking I/O. | |
316 * | |
317 * PARAMETERS: | |
318 * "socket" | |
319 * The address of the Socket for which a client socket is to be | |
320 * created. Must be non-NULL. | |
321 * "plContext" | |
322 * Platform-specific context pointer | |
323 * THREAD SAFETY: | |
324 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
325 * RETURNS: | |
326 * none | |
327 */ | |
328 | |
329 static PKIX_Error * | |
330 pkix_pl_Socket_CreateClient( | |
331 PKIX_PL_Socket *socket, | |
332 void *plContext) | |
333 { | |
334 #ifdef PKIX_SOCKETDEBUG | |
335 PRErrorCode errorcode = 0; | |
336 #endif | |
337 PRFileDesc *mySock = NULL; | |
338 | |
339 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient"); | |
340 PKIX_NULLCHECK_ONE(socket); | |
341 | |
342 PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ()); | |
343 if (!mySock) { | |
344 #ifdef PKIX_SOCKETDEBUG | |
345 errorcode = PR_GetError(); | |
346 printf | |
347 ("pkix_pl_Socket_CreateClient: %s\n", | |
348 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
349 #endif | |
350 PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); | |
351 } | |
352 | |
353 #ifdef PKIX_SOCKETDEBUG | |
354 printf("Created socket, PRFileDesc @ %#X\n", mySock); | |
355 #endif | |
356 | |
357 socket->clientSock = mySock; | |
358 socket->status = SOCKET_UNCONNECTED; | |
359 if (socket->timeout == 0) { | |
360 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext), | |
361 PKIX_SOCKETSETNONBLOCKINGFAILED); | |
362 } | |
363 | |
364 cleanup: | |
365 | |
366 PKIX_RETURN(SOCKET); | |
367 } | |
368 | |
369 /* | |
370 * FUNCTION: pkix_pl_Socket_CreateServer | |
371 * DESCRIPTION: | |
372 * | |
373 * This functions creates a server socket for the PKIX_PL_Socket pointed to | |
374 * by "socket". If "socket" was created with a timeout value of zero, the | |
375 * server socket is set to use nonblocking I/O. | |
376 * | |
377 * Warning: there seems to be a problem with operating a server socket in | |
378 * non-blocking mode. If the server calls Recv prior to a corresponding | |
379 * Send, the message may be lost. | |
380 * | |
381 * PARAMETERS: | |
382 * "socket" | |
383 * The address of the Socket for which a server socket is to be | |
384 * created. Must be non-NULL. | |
385 * "plContext" | |
386 * Platform-specific context pointer | |
387 * THREAD SAFETY: | |
388 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
389 * RETURNS: | |
390 * none | |
391 */ | |
392 static PKIX_Error * | |
393 pkix_pl_Socket_CreateServer( | |
394 PKIX_PL_Socket *socket, | |
395 void *plContext) | |
396 { | |
397 /* #ifdef PKIX_SOCKETDEBUG */ | |
398 PRErrorCode errorcode = 0; | |
399 /* #endif */ | |
400 PRStatus rv = PR_FAILURE; | |
401 PRFileDesc *serverSock = NULL; | |
402 PRSocketOptionData sockOptionData; | |
403 | |
404 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer"); | |
405 PKIX_NULLCHECK_ONE(socket); | |
406 | |
407 PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ()); | |
408 if (!serverSock) { | |
409 #ifdef PKIX_SOCKETDEBUG | |
410 errorcode = PR_GetError(); | |
411 printf | |
412 ("pkix_pl_Socket_CreateServer: %s\n", | |
413 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
414 #endif | |
415 PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); | |
416 } | |
417 | |
418 socket->serverSock = serverSock; | |
419 | |
420 #ifdef PKIX_SOCKETDEBUG | |
421 printf("Created socket, PRFileDesc @ %#X\n", serverSock); | |
422 #endif | |
423 | |
424 if (socket->timeout == 0) { | |
425 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext), | |
426 PKIX_SOCKETSETNONBLOCKINGFAILED); | |
427 } | |
428 | |
429 sockOptionData.option = PR_SockOpt_Reuseaddr; | |
430 sockOptionData.value.reuse_addr = PR_TRUE; | |
431 | |
432 PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption, | |
433 (serverSock, &sockOptionData)); | |
434 | |
435 if (rv != PR_SUCCESS) { | |
436 PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING); | |
437 } | |
438 | |
439 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr)); | |
440 | |
441 if (rv == PR_FAILURE) { | |
442 /* #ifdef PKIX_SOCKETDEBUG */ | |
443 errorcode = PR_GetError(); | |
444 printf | |
445 ("pkix_pl_Socket_CreateServer: %s\n", | |
446 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
447 /* #endif */ | |
448 PKIX_ERROR(PKIX_PRBINDFAILED); | |
449 } | |
450 | |
451 #ifdef PKIX_SOCKETDEBUG | |
452 printf("Successful bind!\n"); | |
453 #endif | |
454 | |
455 socket->status = SOCKET_BOUND; | |
456 | |
457 cleanup: | |
458 | |
459 PKIX_RETURN(SOCKET); | |
460 } | |
461 | |
462 /* | |
463 * FUNCTION: pkix_pl_Socket_Connect | |
464 * DESCRIPTION: | |
465 * | |
466 * This functions performs the connect function for the client socket | |
467 * specified in "socket", storing the status at "pStatus". | |
468 * | |
469 * PARAMETERS: | |
470 * "socket" | |
471 * The address of the Socket for which a connect is to be performed. | |
472 * Must be non-NULL. | |
473 * "pStatus" | |
474 * The address at which the connection status is stored. Must be non-NULL. | |
475 * "plContext" | |
476 * Platform-specific context pointer | |
477 * THREAD SAFETY: | |
478 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
479 * RETURNS: | |
480 * none | |
481 */ | |
482 static PKIX_Error * | |
483 pkix_pl_Socket_Connect( | |
484 PKIX_PL_Socket *socket, | |
485 PRErrorCode *pStatus, | |
486 void *plContext) | |
487 { | |
488 PRStatus rv = PR_FAILURE; | |
489 PRErrorCode errorcode = 0; | |
490 | |
491 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect"); | |
492 PKIX_NULLCHECK_TWO(socket, socket->clientSock); | |
493 | |
494 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect, | |
495 (socket->clientSock, socket->netAddr, socket->timeout)); | |
496 | |
497 if (rv == PR_FAILURE) { | |
498 errorcode = PR_GetError(); | |
499 *pStatus = errorcode; | |
500 if (errorcode == PR_IN_PROGRESS_ERROR) { | |
501 socket->status = SOCKET_CONNECTPENDING; | |
502 goto cleanup; | |
503 } else { | |
504 #ifdef PKIX_SOCKETDEBUG | |
505 printf | |
506 ("pkix_pl_Socket_Connect: %s\n", | |
507 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
508 #endif | |
509 PKIX_ERROR(PKIX_PRCONNECTFAILED); | |
510 } | |
511 } | |
512 | |
513 #ifdef PKIX_SOCKETDEBUG | |
514 printf("Successful connect!\n"); | |
515 #endif | |
516 | |
517 *pStatus = 0; | |
518 socket->status = SOCKET_CONNECTED; | |
519 | |
520 cleanup: | |
521 | |
522 PKIX_RETURN(SOCKET); | |
523 } | |
524 | |
525 /* | |
526 * FUNCTION: pkix_pl_Socket_ConnectContinue | |
527 * DESCRIPTION: | |
528 * | |
529 * This functions continues the connect function for the client socket | |
530 * specified in "socket", storing the status at "pStatus". It is expected that | |
531 * the non-blocking connect has returned PR_IN_PROGRESS_ERROR. | |
532 * | |
533 * PARAMETERS: | |
534 * "socket" | |
535 * The address of the Socket for which a connect is to be continued. | |
536 * Must be non-NULL. | |
537 * "pStatus" | |
538 * The address at which the connection status is stored. Must be non-NULL. | |
539 * "plContext" | |
540 * Platform-specific context pointer | |
541 * THREAD SAFETY: | |
542 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
543 * RETURNS: | |
544 * none | |
545 */ | |
546 static PKIX_Error * | |
547 pkix_pl_Socket_ConnectContinue( | |
548 PKIX_PL_Socket *socket, | |
549 PRErrorCode *pStatus, | |
550 void *plContext) | |
551 { | |
552 PRStatus rv = PR_FAILURE; | |
553 PRErrorCode errorcode = 0; | |
554 PRPollDesc pollDesc; | |
555 PRInt32 numEvents = 0; | |
556 | |
557 PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue"); | |
558 PKIX_NULLCHECK_TWO(socket, socket->clientSock); | |
559 | |
560 pollDesc.fd = socket->clientSock; | |
561 pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; | |
562 pollDesc.out_flags = 0; | |
563 PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0)); | |
564 if (numEvents < 0) { | |
565 PKIX_ERROR(PKIX_PRPOLLFAILED); | |
566 } | |
567 | |
568 if (numEvents == 0) { | |
569 *pStatus = PR_IN_PROGRESS_ERROR; | |
570 goto cleanup; | |
571 } | |
572 | |
573 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue, | |
574 (socket->clientSock, pollDesc.out_flags)); | |
575 | |
576 /* | |
577 * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS | |
578 * even though the connection is not yet ready. But its deceit | |
579 * is betrayed by the contents of out_flags! | |
580 */ | |
581 if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) { | |
582 *pStatus = PR_IN_PROGRESS_ERROR; | |
583 goto cleanup; | |
584 } | |
585 | |
586 if (rv == PR_FAILURE) { | |
587 errorcode = PR_GetError(); | |
588 *pStatus = errorcode; | |
589 if (errorcode == PR_IN_PROGRESS_ERROR) { | |
590 goto cleanup; | |
591 } else { | |
592 #ifdef PKIX_SOCKETDEBUG | |
593 printf | |
594 ("pkix_pl_Socket_ConnectContinue: %s\n", | |
595 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
596 #endif | |
597 PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED); | |
598 } | |
599 } | |
600 | |
601 #ifdef PKIX_SOCKETDEBUG | |
602 printf("Successful connect!\n"); | |
603 #endif | |
604 | |
605 *pStatus = 0; | |
606 socket->status = SOCKET_CONNECTED; | |
607 | |
608 cleanup: | |
609 | |
610 PKIX_RETURN(SOCKET); | |
611 } | |
612 | |
613 /* | |
614 * FUNCTION: pkix_pl_Socket_Destroy | |
615 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) | |
616 */ | |
617 static PKIX_Error * | |
618 pkix_pl_Socket_Destroy( | |
619 PKIX_PL_Object *object, | |
620 void *plContext) | |
621 { | |
622 PKIX_PL_Socket *socket = NULL; | |
623 | |
624 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy"); | |
625 PKIX_NULLCHECK_ONE(object); | |
626 | |
627 PKIX_CHECK(pkix_CheckType | |
628 (object, PKIX_SOCKET_TYPE, plContext), | |
629 PKIX_OBJECTNOTANSOCKET); | |
630 | |
631 socket = (PKIX_PL_Socket *)object; | |
632 | |
633 if (socket->isServer) { | |
634 if (socket->serverSock) { | |
635 PR_Close(socket->serverSock); | |
636 } | |
637 } else { | |
638 if (socket->clientSock) { | |
639 PR_Close(socket->clientSock); | |
640 } | |
641 } | |
642 | |
643 cleanup: | |
644 | |
645 PKIX_RETURN(SOCKET); | |
646 } | |
647 | |
648 /* | |
649 * FUNCTION: pkix_pl_Socket_Hashcode | |
650 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) | |
651 */ | |
652 static PKIX_Error * | |
653 pkix_pl_Socket_Hashcode( | |
654 PKIX_PL_Object *object, | |
655 PKIX_UInt32 *pHashcode, | |
656 void *plContext) | |
657 { | |
658 PKIX_PL_Socket *socket = NULL; | |
659 | |
660 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode"); | |
661 PKIX_NULLCHECK_TWO(object, pHashcode); | |
662 | |
663 PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext), | |
664 PKIX_OBJECTNOTSOCKET); | |
665 | |
666 socket = (PKIX_PL_Socket *)object; | |
667 | |
668 *pHashcode = (((socket->timeout << 3) + | |
669 (socket->netAddr->inet.family << 3)) + | |
670 (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) + | |
671 socket->netAddr->inet.port; | |
672 | |
673 cleanup: | |
674 | |
675 PKIX_RETURN(SOCKET); | |
676 } | |
677 | |
678 /* | |
679 * FUNCTION: pkix_pl_Socket_Equals | |
680 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) | |
681 */ | |
682 static PKIX_Error * | |
683 pkix_pl_Socket_Equals( | |
684 PKIX_PL_Object *firstObject, | |
685 PKIX_PL_Object *secondObject, | |
686 PKIX_Int32 *pResult, | |
687 void *plContext) | |
688 { | |
689 PKIX_PL_Socket *firstSocket = NULL; | |
690 PKIX_PL_Socket *secondSocket = NULL; | |
691 | |
692 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals"); | |
693 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); | |
694 | |
695 *pResult = PKIX_FALSE; | |
696 | |
697 PKIX_CHECK(pkix_CheckTypes | |
698 (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext), | |
699 PKIX_OBJECTNOTSOCKET); | |
700 | |
701 firstSocket = (PKIX_PL_Socket *)firstObject; | |
702 secondSocket = (PKIX_PL_Socket *)secondObject; | |
703 | |
704 if (firstSocket->timeout != secondSocket->timeout) { | |
705 goto cleanup; | |
706 } | |
707 | |
708 if (firstSocket->netAddr == secondSocket->netAddr) { | |
709 *pResult = PKIX_TRUE; | |
710 goto cleanup; | |
711 } | |
712 | |
713 if ((firstSocket->netAddr->inet.family != | |
714 secondSocket->netAddr->inet.family) || | |
715 (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) != | |
716 *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) || | |
717 (firstSocket->netAddr->inet.port != | |
718 secondSocket->netAddr->inet.port)) { | |
719 | |
720 goto cleanup; | |
721 | |
722 } | |
723 | |
724 *pResult = PKIX_TRUE; | |
725 | |
726 cleanup: | |
727 | |
728 PKIX_RETURN(SOCKET); | |
729 } | |
730 | |
731 /* | |
732 * FUNCTION: pkix_pl_Socket_RegisterSelf | |
733 * | |
734 * DESCRIPTION: | |
735 * Registers PKIX_PL_SOCKET_TYPE and its related | |
736 * functions with systemClasses[] | |
737 * | |
738 * THREAD SAFETY: | |
739 * Not Thread Safe - for performance and complexity reasons | |
740 * | |
741 * Since this function is only called by PKIX_PL_Initialize, which should | |
742 * only be called once, it is acceptable that this function is not | |
743 * thread-safe. | |
744 */ | |
745 PKIX_Error * | |
746 pkix_pl_Socket_RegisterSelf(void *plContext) | |
747 { | |
748 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; | |
749 pkix_ClassTable_Entry entry; | |
750 | |
751 PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf"); | |
752 | |
753 entry.description = "Socket"; | |
754 entry.objCounter = 0; | |
755 entry.typeObjectSize = sizeof(PKIX_PL_Socket); | |
756 entry.destructor = pkix_pl_Socket_Destroy; | |
757 entry.equalsFunction = pkix_pl_Socket_Equals; | |
758 entry.hashcodeFunction = pkix_pl_Socket_Hashcode; | |
759 entry.toStringFunction = NULL; | |
760 entry.comparator = NULL; | |
761 entry.duplicateFunction = NULL; | |
762 | |
763 systemClasses[PKIX_SOCKET_TYPE] = entry; | |
764 | |
765 #ifdef PKIX_SOCKETTRACE | |
766 { | |
767 char *val = NULL; | |
768 val = PR_GetEnvSecure("SOCKETTRACE"); | |
769 /* Is SOCKETTRACE set in the environment? */ | |
770 if ((val != NULL) && (*val != '\0')) { | |
771 socketTraceFlag = | |
772 ((*val == '1')?PKIX_TRUE:PKIX_FALSE); | |
773 } | |
774 } | |
775 #endif | |
776 | |
777 PKIX_RETURN(SOCKET); | |
778 } | |
779 | |
780 /* --Public-Socket-Functions----------------------------------- */ | |
781 | |
782 /* | |
783 * FUNCTION: pkix_pl_Socket_Listen | |
784 * DESCRIPTION: | |
785 * | |
786 * This functions establishes a listening queue for the server Socket | |
787 * pointed to by "socket". | |
788 * | |
789 * PARAMETERS: | |
790 * "socket" | |
791 * The address of the server socket for which the queue is to be | |
792 * established. Must be non-NULL. | |
793 * "backlog" | |
794 * The UInt32 value of the length of the queue to be established. | |
795 * "plContext" | |
796 * Platform-specific context pointer | |
797 * THREAD SAFETY: | |
798 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
799 * RETURNS: | |
800 * none | |
801 */ | |
802 static PKIX_Error * | |
803 pkix_pl_Socket_Listen( | |
804 PKIX_PL_Socket *socket, | |
805 PKIX_UInt32 backlog, | |
806 void *plContext) | |
807 { | |
808 #ifdef PKIX_SOCKETDEBUG | |
809 PRErrorCode errorcode = 0; | |
810 #endif | |
811 PRStatus rv = PR_FAILURE; | |
812 | |
813 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen"); | |
814 PKIX_NULLCHECK_TWO(socket, socket->serverSock); | |
815 | |
816 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen, | |
817 (socket->serverSock, (PRIntn)backlog)); | |
818 | |
819 if (rv == PR_FAILURE) { | |
820 #ifdef PKIX_SOCKETDEBUG | |
821 errorcode = PR_GetError(); | |
822 printf | |
823 ("pkix_pl_Socket_Listen: %s\n", | |
824 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
825 #endif | |
826 PKIX_ERROR(PKIX_PRLISTENFAILED); | |
827 } | |
828 | |
829 #ifdef PKIX_SOCKETDEBUG | |
830 printf("Successful listen!\n"); | |
831 #endif | |
832 | |
833 socket->status = SOCKET_LISTENING; | |
834 cleanup: | |
835 | |
836 PKIX_RETURN(SOCKET); | |
837 } | |
838 | |
839 /* | |
840 * FUNCTION: pkix_pl_Socket_Shutdown | |
841 * DESCRIPTION: | |
842 * | |
843 * This functions performs the shutdown of any connections controlled by the | |
844 * socket pointed to by "socket". | |
845 * | |
846 * PARAMETERS: | |
847 * "socket" | |
848 * The address of the socket to be shut down. Must be non-NULL. | |
849 * "plContext" | |
850 * Platform-specific context pointer | |
851 * THREAD SAFETY: | |
852 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
853 * RETURNS: | |
854 * none | |
855 */ | |
856 static PKIX_Error * | |
857 pkix_pl_Socket_Shutdown( | |
858 PKIX_PL_Socket *socket, | |
859 void *plContext) | |
860 { | |
861 #ifdef PKIX_SOCKETDEBUG | |
862 PRErrorCode errorcode = 0; | |
863 #endif | |
864 PRStatus rv = PR_FAILURE; | |
865 PRFileDesc *fileDesc = NULL; | |
866 | |
867 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown"); | |
868 PKIX_NULLCHECK_ONE(socket); | |
869 | |
870 fileDesc = | |
871 (socket->isServer)?(socket->serverSock):(socket->clientSock); | |
872 | |
873 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown, | |
874 (fileDesc, PR_SHUTDOWN_BOTH)); | |
875 | |
876 if (rv == PR_FAILURE) { | |
877 #ifdef PKIX_SOCKETDEBUG | |
878 errorcode = PR_GetError(); | |
879 printf | |
880 ("pkix_pl_Socket_Shutdown: %s\n", | |
881 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
882 #endif | |
883 PKIX_ERROR(PKIX_PRSHUTDOWNFAILED); | |
884 } | |
885 socket->status = SOCKET_SHUTDOWN; | |
886 | |
887 cleanup: | |
888 | |
889 PKIX_RETURN(SOCKET); | |
890 } | |
891 | |
892 /* | |
893 * FUNCTION: pkix_pl_Socket_Send | |
894 * DESCRIPTION: | |
895 * | |
896 * This functions sends a message using the socket pointed to by "sendSock", | |
897 * from the buffer pointed to by "buf", of the number of bytes given by | |
898 * "bytesToWrite", storing the number of bytes actually written at | |
899 * "pBytesWritten". If "socket" is in non-blocking mode, the send operation | |
900 * may store -1 at "pBytesWritten" and the write is not complete until a | |
901 * corresponding pkix_pl_Poll call has indicated its completion by returning | |
902 * a non-negative value for bytes written. | |
903 * | |
904 * PARAMETERS: | |
905 * "sendSock" | |
906 * The address of the Socket on which the message is to be sent. Must | |
907 * be non-NULL. | |
908 * "buf" | |
909 * The address of the data to be sent. Must be non-NULL. | |
910 * "bytesToWrite"" | |
911 * The UInt32 value indicating the number of bytes to write. | |
912 * "pBytesWritten" | |
913 * The address at which the Int32 value indicating the number of bytes | |
914 * actually written is to be stored. Must be non-NULL. | |
915 * "plContext" | |
916 * Platform-specific context pointer | |
917 * THREAD SAFETY: | |
918 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
919 * RETURNS: | |
920 * none | |
921 */ | |
922 static PKIX_Error * | |
923 pkix_pl_Socket_Send( | |
924 PKIX_PL_Socket *sendSock, | |
925 void *buf, | |
926 PKIX_UInt32 bytesToWrite, | |
927 PKIX_Int32 *pBytesWritten, | |
928 void *plContext) | |
929 { | |
930 PRInt32 bytesWritten = 0; | |
931 PRErrorCode errorcode = 0; | |
932 PRFileDesc *fd = NULL; | |
933 | |
934 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send"); | |
935 PKIX_NULLCHECK_TWO(buf, pBytesWritten); | |
936 | |
937 fd = sendSock->clientSock; | |
938 | |
939 PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send, | |
940 (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout)); | |
941 | |
942 if (bytesWritten >= 0) { | |
943 if (sendSock->status == SOCKET_SENDRCVPENDING) { | |
944 sendSock->status = SOCKET_RCVPENDING; | |
945 } else { | |
946 sendSock->status = SOCKET_CONNECTED; | |
947 } | |
948 #ifdef PKIX_SOCKETTRACE | |
949 pkix_pl_socket_tracebuff(buf, bytesWritten); | |
950 #endif | |
951 } else { | |
952 errorcode = PR_GetError(); | |
953 if (errorcode != PR_WOULD_BLOCK_ERROR) { | |
954 #ifdef PKIX_SOCKETDEBUG | |
955 printf | |
956 ("pkix_pl_Socket_Send: %s\n", | |
957 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
958 #endif | |
959 PKIX_ERROR(PKIX_PRSENDFAILED); | |
960 } | |
961 | |
962 sendSock->writeBuf = buf; | |
963 sendSock->writeBufSize = bytesToWrite; | |
964 if (sendSock->status == SOCKET_RCVPENDING) { | |
965 sendSock->status = SOCKET_SENDRCVPENDING; | |
966 } else { | |
967 sendSock->status = SOCKET_SENDPENDING; | |
968 } | |
969 } | |
970 | |
971 *pBytesWritten = (PKIX_Int32)bytesWritten; | |
972 | |
973 cleanup: | |
974 | |
975 PKIX_RETURN(SOCKET); | |
976 } | |
977 | |
978 /* | |
979 * FUNCTION: pkix_pl_Socket_Recv | |
980 * DESCRIPTION: | |
981 * | |
982 * This functions receives a message on the socket pointed to by "rcvSock", | |
983 * into the buffer pointed to by "buf", of capacity given by "capacity", | |
984 * storing the number of bytes actually received at "pBytesRead". If "socket" | |
985 * is in non-blocking mode, the receive operation may store -1 at | |
986 * "pBytesWritten". In that case the write is not complete until a | |
987 * corresponding pkix_pl_Poll call has indicated its completion by returning | |
988 * a non-negative value for bytes read. | |
989 * | |
990 * PARAMETERS: | |
991 * "rcvSock" | |
992 * The address of the Socket on which the message is to be received. | |
993 * Must be non-NULL. | |
994 * "buf" | |
995 * The address of the buffer into which the message is to be received. | |
996 * Must be non-NULL. | |
997 * "capacity" | |
998 * The UInt32 value of the size of the buffer; that is, the maximum | |
999 * number of bytes that can be received. | |
1000 * "pBytesRead" | |
1001 * The address at which is stored the Int32 value of the number of bytes | |
1002 * actually received. | |
1003 * "plContext" | |
1004 * Platform-specific context pointer | |
1005 * THREAD SAFETY: | |
1006 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
1007 * RETURNS: | |
1008 * none | |
1009 */ | |
1010 static PKIX_Error * | |
1011 pkix_pl_Socket_Recv( | |
1012 PKIX_PL_Socket *rcvSock, | |
1013 void *buf, | |
1014 PKIX_UInt32 capacity, | |
1015 PKIX_Int32 *pBytesRead, | |
1016 void *plContext) | |
1017 { | |
1018 PRErrorCode errorcode = 0; | |
1019 PRInt32 bytesRead = 0; | |
1020 PRFileDesc *fd = NULL; | |
1021 | |
1022 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv"); | |
1023 PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead); | |
1024 | |
1025 fd = rcvSock->clientSock; | |
1026 | |
1027 PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv, | |
1028 (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout)); | |
1029 | |
1030 if (bytesRead > 0) { | |
1031 if (rcvSock->status == SOCKET_SENDRCVPENDING) { | |
1032 rcvSock->status = SOCKET_SENDPENDING; | |
1033 } else { | |
1034 rcvSock->status = SOCKET_CONNECTED; | |
1035 } | |
1036 #ifdef PKIX_SOCKETTRACE | |
1037 pkix_pl_socket_tracebuff(buf, bytesRead); | |
1038 #endif | |
1039 } else if (bytesRead == 0) { | |
1040 PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED); | |
1041 } else { | |
1042 errorcode = PR_GetError(); | |
1043 if (errorcode != PR_WOULD_BLOCK_ERROR) { | |
1044 #ifdef PKIX_SOCKETDEBUG | |
1045 printf | |
1046 ("pkix_pl_Socket_Recv: %s\n", | |
1047 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
1048 #endif | |
1049 PKIX_ERROR(PKIX_PRRECVFAILED); | |
1050 } | |
1051 rcvSock->readBuf = buf; | |
1052 rcvSock->readBufSize = capacity; | |
1053 if (rcvSock->status == SOCKET_SENDPENDING) { | |
1054 rcvSock->status = SOCKET_SENDRCVPENDING; | |
1055 } else { | |
1056 rcvSock->status = SOCKET_RCVPENDING; | |
1057 } | |
1058 | |
1059 } | |
1060 | |
1061 *pBytesRead = (PKIX_Int32)bytesRead; | |
1062 | |
1063 cleanup: | |
1064 | |
1065 PKIX_RETURN(SOCKET); | |
1066 } | |
1067 | |
1068 /* | |
1069 * FUNCTION: pkix_pl_Socket_Poll | |
1070 * DESCRIPTION: | |
1071 * | |
1072 * This functions checks for completion of an earlier Send or Recv on the | |
1073 * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes | |
1074 * written by a completed Send and in "pBytesRead" the number of bytes | |
1075 * received in a completed Recv. A value of -1 returned indicates the | |
1076 * operation has still not completed. A NULL pointer may be supplied for | |
1077 * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer | |
1078 * may be supplied for "pBytesRead" to avoid checking for completion of a Recv. | |
1079 * | |
1080 * PARAMETERS: | |
1081 * "sock" | |
1082 * The address of the socket for which completions are to be checked. | |
1083 * "pBytesWritten" | |
1084 * The address at which the number of bytes written is to be stored, if | |
1085 * a pending Send has completed. If NULL, Sends are not checked. | |
1086 * "pBytesRead" | |
1087 * The address at which the number of bytes read is to be stored, if | |
1088 * a pending Recv has completed. If NULL, Recvs are not checked. | |
1089 * "plContext" | |
1090 * Platform-specific context pointer | |
1091 * THREAD SAFETY: | |
1092 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
1093 * RETURNS: | |
1094 * none | |
1095 */ | |
1096 static PKIX_Error * | |
1097 pkix_pl_Socket_Poll( | |
1098 PKIX_PL_Socket *sock, | |
1099 PKIX_Int32 *pBytesWritten, | |
1100 PKIX_Int32 *pBytesRead, | |
1101 void *plContext) | |
1102 { | |
1103 PRPollDesc pollDesc; | |
1104 PRInt32 numEvents = 0; | |
1105 PKIX_Int32 bytesRead = 0; | |
1106 PKIX_Int32 bytesWritten = 0; | |
1107 PRErrorCode errorcode = 0; | |
1108 | |
1109 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll"); | |
1110 PKIX_NULLCHECK_ONE(sock); | |
1111 | |
1112 pollDesc.fd = sock->clientSock; | |
1113 pollDesc.in_flags = 0; | |
1114 pollDesc.out_flags = 0; | |
1115 | |
1116 if ((pBytesWritten) && | |
1117 ((sock->status == SOCKET_SENDPENDING) || | |
1118 (sock->status == SOCKET_SENDRCVPENDING))) { | |
1119 pollDesc.in_flags = PR_POLL_WRITE; | |
1120 } | |
1121 | |
1122 if ((pBytesRead) && | |
1123 ((sock->status == SOCKET_RCVPENDING) || | |
1124 (sock->status == SOCKET_SENDRCVPENDING))) { | |
1125 pollDesc.in_flags |= PR_POLL_READ; | |
1126 } | |
1127 | |
1128 PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0)); | |
1129 | |
1130 if (numEvents < 0) { | |
1131 PKIX_ERROR(PKIX_PRPOLLFAILED); | |
1132 } else if (numEvents > 0) { | |
1133 if (pollDesc.out_flags & PR_POLL_WRITE) { | |
1134 PKIX_CHECK(pkix_pl_Socket_Send | |
1135 (sock, | |
1136 sock->writeBuf, | |
1137 sock->writeBufSize, | |
1138 &bytesWritten, | |
1139 plContext), | |
1140 PKIX_SOCKETSENDFAILED); | |
1141 *pBytesWritten = (PKIX_Int32)bytesWritten; | |
1142 if (bytesWritten >= 0) { | |
1143 sock->writeBuf = NULL; | |
1144 sock->writeBufSize = 0; | |
1145 } | |
1146 } | |
1147 | |
1148 if (pollDesc.out_flags & PR_POLL_READ) { | |
1149 PKIX_CHECK(pkix_pl_Socket_Recv | |
1150 (sock, | |
1151 sock->readBuf, | |
1152 sock->readBufSize, | |
1153 &bytesRead, | |
1154 plContext), | |
1155 PKIX_SOCKETRECVFAILED); | |
1156 *pBytesRead = (PKIX_Int32)bytesRead; | |
1157 if (bytesRead >= 0) { | |
1158 sock->readBuf = NULL; | |
1159 sock->readBufSize = 0; | |
1160 } | |
1161 } | |
1162 } else if (numEvents == 0) { | |
1163 errorcode = PR_GetError(); | |
1164 if (errorcode != PR_WOULD_BLOCK_ERROR) { | |
1165 #ifdef PKIX_SOCKETDEBUG | |
1166 printf | |
1167 ("pkix_pl_Socket_Poll: %s\n", | |
1168 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
1169 #endif | |
1170 PKIX_ERROR(PKIX_PRPOLLFAILED); | |
1171 } | |
1172 if (pBytesWritten) { | |
1173 *pBytesWritten = 0; | |
1174 } | |
1175 if (pBytesRead) { | |
1176 *pBytesRead = 0; | |
1177 } | |
1178 } | |
1179 | |
1180 cleanup: | |
1181 | |
1182 PKIX_RETURN(SOCKET); | |
1183 } | |
1184 | |
1185 /* | |
1186 * FUNCTION: pkix_pl_Socket_Accept | |
1187 * DESCRIPTION: | |
1188 * | |
1189 * This functions accepts a client connection for the server Socket pointed | |
1190 * to by "serverSocket", creating a new Socket and storing the result at | |
1191 * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this | |
1192 * function will return NULL if there is no client connection to accept. | |
1193 * Otherwise this function will block until a connection is available. | |
1194 * When a client connection is available the new Socket will have the same | |
1195 * blocking/non-blocking property as "serverSocket". | |
1196 * | |
1197 * PARAMETERS: | |
1198 * "serverSocket" | |
1199 * The address of the Socket for which a client connection is to be | |
1200 * accepted. Must be non-NULL. | |
1201 * "pRendezvousSocket" | |
1202 * The address at which the created Socket is stored, when a client | |
1203 * connection is available, or at which NULL is stored, if no connection | |
1204 * is available for a non-blocking "serverSocket". Must be non-NULL. | |
1205 * "plContext" | |
1206 * Platform-specific context pointer | |
1207 * THREAD SAFETY: | |
1208 * Thread Safe (see Thread Safety definitions in Programmer's Guide) | |
1209 * RETURNS: | |
1210 * none | |
1211 */ | |
1212 static PKIX_Error * | |
1213 pkix_pl_Socket_Accept( | |
1214 PKIX_PL_Socket *serverSocket, | |
1215 PKIX_PL_Socket **pRendezvousSocket, | |
1216 void *plContext) | |
1217 { | |
1218 PRErrorCode errorcode = 0; | |
1219 PRFileDesc *rendezvousSock = NULL; | |
1220 PRNetAddr *clientAddr = NULL; | |
1221 PKIX_PL_Socket *newSocket = NULL; | |
1222 | |
1223 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept"); | |
1224 PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket); | |
1225 | |
1226 PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept, | |
1227 (serverSocket->serverSock, clientAddr, serverSocket->timeout)); | |
1228 | |
1229 if (!rendezvousSock) { | |
1230 errorcode = PR_GetError(); | |
1231 if (errorcode != PR_WOULD_BLOCK_ERROR) { | |
1232 #ifdef PKIX_SOCKETDEBUG | |
1233 printf | |
1234 ("pkix_pl_Socket_Accept: %s\n", | |
1235 PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); | |
1236 #endif | |
1237 PKIX_ERROR(PKIX_PRACCEPTFAILED); | |
1238 } | |
1239 serverSocket->status = SOCKET_ACCEPTPENDING; | |
1240 *pRendezvousSocket = NULL; | |
1241 goto cleanup; | |
1242 | |
1243 } | |
1244 | |
1245 #ifdef PKIX_SOCKETDEBUG | |
1246 printf("Successful accept!\n"); | |
1247 #endif | |
1248 | |
1249 PKIX_CHECK(PKIX_PL_Object_Alloc | |
1250 (PKIX_SOCKET_TYPE, | |
1251 sizeof (PKIX_PL_Socket), | |
1252 (PKIX_PL_Object **)&newSocket, | |
1253 plContext), | |
1254 PKIX_COULDNOTCREATESOCKETOBJECT); | |
1255 | |
1256 newSocket->isServer = PKIX_FALSE; | |
1257 newSocket->timeout = serverSocket->timeout; | |
1258 newSocket->clientSock = rendezvousSock; | |
1259 newSocket->serverSock = NULL; | |
1260 newSocket->netAddr = NULL; | |
1261 newSocket->status = SOCKET_CONNECTED; | |
1262 newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
1263 newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
1264 newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
1265 newSocket->callbackList.connectcontinueCallback = | |
1266 pkix_pl_Socket_ConnectContinue; | |
1267 newSocket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
1268 newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
1269 newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
1270 | |
1271 if (serverSocket->timeout == 0) { | |
1272 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking | |
1273 (rendezvousSock, plContext), | |
1274 PKIX_SOCKETSETNONBLOCKINGFAILED); | |
1275 } | |
1276 | |
1277 *pRendezvousSocket = newSocket; | |
1278 | |
1279 cleanup: | |
1280 | |
1281 PKIX_RETURN(SOCKET); | |
1282 } | |
1283 | |
1284 /* | |
1285 * FUNCTION: pkix_pl_Socket_Create | |
1286 * DESCRIPTION: | |
1287 * | |
1288 * This function creates a new Socket, setting it to be a server or a client | |
1289 * according to the value of "isServer", setting its timeout value from | |
1290 * "timeout" and server address from "netAddr", and stores the created Socket | |
1291 * at "pSocket". | |
1292 * | |
1293 * PARAMETERS: | |
1294 * "isServer" | |
1295 * The Boolean value indicating if PKIX_TRUE, that a server socket (using | |
1296 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a | |
1297 * client socket (using Connect) is to be created. | |
1298 * "timeout" | |
1299 * A PRTimeInterval value to be used for I/O waits for this socket. If | |
1300 * zero, non-blocking I/O is to be used. | |
1301 * "netAddr" | |
1302 * The PRNetAddr to be used for the Bind function, if this is a server | |
1303 * socket, or for the Connect, if this is a client socket. | |
1304 * "pSocket" | |
1305 * The address at which the Socket is to be stored. Must be non-NULL. | |
1306 * "plContext" | |
1307 * Platform-specific context pointer. | |
1308 * THREAD SAFETY: | |
1309 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
1310 * RETURNS: | |
1311 * Returns NULL if the function succeeds. | |
1312 * Returns a Socket Error if the function fails in | |
1313 * a non-fatal way. | |
1314 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
1315 */ | |
1316 PKIX_Error * | |
1317 pkix_pl_Socket_Create( | |
1318 PKIX_Boolean isServer, | |
1319 PRIntervalTime timeout, | |
1320 PRNetAddr *netAddr, | |
1321 PRErrorCode *status, | |
1322 PKIX_PL_Socket **pSocket, | |
1323 void *plContext) | |
1324 { | |
1325 PKIX_PL_Socket *socket = NULL; | |
1326 | |
1327 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create"); | |
1328 PKIX_NULLCHECK_ONE(pSocket); | |
1329 | |
1330 PKIX_CHECK(PKIX_PL_Object_Alloc | |
1331 (PKIX_SOCKET_TYPE, | |
1332 sizeof (PKIX_PL_Socket), | |
1333 (PKIX_PL_Object **)&socket, | |
1334 plContext), | |
1335 PKIX_COULDNOTCREATESOCKETOBJECT); | |
1336 | |
1337 socket->isServer = isServer; | |
1338 socket->timeout = timeout; | |
1339 socket->clientSock = NULL; | |
1340 socket->serverSock = NULL; | |
1341 socket->netAddr = netAddr; | |
1342 | |
1343 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
1344 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
1345 socket->callbackList.connectcontinueCallback = | |
1346 pkix_pl_Socket_ConnectContinue; | |
1347 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
1348 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
1349 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
1350 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
1351 | |
1352 if (isServer) { | |
1353 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
1354 PKIX_SOCKETCREATESERVERFAILED); | |
1355 *status = 0; | |
1356 } else { | |
1357 socket->timeout = timeout; | |
1358 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
1359 PKIX_SOCKETCREATECLIENTFAILED); | |
1360 PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext), | |
1361 PKIX_SOCKETCONNECTFAILED); | |
1362 } | |
1363 | |
1364 *pSocket = socket; | |
1365 | |
1366 cleanup: | |
1367 if (PKIX_ERROR_RECEIVED) { | |
1368 PKIX_DECREF(socket); | |
1369 } | |
1370 | |
1371 PKIX_RETURN(SOCKET); | |
1372 } | |
1373 | |
1374 /* | |
1375 * FUNCTION: pkix_pl_Socket_CreateByName | |
1376 * DESCRIPTION: | |
1377 * | |
1378 * This function creates a new Socket, setting it to be a server or a client | |
1379 * according to the value of "isServer", setting its timeout value from | |
1380 * "timeout" and server address and port number from "serverName", and stores | |
1381 * the status at "pStatus" and the created Socket at "pSocket". | |
1382 * | |
1383 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip | |
1384 * address of PR_INADDR_ANY. | |
1385 * | |
1386 * PARAMETERS: | |
1387 * "isServer" | |
1388 * The Boolean value indicating if PKIX_TRUE, that a server socket (using | |
1389 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a | |
1390 * client socket (using Connect) is to be created. | |
1391 * "timeout" | |
1392 * A PRTimeInterval value to be used for I/O waits for this socket. If | |
1393 * zero, non-blocking I/O is to be used. | |
1394 * "serverName" | |
1395 * Address of a character string consisting of the server's domain name | |
1396 * followed by a colon and a port number for the desired socket. | |
1397 * "pStatus" | |
1398 * Address at which the PRErrorCode resulting from the create is | |
1399 * stored. Must be non-NULL. | |
1400 * "pSocket" | |
1401 * The address at which the Socket is to be stored. Must be non-NULL. | |
1402 * "plContext" | |
1403 * Platform-specific context pointer. | |
1404 * THREAD SAFETY: | |
1405 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
1406 * RETURNS: | |
1407 * Returns NULL if the function succeeds. | |
1408 * Returns a Socket Error if the function fails in | |
1409 * a non-fatal way. | |
1410 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
1411 */ | |
1412 PKIX_Error * | |
1413 pkix_pl_Socket_CreateByName( | |
1414 PKIX_Boolean isServer, | |
1415 PRIntervalTime timeout, | |
1416 char *serverName, | |
1417 PRErrorCode *pStatus, | |
1418 PKIX_PL_Socket **pSocket, | |
1419 void *plContext) | |
1420 { | |
1421 PRNetAddr netAddr; | |
1422 PKIX_PL_Socket *socket = NULL; | |
1423 char *sepPtr = NULL; | |
1424 PRHostEnt hostent; | |
1425 PRIntn hostenum; | |
1426 PRStatus prstatus = PR_FAILURE; | |
1427 char buf[PR_NETDB_BUF_SIZE]; | |
1428 PRUint16 portNum = 0; | |
1429 char *localCopyName = NULL; | |
1430 | |
1431 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName"); | |
1432 PKIX_NULLCHECK_TWO(serverName, pSocket); | |
1433 | |
1434 localCopyName = PL_strdup(serverName); | |
1435 | |
1436 sepPtr = strchr(localCopyName, ':'); | |
1437 /* First strip off the portnum, if present, from the end of the name */ | |
1438 if (sepPtr) { | |
1439 *sepPtr++ = '\0'; | |
1440 portNum = (PRUint16)atoi(sepPtr); | |
1441 } else { | |
1442 portNum = (PRUint16)LDAP_PORT; | |
1443 } | |
1444 | |
1445 prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent); | |
1446 | |
1447 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
1448 /* | |
1449 * The hostname may be a fully-qualified name. Try using just | |
1450 * the leftmost component in our lookup. | |
1451 */ | |
1452 sepPtr = strchr(localCopyName, '.'); | |
1453 if (sepPtr) { | |
1454 *sepPtr++ = '\0'; | |
1455 } | |
1456 prstatus = PR_GetHostByName | |
1457 (localCopyName, buf, sizeof(buf), &hostent); | |
1458 | |
1459 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
1460 PKIX_ERROR | |
1461 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); | |
1462 } | |
1463 } | |
1464 | |
1465 netAddr.inet.family = PR_AF_INET; | |
1466 netAddr.inet.port = PR_htons(portNum); | |
1467 | |
1468 if (isServer) { | |
1469 | |
1470 netAddr.inet.ip = PR_INADDR_ANY; | |
1471 | |
1472 } else { | |
1473 | |
1474 hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr); | |
1475 if (hostenum == -1) { | |
1476 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); | |
1477 } | |
1478 } | |
1479 | |
1480 PKIX_CHECK(PKIX_PL_Object_Alloc | |
1481 (PKIX_SOCKET_TYPE, | |
1482 sizeof (PKIX_PL_Socket), | |
1483 (PKIX_PL_Object **)&socket, | |
1484 plContext), | |
1485 PKIX_COULDNOTCREATESOCKETOBJECT); | |
1486 | |
1487 socket->isServer = isServer; | |
1488 socket->timeout = timeout; | |
1489 socket->clientSock = NULL; | |
1490 socket->serverSock = NULL; | |
1491 socket->netAddr = &netAddr; | |
1492 | |
1493 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
1494 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
1495 socket->callbackList.connectcontinueCallback = | |
1496 pkix_pl_Socket_ConnectContinue; | |
1497 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
1498 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
1499 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
1500 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
1501 | |
1502 if (isServer) { | |
1503 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
1504 PKIX_SOCKETCREATESERVERFAILED); | |
1505 *pStatus = 0; | |
1506 } else { | |
1507 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
1508 PKIX_SOCKETCREATECLIENTFAILED); | |
1509 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), | |
1510 PKIX_SOCKETCONNECTFAILED); | |
1511 } | |
1512 | |
1513 *pSocket = socket; | |
1514 | |
1515 cleanup: | |
1516 PL_strfree(localCopyName); | |
1517 | |
1518 if (PKIX_ERROR_RECEIVED) { | |
1519 PKIX_DECREF(socket); | |
1520 } | |
1521 | |
1522 PKIX_RETURN(SOCKET); | |
1523 } | |
1524 | |
1525 /* | |
1526 * FUNCTION: pkix_pl_Socket_CreateByHostAndPort | |
1527 * DESCRIPTION: | |
1528 * | |
1529 * This function creates a new Socket, setting it to be a server or a client | |
1530 * according to the value of "isServer", setting its timeout value from | |
1531 * "timeout", host from "hostname", and port number from "portNum", and stores | |
1532 * the status at "pStatus" and the created Socket at "pSocket". | |
1533 * | |
1534 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip | |
1535 * address of PR_INADDR_ANY. | |
1536 * | |
1537 * PARAMETERS: | |
1538 * "isServer" | |
1539 * The Boolean value indicating if PKIX_TRUE, that a server socket (using | |
1540 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a | |
1541 * client socket (using Connect) is to be created. | |
1542 * "timeout" | |
1543 * A PRTimeInterval value to be used for I/O waits for this socket. If | |
1544 * zero, non-blocking I/O is to be used. | |
1545 * "hostname" | |
1546 * Address of a character string consisting of the server's domain name. | |
1547 * "portNum" | |
1548 * UInt16 value of the port number for the desired socket. | |
1549 * "pStatus" | |
1550 * Address at which the PRErrorCode resulting from the create is | |
1551 * stored. Must be non-NULL. | |
1552 * "pSocket" | |
1553 * The address at which the Socket is to be stored. Must be non-NULL. | |
1554 * "plContext" | |
1555 * Platform-specific context pointer. | |
1556 * THREAD SAFETY: | |
1557 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
1558 * RETURNS: | |
1559 * Returns NULL if the function succeeds. | |
1560 * Returns a Socket Error if the function fails in | |
1561 * a non-fatal way. | |
1562 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
1563 */ | |
1564 PKIX_Error * | |
1565 pkix_pl_Socket_CreateByHostAndPort( | |
1566 PKIX_Boolean isServer, | |
1567 PRIntervalTime timeout, | |
1568 char *hostname, | |
1569 PRUint16 portnum, | |
1570 PRErrorCode *pStatus, | |
1571 PKIX_PL_Socket **pSocket, | |
1572 void *plContext) | |
1573 { | |
1574 PRNetAddr netAddr; | |
1575 PKIX_PL_Socket *socket = NULL; | |
1576 char *sepPtr = NULL; | |
1577 PRHostEnt hostent; | |
1578 PRIntn hostenum; | |
1579 PRStatus prstatus = PR_FAILURE; | |
1580 char buf[PR_NETDB_BUF_SIZE]; | |
1581 | |
1582 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort"); | |
1583 PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); | |
1584 | |
1585 | |
1586 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent); | |
1587 | |
1588 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
1589 /* | |
1590 * The hostname may be a fully-qualified name. Try using just | |
1591 * the leftmost component in our lookup. | |
1592 */ | |
1593 sepPtr = strchr(hostname, '.'); | |
1594 if (sepPtr) { | |
1595 *sepPtr++ = '\0'; | |
1596 } | |
1597 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent
); | |
1598 | |
1599 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
1600 PKIX_ERROR | |
1601 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); | |
1602 } | |
1603 } | |
1604 | |
1605 netAddr.inet.family = PR_AF_INET; | |
1606 netAddr.inet.port = PR_htons(portnum); | |
1607 | |
1608 if (isServer) { | |
1609 | |
1610 netAddr.inet.ip = PR_INADDR_ANY; | |
1611 | |
1612 } else { | |
1613 | |
1614 hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr); | |
1615 if (hostenum == -1) { | |
1616 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); | |
1617 } | |
1618 } | |
1619 | |
1620 PKIX_CHECK(PKIX_PL_Object_Alloc | |
1621 (PKIX_SOCKET_TYPE, | |
1622 sizeof (PKIX_PL_Socket), | |
1623 (PKIX_PL_Object **)&socket, | |
1624 plContext), | |
1625 PKIX_COULDNOTCREATESOCKETOBJECT); | |
1626 | |
1627 socket->isServer = isServer; | |
1628 socket->timeout = timeout; | |
1629 socket->clientSock = NULL; | |
1630 socket->serverSock = NULL; | |
1631 socket->netAddr = &netAddr; | |
1632 | |
1633 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
1634 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
1635 socket->callbackList.connectcontinueCallback = | |
1636 pkix_pl_Socket_ConnectContinue; | |
1637 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
1638 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
1639 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
1640 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
1641 | |
1642 if (isServer) { | |
1643 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
1644 PKIX_SOCKETCREATESERVERFAILED); | |
1645 *pStatus = 0; | |
1646 } else { | |
1647 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
1648 PKIX_SOCKETCREATECLIENTFAILED); | |
1649 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), | |
1650 PKIX_SOCKETCONNECTFAILED); | |
1651 } | |
1652 | |
1653 *pSocket = socket; | |
1654 | |
1655 cleanup: | |
1656 if (PKIX_ERROR_RECEIVED) { | |
1657 PKIX_DECREF(socket); | |
1658 } | |
1659 | |
1660 PKIX_RETURN(SOCKET); | |
1661 } | |
1662 | |
1663 /* | |
1664 * FUNCTION: pkix_pl_Socket_GetCallbackList | |
1665 */ | |
1666 PKIX_Error * | |
1667 pkix_pl_Socket_GetCallbackList( | |
1668 PKIX_PL_Socket *socket, | |
1669 PKIX_PL_Socket_Callback **pCallbackList, | |
1670 void *plContext) | |
1671 { | |
1672 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList"); | |
1673 PKIX_NULLCHECK_TWO(socket, pCallbackList); | |
1674 | |
1675 *pCallbackList = &(socket->callbackList); | |
1676 | |
1677 PKIX_RETURN(SOCKET); | |
1678 } | |
1679 | |
1680 /* | |
1681 * FUNCTION: pkix_pl_Socket_GetPRFileDesc | |
1682 */ | |
1683 PKIX_Error * | |
1684 pkix_pl_Socket_GetPRFileDesc( | |
1685 PKIX_PL_Socket *socket, | |
1686 PRFileDesc **pDesc, | |
1687 void *plContext) | |
1688 { | |
1689 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc"); | |
1690 PKIX_NULLCHECK_TWO(socket, pDesc); | |
1691 | |
1692 *pDesc = socket->clientSock; | |
1693 | |
1694 PKIX_RETURN(SOCKET); | |
1695 } | |
OLD | NEW |