nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / lib / libpkix / pkix_pl_nss / module / pkix_pl_socket.c
blob8a2231c30346099e27373eef8e1cba8530ee872b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems, Inc.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * pkix_pl_socket.c
40 * Socket Function Definitions
45 * If Socket Tracing is active, messages sent and received will be
46 * timestamped and dumped (to stdout) in standard hex-dump format. E.g.,
48 * 1116612359156140:
49 * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!.
51 * The timestamp is not formatted to be meaningful except as an increasing
52 * value of seconds.microseconds, which is good enough to correlate two
53 * sides of a message exchange and to figure durations.
55 * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE
56 * is defined, but that doesn't mean socket tracing is active. Tracing also
57 * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is
58 * the default value, but it can be overridden by using the debugger to
59 * change its value -- allowing tracing to be turned on and off at various
60 * breakpoints -- or by setting the environment variable SOCKETTRACE. A
61 * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other
62 * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment
63 * value is checked during system initialization.
65 #ifndef BUILD_OPT
66 #define PKIX_SOCKETTRACE 1
67 #endif
69 #ifdef PKIX_SOCKETDEBUG
70 #define PKIX_SOCKETTRACE 1
71 #endif
73 #include "pkix_pl_socket.h"
75 /* --Private-Socket-Functions---------------------------------- */
77 #ifdef PKIX_SOCKETTRACE
78 static PKIX_Boolean socketTraceFlag = PKIX_TRUE;
81 * FUNCTION: pkix_pl_socket_timestamp
82 * DESCRIPTION:
84 * This functions prints to stdout the time of day, as obtained from the
85 * system function gettimeofday, as seconds.microseconds. Its resolution
86 * is whatever the system call provides.
88 * PARAMETERS:
89 * none
90 * THREAD SAFETY:
91 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
92 * RETURNS:
93 * none
95 static void pkix_pl_socket_timestamp() {
96 PRInt64 prTime;
97 prTime = PR_Now();
98 printf("%lld:\n", prTime);
102 * FUNCTION: pkix_pl_socket_hexDigit
103 * DESCRIPTION:
105 * This functions prints to stdout the byte "byteVal" as two hex digits.
107 * PARAMETERS:
108 * "byteVal"
109 * The value to be printed.
110 * THREAD SAFETY:
111 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
112 * RETURNS:
113 * none
115 static void pkix_pl_socket_hexDigit(char byteVal) {
116 int n = 0;
117 char cHi = '\0';
118 char cLow = '\0';
119 n = ((byteVal >> 4) & 0xf);
120 if (n > 9) {
121 cHi = (char) ((n - 10) + 'A');
122 } else {
123 cHi = (char) (n + '0');
125 n = byteVal & 0xf;
126 if (n > 9) {
127 cLow = (char) ((n - 10) + 'A');
128 } else {
129 cLow = (char) (n + '0');
131 (void) printf("%c%c", cHi, cLow);
135 * FUNCTION: pkix_pl_socket_linePrefix
136 * DESCRIPTION:
138 * This functions prints to stdout the address provided by "addr" as four
139 * hexadecimal digits followed by a colon and a space.
141 * PARAMETERS:
142 * "addr"
143 * The address to be printed
144 * none
145 * THREAD SAFETY:
146 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
147 * RETURNS:
148 * none
150 static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) {
151 pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff));
152 pkix_pl_socket_hexDigit((char)(addr & 0xff));
153 (void) printf(": ");
157 * FUNCTION: pkix_pl_socket_traceLine
158 * DESCRIPTION:
160 * This functions prints to stdout the sixteen bytes beginning at the
161 * address pointed to by "ptr". The bytes are printed as sixteen pairs
162 * of hexadecimal characters followed by an ascii interpretation, in which
163 * characters from 0x20 to 0x7d are shown as their ascii equivalents, and
164 * other values are represented as periods.
166 * PARAMETERS:
167 * "ptr"
168 * The address of the first of the bytes to be printed
169 * THREAD SAFETY:
170 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
171 * RETURNS:
172 * none
174 static void pkix_pl_socket_traceLine(char *ptr) {
175 PKIX_UInt32 i = 0;
176 pkix_pl_socket_linePrefix((PKIX_UInt32)ptr);
177 for (i = 0; i < 16; i++) {
178 printf(" ");
179 pkix_pl_socket_hexDigit(ptr[i]);
180 if (i == 7) {
181 printf(" ");
184 printf(" ");
185 for (i = 0; i < 16; i++) {
186 if ((ptr[i] < ' ') || (ptr[i] > '}')) {
187 printf(".");
188 } else {
189 printf("%c", ptr[i]);
192 printf("\n");
196 * FUNCTION: pkix_pl_socket_tracePartialLine
197 * DESCRIPTION:
199 * This functions prints to stdout the number of bytes given by "nBytes",
200 * beginning at the address pointed to by "ptr". The bytes are printed as
201 * pairs of hexadecimal characters followed by an ascii interpretation, in
202 * which characters from 0x20 to 0x7d are shown as their ascii equivalents,
203 * and other values are represented as periods.
205 * PARAMETERS:
206 * "ptr"
207 * The address of the first of the bytes to be printed
208 * "nBytes"
209 * The Int32 value giving the number of bytes to be printed. If "nBytes"
210 * is greater than sixteen, the results will be unattractive.
211 * none
212 * THREAD SAFETY:
213 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
214 * RETURNS:
215 * none
217 static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) {
218 PKIX_UInt32 i = 0;
219 if (nBytes > 0) {
220 pkix_pl_socket_linePrefix((PKIX_UInt32)ptr);
222 for (i = 0; i < nBytes; i++) {
223 printf(" ");
224 pkix_pl_socket_hexDigit(ptr[i]);
225 if (i == 7) {
226 printf(" ");
229 for (i = nBytes; i < 16; i++) {
230 printf(" ");
231 if (i == 7) {
232 printf(" ");
235 printf(" ");
236 for (i = 0; i < nBytes; i++) {
237 if ((ptr[i] < ' ') || (ptr[i] > '}')) {
238 printf(".");
239 } else {
240 printf("%c", ptr[i]);
243 printf("\n");
247 * FUNCTION: pkix_pl_socket_tracebuff
248 * DESCRIPTION:
250 * This functions prints to stdout the number of bytes given by "nBytes",
251 * beginning with the byte pointed to by "buf". The output is preceded by
252 * a timestamp, and each group of sixteen (and a remainder, if any) is
253 * preceded by its address. The contents are shown in hexadecimal and as
254 * ascii characters. If "nBytes" is zero, the timestamp and starting
255 * address are displayed.
257 * PARAMETERS:
258 * "buf"
259 * The starting address of the bytes to be printed
260 * "nBytes"
261 * The number of bytes to be printed
262 * THREAD SAFETY:
263 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
264 * RETURNS:
265 * none
267 void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) {
268 PKIX_UInt32 bytesRemaining = nBytes;
269 PKIX_UInt32 offset = 0;
270 char *bufptr = (char *)buf;
272 if (socketTraceFlag == PKIX_FALSE) return;
274 pkix_pl_socket_timestamp();
276 * Special case: if called with length of zero, just do address
278 if (nBytes == 0) {
279 pkix_pl_socket_linePrefix((PKIX_UInt32)buf);
280 printf("\n");
281 } else {
282 while (bytesRemaining >= 16) {
283 pkix_pl_socket_traceLine(&bufptr[offset]);
284 bytesRemaining -= 16;
285 offset += 16;
287 pkix_pl_socket_tracePartialLine
288 (&bufptr[offset], bytesRemaining);
292 #endif
295 * FUNCTION: pkix_pl_Socket_SetNonBlocking
296 * DESCRIPTION:
298 * This functions sets the socket represented by the PRFileDesc "fileDesc"
299 * to nonblocking mode.
301 * PARAMETERS:
302 * "fileDesc"
303 * The address of the PRFileDesc whose I/O mode is to be set
304 * non-blocking. Must be non-NULL.
305 * "plContext"
306 * Platform-specific context pointer
307 * THREAD SAFETY:
308 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
309 * RETURNS:
310 * none
312 static PKIX_Error *
313 pkix_pl_Socket_SetNonBlocking(
314 PRFileDesc *fileDesc,
315 void *plContext)
317 PRStatus rv = PR_FAILURE;
318 PRSocketOptionData sockOptionData;
320 PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking");
321 PKIX_NULLCHECK_ONE(fileDesc);
323 sockOptionData.option = PR_SockOpt_Nonblocking;
324 sockOptionData.value.non_blocking = PR_TRUE;
326 PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption,
327 (fileDesc, &sockOptionData));
329 if (rv != PR_SUCCESS) {
330 PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
332 cleanup:
334 PKIX_RETURN(SOCKET);
338 * FUNCTION: pkix_pl_Socket_CreateClient
339 * DESCRIPTION:
341 * This functions creates a client socket for the PKIX_PL_Socket pointed to
342 * by "socket". If "socket" was created with a timeout value of zero, the
343 * client socket is set to use nonblocking I/O.
345 * PARAMETERS:
346 * "socket"
347 * The address of the Socket for which a client socket is to be
348 * created. Must be non-NULL.
349 * "plContext"
350 * Platform-specific context pointer
351 * THREAD SAFETY:
352 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
353 * RETURNS:
354 * none
357 static PKIX_Error *
358 pkix_pl_Socket_CreateClient(
359 PKIX_PL_Socket *socket,
360 void *plContext)
362 #ifdef PKIX_SOCKETDEBUG
363 PRErrorCode errorcode = 0;
364 #endif
365 PRFileDesc *mySock = NULL;
367 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient");
368 PKIX_NULLCHECK_ONE(socket);
370 PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ());
371 if (!mySock) {
372 #ifdef PKIX_SOCKETDEBUG
373 errorcode = PR_GetError();
374 printf
375 ("pkix_pl_Socket_CreateClient: %s\n",
376 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
377 #endif
378 PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
381 #ifdef PKIX_SOCKETDEBUG
382 printf("Created socket, PRFileDesc @ %#X\n", mySock);
383 #endif
385 socket->clientSock = mySock;
386 socket->status = SOCKET_UNCONNECTED;
387 if (socket->timeout == 0) {
388 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext),
389 PKIX_SOCKETSETNONBLOCKINGFAILED);
392 cleanup:
394 PKIX_RETURN(SOCKET);
398 * FUNCTION: pkix_pl_Socket_CreateServer
399 * DESCRIPTION:
401 * This functions creates a server socket for the PKIX_PL_Socket pointed to
402 * by "socket". If "socket" was created with a timeout value of zero, the
403 * server socket is set to use nonblocking I/O.
405 * Warning: there seems to be a problem with operating a server socket in
406 * non-blocking mode. If the server calls Recv prior to a corresponding
407 * Send, the message may be lost.
409 * PARAMETERS:
410 * "socket"
411 * The address of the Socket for which a server socket is to be
412 * created. Must be non-NULL.
413 * "plContext"
414 * Platform-specific context pointer
415 * THREAD SAFETY:
416 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
417 * RETURNS:
418 * none
420 static PKIX_Error *
421 pkix_pl_Socket_CreateServer(
422 PKIX_PL_Socket *socket,
423 void *plContext)
425 /* #ifdef PKIX_SOCKETDEBUG */
426 PRErrorCode errorcode = 0;
427 /* #endif */
428 PRStatus rv = PR_FAILURE;
429 PRFileDesc *serverSock = NULL;
430 PRSocketOptionData sockOptionData;
432 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer");
433 PKIX_NULLCHECK_ONE(socket);
435 PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ());
436 if (!serverSock) {
437 #ifdef PKIX_SOCKETDEBUG
438 errorcode = PR_GetError();
439 printf
440 ("pkix_pl_Socket_CreateServer: %s\n",
441 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
442 #endif
443 PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
446 socket->serverSock = serverSock;
448 #ifdef PKIX_SOCKETDEBUG
449 printf("Created socket, PRFileDesc @ %#X\n", serverSock);
450 #endif
452 if (socket->timeout == 0) {
453 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext),
454 PKIX_SOCKETSETNONBLOCKINGFAILED);
457 sockOptionData.option = PR_SockOpt_Reuseaddr;
458 sockOptionData.value.reuse_addr = PR_TRUE;
460 PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption,
461 (serverSock, &sockOptionData));
463 if (rv != PR_SUCCESS) {
464 PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
467 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr));
469 if (rv == PR_FAILURE) {
470 /* #ifdef PKIX_SOCKETDEBUG */
471 errorcode = PR_GetError();
472 printf
473 ("pkix_pl_Socket_CreateServer: %s\n",
474 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
475 /* #endif */
476 PKIX_ERROR(PKIX_PRBINDFAILED);
479 #ifdef PKIX_SOCKETDEBUG
480 printf("Successful bind!\n");
481 #endif
483 socket->status = SOCKET_BOUND;
485 cleanup:
487 PKIX_RETURN(SOCKET);
491 * FUNCTION: pkix_pl_Socket_Connect
492 * DESCRIPTION:
494 * This functions performs the connect function for the client socket
495 * specified in "socket", storing the status at "pStatus".
497 * PARAMETERS:
498 * "socket"
499 * The address of the Socket for which a connect is to be performed.
500 * Must be non-NULL.
501 * "pStatus"
502 * The address at which the connection status is stored. Must be non-NULL.
503 * "plContext"
504 * Platform-specific context pointer
505 * THREAD SAFETY:
506 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
507 * RETURNS:
508 * none
510 static PKIX_Error *
511 pkix_pl_Socket_Connect(
512 PKIX_PL_Socket *socket,
513 PRErrorCode *pStatus,
514 void *plContext)
516 PRStatus rv = PR_FAILURE;
517 PRErrorCode errorcode = 0;
519 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect");
520 PKIX_NULLCHECK_TWO(socket, socket->clientSock);
522 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect,
523 (socket->clientSock, socket->netAddr, socket->timeout));
525 if (rv == PR_FAILURE) {
526 errorcode = PR_GetError();
527 *pStatus = errorcode;
528 if (errorcode == PR_IN_PROGRESS_ERROR) {
529 socket->status = SOCKET_CONNECTPENDING;
530 goto cleanup;
531 } else {
532 #ifdef PKIX_SOCKETDEBUG
533 printf
534 ("pkix_pl_Socket_Connect: %s\n",
535 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
536 #endif
537 PKIX_ERROR(PKIX_PRCONNECTFAILED);
541 #ifdef PKIX_SOCKETDEBUG
542 printf("Successful connect!\n");
543 #endif
545 *pStatus = 0;
546 socket->status = SOCKET_CONNECTED;
548 cleanup:
550 PKIX_RETURN(SOCKET);
554 * FUNCTION: pkix_pl_Socket_ConnectContinue
555 * DESCRIPTION:
557 * This functions continues the connect function for the client socket
558 * specified in "socket", storing the status at "pStatus". It is expected that
559 * the non-blocking connect has returned PR_IN_PROGRESS_ERROR.
561 * PARAMETERS:
562 * "socket"
563 * The address of the Socket for which a connect is to be continued.
564 * Must be non-NULL.
565 * "pStatus"
566 * The address at which the connection status is stored. Must be non-NULL.
567 * "plContext"
568 * Platform-specific context pointer
569 * THREAD SAFETY:
570 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
571 * RETURNS:
572 * none
574 static PKIX_Error *
575 pkix_pl_Socket_ConnectContinue(
576 PKIX_PL_Socket *socket,
577 PRErrorCode *pStatus,
578 void *plContext)
580 PRStatus rv = PR_FAILURE;
581 PRErrorCode errorcode = 0;
582 PRPollDesc pollDesc;
583 PRInt32 numEvents = 0;
585 PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue");
586 PKIX_NULLCHECK_TWO(socket, socket->clientSock);
588 pollDesc.fd = socket->clientSock;
589 pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
590 pollDesc.out_flags = 0;
591 PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
592 if (numEvents < 0) {
593 PKIX_ERROR(PKIX_PRPOLLFAILED);
596 if (numEvents == 0) {
597 *pStatus = PR_IN_PROGRESS_ERROR;
598 goto cleanup;
601 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue,
602 (socket->clientSock, pollDesc.out_flags));
605 * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS
606 * even though the connection is not yet ready. But its deceit
607 * is betrayed by the contents of out_flags!
609 if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) {
610 *pStatus = PR_IN_PROGRESS_ERROR;
611 goto cleanup;
614 if (rv == PR_FAILURE) {
615 errorcode = PR_GetError();
616 *pStatus = errorcode;
617 if (errorcode == PR_IN_PROGRESS_ERROR) {
618 goto cleanup;
619 } else {
620 #ifdef PKIX_SOCKETDEBUG
621 printf
622 ("pkix_pl_Socket_ConnectContinue: %s\n",
623 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
624 #endif
625 PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED);
629 #ifdef PKIX_SOCKETDEBUG
630 printf("Successful connect!\n");
631 #endif
633 *pStatus = 0;
634 socket->status = SOCKET_CONNECTED;
636 cleanup:
638 PKIX_RETURN(SOCKET);
642 * FUNCTION: pkix_pl_Socket_Destroy
643 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
645 static PKIX_Error *
646 pkix_pl_Socket_Destroy(
647 PKIX_PL_Object *object,
648 void *plContext)
650 PKIX_PL_Socket *socket = NULL;
652 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy");
653 PKIX_NULLCHECK_ONE(object);
655 PKIX_CHECK(pkix_CheckType
656 (object, PKIX_SOCKET_TYPE, plContext),
657 PKIX_OBJECTNOTANSOCKET);
659 socket = (PKIX_PL_Socket *)object;
661 if (socket->isServer) {
662 if (socket->serverSock) {
663 PR_Close(socket->serverSock);
665 } else {
666 if (socket->clientSock) {
667 PR_Close(socket->clientSock);
671 cleanup:
673 PKIX_RETURN(SOCKET);
677 * FUNCTION: pkix_pl_Socket_Hashcode
678 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
680 static PKIX_Error *
681 pkix_pl_Socket_Hashcode(
682 PKIX_PL_Object *object,
683 PKIX_UInt32 *pHashcode,
684 void *plContext)
686 PKIX_PL_Socket *socket = NULL;
688 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode");
689 PKIX_NULLCHECK_TWO(object, pHashcode);
691 PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext),
692 PKIX_OBJECTNOTSOCKET);
694 socket = (PKIX_PL_Socket *)object;
696 *pHashcode = (((socket->timeout << 3) +
697 (socket->netAddr->inet.family << 3)) +
698 (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) +
699 socket->netAddr->inet.port;
701 cleanup:
703 PKIX_RETURN(SOCKET);
707 * FUNCTION: pkix_pl_Socket_Equals
708 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
710 static PKIX_Error *
711 pkix_pl_Socket_Equals(
712 PKIX_PL_Object *firstObject,
713 PKIX_PL_Object *secondObject,
714 PKIX_Int32 *pResult,
715 void *plContext)
717 PKIX_PL_Socket *firstSocket = NULL;
718 PKIX_PL_Socket *secondSocket = NULL;
720 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals");
721 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
723 *pResult = PKIX_FALSE;
725 PKIX_CHECK(pkix_CheckTypes
726 (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext),
727 PKIX_OBJECTNOTSOCKET);
729 firstSocket = (PKIX_PL_Socket *)firstObject;
730 secondSocket = (PKIX_PL_Socket *)secondObject;
732 if (firstSocket->timeout != secondSocket->timeout) {
733 goto cleanup;
736 if (firstSocket->netAddr == secondSocket->netAddr) {
737 *pResult = PKIX_TRUE;
738 goto cleanup;
741 if ((firstSocket->netAddr->inet.family !=
742 secondSocket->netAddr->inet.family) ||
743 (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) !=
744 *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) ||
745 (firstSocket->netAddr->inet.port !=
746 secondSocket->netAddr->inet.port)) {
748 goto cleanup;
752 *pResult = PKIX_TRUE;
754 cleanup:
756 PKIX_RETURN(SOCKET);
760 * FUNCTION: pkix_pl_Socket_RegisterSelf
762 * DESCRIPTION:
763 * Registers PKIX_PL_SOCKET_TYPE and its related
764 * functions with systemClasses[]
766 * THREAD SAFETY:
767 * Not Thread Safe - for performance and complexity reasons
769 * Since this function is only called by PKIX_PL_Initialize, which should
770 * only be called once, it is acceptable that this function is not
771 * thread-safe.
773 PKIX_Error *
774 pkix_pl_Socket_RegisterSelf(void *plContext)
776 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
777 pkix_ClassTable_Entry entry;
779 PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf");
781 entry.description = "Socket";
782 entry.objCounter = 0;
783 entry.typeObjectSize = sizeof(PKIX_PL_Socket);
784 entry.destructor = pkix_pl_Socket_Destroy;
785 entry.equalsFunction = pkix_pl_Socket_Equals;
786 entry.hashcodeFunction = pkix_pl_Socket_Hashcode;
787 entry.toStringFunction = NULL;
788 entry.comparator = NULL;
789 entry.duplicateFunction = NULL;
791 systemClasses[PKIX_SOCKET_TYPE] = entry;
793 #ifdef PKIX_SOCKETTRACE
795 char *val = NULL;
796 val = PR_GetEnv("SOCKETTRACE");
797 /* Is SOCKETTRACE set in the environment? */
798 if ((val != NULL) && (*val != '\0')) {
799 socketTraceFlag =
800 ((*val == '1')?PKIX_TRUE:PKIX_FALSE);
803 #endif
805 PKIX_RETURN(SOCKET);
808 /* --Public-Socket-Functions----------------------------------- */
811 * FUNCTION: pkix_pl_Socket_Listen
812 * DESCRIPTION:
814 * This functions establishes a listening queue for the server Socket
815 * pointed to by "socket".
817 * PARAMETERS:
818 * "socket"
819 * The address of the server socket for which the queue is to be
820 * established. Must be non-NULL.
821 * "backlog"
822 * The UInt32 value of the length of the queue to be established.
823 * "plContext"
824 * Platform-specific context pointer
825 * THREAD SAFETY:
826 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
827 * RETURNS:
828 * none
830 static PKIX_Error *
831 pkix_pl_Socket_Listen(
832 PKIX_PL_Socket *socket,
833 PKIX_UInt32 backlog,
834 void *plContext)
836 #ifdef PKIX_SOCKETDEBUG
837 PRErrorCode errorcode = 0;
838 #endif
839 PRStatus rv = PR_FAILURE;
841 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen");
842 PKIX_NULLCHECK_TWO(socket, socket->serverSock);
844 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen,
845 (socket->serverSock, (PRIntn)backlog));
847 if (rv == PR_FAILURE) {
848 #ifdef PKIX_SOCKETDEBUG
849 errorcode = PR_GetError();
850 printf
851 ("pkix_pl_Socket_Listen: %s\n",
852 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
853 #endif
854 PKIX_ERROR(PKIX_PRLISTENFAILED);
857 #ifdef PKIX_SOCKETDEBUG
858 printf("Successful listen!\n");
859 #endif
861 socket->status = SOCKET_LISTENING;
862 cleanup:
864 PKIX_RETURN(SOCKET);
868 * FUNCTION: pkix_pl_Socket_Shutdown
869 * DESCRIPTION:
871 * This functions performs the shutdown of any connections controlled by the
872 * socket pointed to by "socket".
874 * PARAMETERS:
875 * "socket"
876 * The address of the socket to be shut down. Must be non-NULL.
877 * "plContext"
878 * Platform-specific context pointer
879 * THREAD SAFETY:
880 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
881 * RETURNS:
882 * none
884 static PKIX_Error *
885 pkix_pl_Socket_Shutdown(
886 PKIX_PL_Socket *socket,
887 void *plContext)
889 #ifdef PKIX_SOCKETDEBUG
890 PRErrorCode errorcode = 0;
891 #endif
892 PRStatus rv = PR_FAILURE;
893 PRFileDesc *fileDesc = NULL;
895 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown");
896 PKIX_NULLCHECK_ONE(socket);
898 fileDesc =
899 (socket->isServer)?(socket->serverSock):(socket->clientSock);
901 PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown,
902 (fileDesc, PR_SHUTDOWN_BOTH));
904 if (rv == PR_FAILURE) {
905 #ifdef PKIX_SOCKETDEBUG
906 errorcode = PR_GetError();
907 printf
908 ("pkix_pl_Socket_Shutdown: %s\n",
909 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
910 #endif
911 PKIX_ERROR(PKIX_PRSHUTDOWNFAILED);
913 socket->status = SOCKET_SHUTDOWN;
915 cleanup:
917 PKIX_RETURN(SOCKET);
921 * FUNCTION: pkix_pl_Socket_Send
922 * DESCRIPTION:
924 * This functions sends a message using the socket pointed to by "sendSock",
925 * from the buffer pointed to by "buf", of the number of bytes given by
926 * "bytesToWrite", storing the number of bytes actually written at
927 * "pBytesWritten". If "socket" is in non-blocking mode, the send operation
928 * may store -1 at "pBytesWritten" and the write is not complete until a
929 * corresponding pkix_pl_Poll call has indicated its completion by returning
930 * a non-negative value for bytes written.
932 * PARAMETERS:
933 * "sendSock"
934 * The address of the Socket on which the message is to be sent. Must
935 * be non-NULL.
936 * "buf"
937 * The address of the data to be sent. Must be non-NULL.
938 * "bytesToWrite""
939 * The UInt32 value indicating the number of bytes to write.
940 * "pBytesWritten"
941 * The address at which the Int32 value indicating the number of bytes
942 * actually written is to be stored. Must be non-NULL.
943 * "plContext"
944 * Platform-specific context pointer
945 * THREAD SAFETY:
946 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
947 * RETURNS:
948 * none
950 static PKIX_Error *
951 pkix_pl_Socket_Send(
952 PKIX_PL_Socket *sendSock,
953 void *buf,
954 PKIX_UInt32 bytesToWrite,
955 PKIX_Int32 *pBytesWritten,
956 void *plContext)
958 PRInt32 bytesWritten = 0;
959 PRErrorCode errorcode = 0;
960 PRFileDesc *fd = NULL;
962 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send");
963 PKIX_NULLCHECK_TWO(buf, pBytesWritten);
965 fd = sendSock->clientSock;
967 PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send,
968 (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout));
970 if (bytesWritten >= 0) {
971 if (sendSock->status == SOCKET_SENDRCVPENDING) {
972 sendSock->status = SOCKET_RCVPENDING;
973 } else {
974 sendSock->status = SOCKET_CONNECTED;
976 #ifdef PKIX_SOCKETTRACE
977 pkix_pl_socket_tracebuff(buf, bytesWritten);
978 #endif
979 } else {
980 errorcode = PR_GetError();
981 if (errorcode != PR_WOULD_BLOCK_ERROR) {
982 #ifdef PKIX_SOCKETDEBUG
983 printf
984 ("pkix_pl_Socket_Send: %s\n",
985 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
986 #endif
987 PKIX_ERROR(PKIX_PRSENDFAILED);
990 sendSock->writeBuf = buf;
991 sendSock->writeBufSize = bytesToWrite;
992 if (sendSock->status == SOCKET_RCVPENDING) {
993 sendSock->status = SOCKET_SENDRCVPENDING;
994 } else {
995 sendSock->status = SOCKET_SENDPENDING;
999 *pBytesWritten = (PKIX_Int32)bytesWritten;
1001 cleanup:
1003 PKIX_RETURN(SOCKET);
1007 * FUNCTION: pkix_pl_Socket_Recv
1008 * DESCRIPTION:
1010 * This functions receives a message on the socket pointed to by "rcvSock",
1011 * into the buffer pointed to by "buf", of capacity given by "capacity",
1012 * storing the number of bytes actually received at "pBytesRead". If "socket"
1013 * is in non-blocking mode, the receive operation may store -1 at
1014 * "pBytesWritten". In that case the write is not complete until a
1015 * corresponding pkix_pl_Poll call has indicated its completion by returning
1016 * a non-negative value for bytes read.
1018 * PARAMETERS:
1019 * "rcvSock"
1020 * The address of the Socket on which the message is to be received.
1021 * Must be non-NULL.
1022 * "buf"
1023 * The address of the buffer into which the message is to be received.
1024 * Must be non-NULL.
1025 * "capacity"
1026 * The UInt32 value of the size of the buffer; that is, the maximum
1027 * number of bytes that can be received.
1028 * "pBytesRead"
1029 * The address at which is stored the Int32 value of the number of bytes
1030 * actually received.
1031 * "plContext"
1032 * Platform-specific context pointer
1033 * THREAD SAFETY:
1034 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
1035 * RETURNS:
1036 * none
1038 static PKIX_Error *
1039 pkix_pl_Socket_Recv(
1040 PKIX_PL_Socket *rcvSock,
1041 void *buf,
1042 PKIX_UInt32 capacity,
1043 PKIX_Int32 *pBytesRead,
1044 void *plContext)
1046 PRErrorCode errorcode = 0;
1047 PRInt32 bytesRead = 0;
1048 PRFileDesc *fd = NULL;
1050 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv");
1051 PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead);
1053 fd = rcvSock->clientSock;
1055 PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv,
1056 (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout));
1058 if (bytesRead > 0) {
1059 if (rcvSock->status == SOCKET_SENDRCVPENDING) {
1060 rcvSock->status = SOCKET_SENDPENDING;
1061 } else {
1062 rcvSock->status = SOCKET_CONNECTED;
1064 #ifdef PKIX_SOCKETTRACE
1065 pkix_pl_socket_tracebuff(buf, bytesRead);
1066 #endif
1067 } else if (bytesRead == 0) {
1068 PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED);
1069 } else {
1070 errorcode = PR_GetError();
1071 if (errorcode != PR_WOULD_BLOCK_ERROR) {
1072 #ifdef PKIX_SOCKETDEBUG
1073 printf
1074 ("pkix_pl_Socket_Recv: %s\n",
1075 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
1076 #endif
1077 PKIX_ERROR(PKIX_PRRECVFAILED);
1079 rcvSock->readBuf = buf;
1080 rcvSock->readBufSize = capacity;
1081 if (rcvSock->status == SOCKET_SENDPENDING) {
1082 rcvSock->status = SOCKET_SENDRCVPENDING;
1083 } else {
1084 rcvSock->status = SOCKET_RCVPENDING;
1089 *pBytesRead = (PKIX_Int32)bytesRead;
1091 cleanup:
1093 PKIX_RETURN(SOCKET);
1097 * FUNCTION: pkix_pl_Socket_Poll
1098 * DESCRIPTION:
1100 * This functions checks for completion of an earlier Send or Recv on the
1101 * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes
1102 * written by a completed Send and in "pBytesRead" the number of bytes
1103 * received in a completed Recv. A value of -1 returned indicates the
1104 * operation has still not completed. A NULL pointer may be supplied for
1105 * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer
1106 * may be supplied for "pBytesRead" to avoid checking for completion of a Recv.
1108 * PARAMETERS:
1109 * "sock"
1110 * The address of the socket for which completions are to be checked.
1111 * "pBytesWritten"
1112 * The address at which the number of bytes written is to be stored, if
1113 * a pending Send has completed. If NULL, Sends are not checked.
1114 * "pBytesRead"
1115 * The address at which the number of bytes read is to be stored, if
1116 * a pending Recv has completed. If NULL, Recvs are not checked.
1117 * "plContext"
1118 * Platform-specific context pointer
1119 * THREAD SAFETY:
1120 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
1121 * RETURNS:
1122 * none
1124 static PKIX_Error *
1125 pkix_pl_Socket_Poll(
1126 PKIX_PL_Socket *sock,
1127 PKIX_Int32 *pBytesWritten,
1128 PKIX_Int32 *pBytesRead,
1129 void *plContext)
1131 PRPollDesc pollDesc;
1132 PRInt32 numEvents = 0;
1133 PKIX_Int32 bytesRead = 0;
1134 PKIX_Int32 bytesWritten = 0;
1135 PRErrorCode errorcode = 0;
1137 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll");
1138 PKIX_NULLCHECK_ONE(sock);
1140 pollDesc.fd = sock->clientSock;
1141 pollDesc.in_flags = 0;
1142 pollDesc.out_flags = 0;
1144 if ((pBytesWritten) &&
1145 ((sock->status == SOCKET_SENDPENDING) ||
1146 (sock->status = SOCKET_SENDRCVPENDING))) {
1147 pollDesc.in_flags = PR_POLL_WRITE;
1150 if ((pBytesRead) &&
1151 ((sock->status = SOCKET_RCVPENDING) ||
1152 (sock->status = SOCKET_SENDRCVPENDING))) {
1153 pollDesc.in_flags |= PR_POLL_READ;
1156 PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
1158 if (numEvents < 0) {
1159 PKIX_ERROR(PKIX_PRPOLLFAILED);
1160 } else if (numEvents > 0) {
1161 if (pollDesc.out_flags & PR_POLL_WRITE) {
1162 PKIX_CHECK(pkix_pl_Socket_Send
1163 (sock,
1164 sock->writeBuf,
1165 sock->writeBufSize,
1166 &bytesWritten,
1167 plContext),
1168 PKIX_SOCKETSENDFAILED);
1169 *pBytesWritten = (PKIX_Int32)bytesWritten;
1170 if (bytesWritten >= 0) {
1171 sock->writeBuf = NULL;
1172 sock->writeBufSize = 0;
1176 if (pollDesc.out_flags & PR_POLL_READ) {
1177 PKIX_CHECK(pkix_pl_Socket_Recv
1178 (sock,
1179 sock->readBuf,
1180 sock->readBufSize,
1181 &bytesRead,
1182 plContext),
1183 PKIX_SOCKETRECVFAILED);
1184 *pBytesRead = (PKIX_Int32)bytesRead;
1185 if (bytesRead >= 0) {
1186 sock->readBuf = NULL;
1187 sock->readBufSize = 0;
1190 } else if (numEvents == 0) {
1191 errorcode = PR_GetError();
1192 if (errorcode != PR_WOULD_BLOCK_ERROR) {
1193 #ifdef PKIX_SOCKETDEBUG
1194 printf
1195 ("pkix_pl_Socket_Poll: %s\n",
1196 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
1197 #endif
1198 PKIX_ERROR(PKIX_PRPOLLFAILED);
1200 if (pBytesWritten) {
1201 *pBytesWritten = 0;
1203 if (pBytesRead) {
1204 *pBytesRead = 0;
1208 cleanup:
1210 PKIX_RETURN(SOCKET);
1214 * FUNCTION: pkix_pl_Socket_Accept
1215 * DESCRIPTION:
1217 * This functions accepts a client connection for the server Socket pointed
1218 * to by "serverSocket", creating a new Socket and storing the result at
1219 * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this
1220 * function will return NULL if there is no client connection to accept.
1221 * Otherwise this function will block until a connection is available.
1222 * When a client connection is available the new Socket will have the same
1223 * blocking/non-blocking property as "serverSocket".
1225 * PARAMETERS:
1226 * "serverSocket"
1227 * The address of the Socket for which a client connection is to be
1228 * accepted. Must be non-NULL.
1229 * "pRendezvousSocket"
1230 * The address at which the created Socket is stored, when a client
1231 * connection is available, or at which NULL is stored, if no connection
1232 * is available for a non-blocking "serverSocket". Must be non-NULL.
1233 * "plContext"
1234 * Platform-specific context pointer
1235 * THREAD SAFETY:
1236 * Thread Safe (see Thread Safety definitions in Programmer's Guide)
1237 * RETURNS:
1238 * none
1240 static PKIX_Error *
1241 pkix_pl_Socket_Accept(
1242 PKIX_PL_Socket *serverSocket,
1243 PKIX_PL_Socket **pRendezvousSocket,
1244 void *plContext)
1246 PRErrorCode errorcode = 0;
1247 PRFileDesc *rendezvousSock = NULL;
1248 PRNetAddr *clientAddr = NULL;
1249 PKIX_PL_Socket *newSocket = NULL;
1251 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept");
1252 PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket);
1254 PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept,
1255 (serverSocket->serverSock, clientAddr, serverSocket->timeout));
1257 if (!rendezvousSock) {
1258 errorcode = PR_GetError();
1259 if (errorcode != PR_WOULD_BLOCK_ERROR) {
1260 #ifdef PKIX_SOCKETDEBUG
1261 printf
1262 ("pkix_pl_Socket_Accept: %s\n",
1263 PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
1264 #endif
1265 PKIX_ERROR(PKIX_PRACCEPTFAILED);
1267 serverSocket->status = SOCKET_ACCEPTPENDING;
1268 *pRendezvousSocket = NULL;
1269 goto cleanup;
1273 #ifdef PKIX_SOCKETDEBUG
1274 printf("Successful accept!\n");
1275 #endif
1277 PKIX_CHECK(PKIX_PL_Object_Alloc
1278 (PKIX_SOCKET_TYPE,
1279 sizeof (PKIX_PL_Socket),
1280 (PKIX_PL_Object **)&newSocket,
1281 plContext),
1282 PKIX_COULDNOTCREATESOCKETOBJECT);
1284 newSocket->isServer = PKIX_FALSE;
1285 newSocket->timeout = serverSocket->timeout;
1286 newSocket->clientSock = rendezvousSock;
1287 newSocket->serverSock = NULL;
1288 newSocket->netAddr = NULL;
1289 newSocket->status = SOCKET_CONNECTED;
1290 newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
1291 newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen;
1292 newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
1293 newSocket->callbackList.connectcontinueCallback =
1294 pkix_pl_Socket_ConnectContinue;
1295 newSocket->callbackList.sendCallback = pkix_pl_Socket_Send;
1296 newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv;
1297 newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll;
1299 if (serverSocket->timeout == 0) {
1300 PKIX_CHECK(pkix_pl_Socket_SetNonBlocking
1301 (rendezvousSock, plContext),
1302 PKIX_SOCKETSETNONBLOCKINGFAILED);
1305 *pRendezvousSocket = newSocket;
1307 cleanup:
1309 PKIX_RETURN(SOCKET);
1313 * FUNCTION: pkix_pl_Socket_Create
1314 * DESCRIPTION:
1316 * This function creates a new Socket, setting it to be a server or a client
1317 * according to the value of "isServer", setting its timeout value from
1318 * "timeout" and server address from "netAddr", and stores the created Socket
1319 * at "pSocket".
1321 * PARAMETERS:
1322 * "isServer"
1323 * The Boolean value indicating if PKIX_TRUE, that a server socket (using
1324 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
1325 * client socket (using Connect) is to be created.
1326 * "timeout"
1327 * A PRTimeInterval value to be used for I/O waits for this socket. If
1328 * zero, non-blocking I/O is to be used.
1329 * "netAddr"
1330 * The PRNetAddr to be used for the Bind function, if this is a server
1331 * socket, or for the Connect, if this is a client socket.
1332 * "pSocket"
1333 * The address at which the Socket is to be stored. Must be non-NULL.
1334 * "plContext"
1335 * Platform-specific context pointer.
1336 * THREAD SAFETY:
1337 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
1338 * RETURNS:
1339 * Returns NULL if the function succeeds.
1340 * Returns a Socket Error if the function fails in
1341 * a non-fatal way.
1342 * Returns a Fatal Error if the function fails in an unrecoverable way.
1344 PKIX_Error *
1345 pkix_pl_Socket_Create(
1346 PKIX_Boolean isServer,
1347 PRIntervalTime timeout,
1348 PRNetAddr *netAddr,
1349 PRErrorCode *status,
1350 PKIX_PL_Socket **pSocket,
1351 void *plContext)
1353 PKIX_PL_Socket *socket = NULL;
1355 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create");
1356 PKIX_NULLCHECK_ONE(pSocket);
1358 PKIX_CHECK(PKIX_PL_Object_Alloc
1359 (PKIX_SOCKET_TYPE,
1360 sizeof (PKIX_PL_Socket),
1361 (PKIX_PL_Object **)&socket,
1362 plContext),
1363 PKIX_COULDNOTCREATESOCKETOBJECT);
1365 socket->isServer = isServer;
1366 socket->timeout = timeout;
1367 socket->clientSock = NULL;
1368 socket->serverSock = NULL;
1369 socket->netAddr = netAddr;
1371 socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
1372 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
1373 socket->callbackList.connectcontinueCallback =
1374 pkix_pl_Socket_ConnectContinue;
1375 socket->callbackList.sendCallback = pkix_pl_Socket_Send;
1376 socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
1377 socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
1378 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
1380 if (isServer) {
1381 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
1382 PKIX_SOCKETCREATESERVERFAILED);
1383 *status = 0;
1384 } else {
1385 socket->timeout = timeout;
1386 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
1387 PKIX_SOCKETCREATECLIENTFAILED);
1388 PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext),
1389 PKIX_SOCKETCONNECTFAILED);
1392 *pSocket = socket;
1394 cleanup:
1395 if (PKIX_ERROR_RECEIVED) {
1396 PKIX_DECREF(socket);
1399 PKIX_RETURN(SOCKET);
1403 * FUNCTION: pkix_pl_Socket_CreateByName
1404 * DESCRIPTION:
1406 * This function creates a new Socket, setting it to be a server or a client
1407 * according to the value of "isServer", setting its timeout value from
1408 * "timeout" and server address and port number from "serverName", and stores
1409 * the status at "pStatus" and the created Socket at "pSocket".
1411 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
1412 * address of PR_INADDR_ANY.
1414 * PARAMETERS:
1415 * "isServer"
1416 * The Boolean value indicating if PKIX_TRUE, that a server socket (using
1417 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
1418 * client socket (using Connect) is to be created.
1419 * "timeout"
1420 * A PRTimeInterval value to be used for I/O waits for this socket. If
1421 * zero, non-blocking I/O is to be used.
1422 * "serverName"
1423 * Address of a character string consisting of the server's domain name
1424 * followed by a colon and a port number for the desired socket.
1425 * "pStatus"
1426 * Address at which the PRErrorCode resulting from the create is
1427 * stored. Must be non-NULL.
1428 * "pSocket"
1429 * The address at which the Socket is to be stored. Must be non-NULL.
1430 * "plContext"
1431 * Platform-specific context pointer.
1432 * THREAD SAFETY:
1433 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
1434 * RETURNS:
1435 * Returns NULL if the function succeeds.
1436 * Returns a Socket Error if the function fails in
1437 * a non-fatal way.
1438 * Returns a Fatal Error if the function fails in an unrecoverable way.
1440 PKIX_Error *
1441 pkix_pl_Socket_CreateByName(
1442 PKIX_Boolean isServer,
1443 PRIntervalTime timeout,
1444 char *serverName,
1445 PRErrorCode *pStatus,
1446 PKIX_PL_Socket **pSocket,
1447 void *plContext)
1449 PRNetAddr netAddr;
1450 PKIX_PL_Socket *socket = NULL;
1451 char *sepPtr = NULL;
1452 PRHostEnt hostent;
1453 PRIntn hostenum;
1454 PRStatus prstatus = PR_FAILURE;
1455 char buf[PR_NETDB_BUF_SIZE];
1456 PRUint16 portNum = 0;
1457 char *localCopyName = NULL;
1459 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName");
1460 PKIX_NULLCHECK_TWO(serverName, pSocket);
1462 localCopyName = PL_strdup(serverName);
1464 sepPtr = strchr(localCopyName, ':');
1465 /* First strip off the portnum, if present, from the end of the name */
1466 if (sepPtr) {
1467 *sepPtr++ = '\0';
1468 portNum = (PRUint16)atoi(sepPtr);
1469 } else {
1470 portNum = (PRUint16)LDAP_PORT;
1473 prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent);
1475 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
1477 * The hostname may be a fully-qualified name. Try using just
1478 * the leftmost component in our lookup.
1480 sepPtr = strchr(localCopyName, '.');
1481 if (sepPtr) {
1482 *sepPtr++ = '\0';
1484 prstatus = PR_GetHostByName
1485 (localCopyName, buf, sizeof(buf), &hostent);
1487 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
1488 PKIX_ERROR
1489 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
1493 netAddr.inet.family = PR_AF_INET;
1494 netAddr.inet.port = PR_htons(portNum);
1496 if (isServer) {
1498 netAddr.inet.ip = PR_INADDR_ANY;
1500 } else {
1502 hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr);
1503 if (hostenum == -1) {
1504 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
1508 PKIX_CHECK(PKIX_PL_Object_Alloc
1509 (PKIX_SOCKET_TYPE,
1510 sizeof (PKIX_PL_Socket),
1511 (PKIX_PL_Object **)&socket,
1512 plContext),
1513 PKIX_COULDNOTCREATESOCKETOBJECT);
1515 socket->isServer = isServer;
1516 socket->timeout = timeout;
1517 socket->clientSock = NULL;
1518 socket->serverSock = NULL;
1519 socket->netAddr = &netAddr;
1521 socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
1522 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
1523 socket->callbackList.connectcontinueCallback =
1524 pkix_pl_Socket_ConnectContinue;
1525 socket->callbackList.sendCallback = pkix_pl_Socket_Send;
1526 socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
1527 socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
1528 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
1530 if (isServer) {
1531 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
1532 PKIX_SOCKETCREATESERVERFAILED);
1533 *pStatus = 0;
1534 } else {
1535 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
1536 PKIX_SOCKETCREATECLIENTFAILED);
1537 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
1538 PKIX_SOCKETCONNECTFAILED);
1541 *pSocket = socket;
1543 cleanup:
1544 PL_strfree(localCopyName);
1546 if (PKIX_ERROR_RECEIVED) {
1547 PKIX_DECREF(socket);
1550 PKIX_RETURN(SOCKET);
1554 * FUNCTION: pkix_pl_Socket_CreateByHostAndPort
1555 * DESCRIPTION:
1557 * This function creates a new Socket, setting it to be a server or a client
1558 * according to the value of "isServer", setting its timeout value from
1559 * "timeout", host from "hostname", and port number from "portNum", and stores
1560 * the status at "pStatus" and the created Socket at "pSocket".
1562 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
1563 * address of PR_INADDR_ANY.
1565 * PARAMETERS:
1566 * "isServer"
1567 * The Boolean value indicating if PKIX_TRUE, that a server socket (using
1568 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
1569 * client socket (using Connect) is to be created.
1570 * "timeout"
1571 * A PRTimeInterval value to be used for I/O waits for this socket. If
1572 * zero, non-blocking I/O is to be used.
1573 * "hostname"
1574 * Address of a character string consisting of the server's domain name.
1575 * "portNum"
1576 * UInt16 value of the port number for the desired socket.
1577 * "pStatus"
1578 * Address at which the PRErrorCode resulting from the create is
1579 * stored. Must be non-NULL.
1580 * "pSocket"
1581 * The address at which the Socket is to be stored. Must be non-NULL.
1582 * "plContext"
1583 * Platform-specific context pointer.
1584 * THREAD SAFETY:
1585 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
1586 * RETURNS:
1587 * Returns NULL if the function succeeds.
1588 * Returns a Socket Error if the function fails in
1589 * a non-fatal way.
1590 * Returns a Fatal Error if the function fails in an unrecoverable way.
1592 PKIX_Error *
1593 pkix_pl_Socket_CreateByHostAndPort(
1594 PKIX_Boolean isServer,
1595 PRIntervalTime timeout,
1596 char *hostname,
1597 PRUint16 portnum,
1598 PRErrorCode *pStatus,
1599 PKIX_PL_Socket **pSocket,
1600 void *plContext)
1602 PRNetAddr netAddr;
1603 PKIX_PL_Socket *socket = NULL;
1604 char *sepPtr = NULL;
1605 PRHostEnt hostent;
1606 PRIntn hostenum;
1607 PRStatus prstatus = PR_FAILURE;
1608 char buf[PR_NETDB_BUF_SIZE];
1609 char *localCopyName = NULL;
1611 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort");
1612 PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
1615 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
1617 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
1619 * The hostname may be a fully-qualified name. Try using just
1620 * the leftmost component in our lookup.
1622 sepPtr = strchr(hostname, '.');
1623 if (sepPtr) {
1624 *sepPtr++ = '\0';
1626 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
1628 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
1629 PKIX_ERROR
1630 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
1634 netAddr.inet.family = PR_AF_INET;
1635 netAddr.inet.port = PR_htons(portnum);
1637 if (isServer) {
1639 netAddr.inet.ip = PR_INADDR_ANY;
1641 } else {
1643 hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr);
1644 if (hostenum == -1) {
1645 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
1649 PKIX_CHECK(PKIX_PL_Object_Alloc
1650 (PKIX_SOCKET_TYPE,
1651 sizeof (PKIX_PL_Socket),
1652 (PKIX_PL_Object **)&socket,
1653 plContext),
1654 PKIX_COULDNOTCREATESOCKETOBJECT);
1656 socket->isServer = isServer;
1657 socket->timeout = timeout;
1658 socket->clientSock = NULL;
1659 socket->serverSock = NULL;
1660 socket->netAddr = &netAddr;
1662 socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
1663 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
1664 socket->callbackList.connectcontinueCallback =
1665 pkix_pl_Socket_ConnectContinue;
1666 socket->callbackList.sendCallback = pkix_pl_Socket_Send;
1667 socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
1668 socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
1669 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
1671 if (isServer) {
1672 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
1673 PKIX_SOCKETCREATESERVERFAILED);
1674 *pStatus = 0;
1675 } else {
1676 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
1677 PKIX_SOCKETCREATECLIENTFAILED);
1678 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
1679 PKIX_SOCKETCONNECTFAILED);
1682 *pSocket = socket;
1684 cleanup:
1685 if (PKIX_ERROR_RECEIVED) {
1686 PKIX_DECREF(socket);
1689 PKIX_RETURN(SOCKET);
1693 * FUNCTION: pkix_pl_Socket_GetCallbackList
1695 PKIX_Error *
1696 pkix_pl_Socket_GetCallbackList(
1697 PKIX_PL_Socket *socket,
1698 PKIX_PL_Socket_Callback **pCallbackList,
1699 void *plContext)
1701 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList");
1702 PKIX_NULLCHECK_TWO(socket, pCallbackList);
1704 *pCallbackList = &(socket->callbackList);
1706 PKIX_RETURN(SOCKET);
1710 * FUNCTION: pkix_pl_Socket_GetPRFileDesc
1712 PKIX_Error *
1713 pkix_pl_Socket_GetPRFileDesc(
1714 PKIX_PL_Socket *socket,
1715 PRFileDesc **pDesc,
1716 void *plContext)
1718 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc");
1719 PKIX_NULLCHECK_TWO(socket, pDesc);
1721 *pDesc = socket->clientSock;
1723 PKIX_RETURN(SOCKET);