summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c')
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c1695
1 files changed, 1695 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
new file mode 100644
index 000000000..e8698376b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
@@ -0,0 +1,1695 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_socket.c
+ *
+ * Socket Function Definitions
+ *
+ */
+
+/*
+ * If Socket Tracing is active, messages sent and received will be
+ * timestamped and dumped (to stdout) in standard hex-dump format. E.g.,
+ *
+ * 1116612359156140:
+ * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!.
+ *
+ * The timestamp is not formatted to be meaningful except as an increasing
+ * value of seconds.microseconds, which is good enough to correlate two
+ * sides of a message exchange and to figure durations.
+ *
+ * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE
+ * is defined, but that doesn't mean socket tracing is active. Tracing also
+ * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is
+ * the default value, but it can be overridden by using the debugger to
+ * change its value -- allowing tracing to be turned on and off at various
+ * breakpoints -- or by setting the environment variable SOCKETTRACE. A
+ * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other
+ * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment
+ * value is checked during system initialization.
+ */
+#ifndef BUILD_OPT
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#ifdef PKIX_SOCKETDEBUG
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#include "pkix_pl_socket.h"
+
+/* --Private-Socket-Functions---------------------------------- */
+
+#ifdef PKIX_SOCKETTRACE
+static PKIX_Boolean socketTraceFlag = PKIX_FALSE;
+
+/*
+ * FUNCTION: pkix_pl_socket_timestamp
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the time of day, as obtained from the
+ * system function gettimeofday, as seconds.microseconds. Its resolution
+ * is whatever the system call provides.
+ *
+ * PARAMETERS:
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_timestamp() {
+ PRInt64 prTime;
+ prTime = PR_Now();
+/* We shouldn't use PR_ALTERNATE_INT64_TYPEDEF, but nor can we use PRId64 */
+#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF)
+ printf("%ld:\n", prTime);
+#else
+ printf("%lld:\n", prTime);
+#endif
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_hexDigit
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the byte "byteVal" as two hex digits.
+ *
+ * PARAMETERS:
+ * "byteVal"
+ * The value to be printed.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_hexDigit(char byteVal) {
+ int n = 0;
+ char cHi = '\0';
+ char cLow = '\0';
+ n = ((byteVal >> 4) & 0xf);
+ if (n > 9) {
+ cHi = (char) ((n - 10) + 'A');
+ } else {
+ cHi = (char) (n + '0');
+ }
+ n = byteVal & 0xf;
+ if (n > 9) {
+ cLow = (char) ((n - 10) + 'A');
+ } else {
+ cLow = (char) (n + '0');
+ }
+ (void) printf("%c%c", cHi, cLow);
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_linePrefix
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the address provided by "addr" as four
+ * hexadecimal digits followed by a colon and a space.
+ *
+ * PARAMETERS:
+ * "addr"
+ * The address to be printed
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) {
+ pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff));
+ pkix_pl_socket_hexDigit((char)(addr & 0xff));
+ (void) printf(": ");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_traceLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the sixteen bytes beginning at the
+ * address pointed to by "ptr". The bytes are printed as sixteen pairs
+ * of hexadecimal characters followed by an ascii interpretation, in which
+ * characters from 0x20 to 0x7d are shown as their ascii equivalents, and
+ * other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_traceLine(char *ptr) {
+ PKIX_UInt32 i = 0;
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ for (i = 0; i < 16; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < 16; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracePartialLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning at the address pointed to by "ptr". The bytes are printed as
+ * pairs of hexadecimal characters followed by an ascii interpretation, in
+ * which characters from 0x20 to 0x7d are shown as their ascii equivalents,
+ * and other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * "nBytes"
+ * The Int32 value giving the number of bytes to be printed. If "nBytes"
+ * is greater than sixteen, the results will be unattractive.
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 i = 0;
+ if (nBytes > 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ }
+ for (i = 0; i < nBytes; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ for (i = nBytes; i < 16; i++) {
+ printf(" ");
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < nBytes; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracebuff
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning with the byte pointed to by "buf". The output is preceded by
+ * a timestamp, and each group of sixteen (and a remainder, if any) is
+ * preceded by its address. The contents are shown in hexadecimal and as
+ * ascii characters. If "nBytes" is zero, the timestamp and starting
+ * address are displayed.
+ *
+ * PARAMETERS:
+ * "buf"
+ * The starting address of the bytes to be printed
+ * "nBytes"
+ * The number of bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 bytesRemaining = nBytes;
+ PKIX_UInt32 offset = 0;
+ char *bufptr = (char *)buf;
+
+ if (socketTraceFlag == PKIX_FALSE) return;
+
+ pkix_pl_socket_timestamp();
+ /*
+ * Special case: if called with length of zero, just do address
+ */
+ if (nBytes == 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)buf - (char *)NULL));
+ printf("\n");
+ } else {
+ while (bytesRemaining >= 16) {
+ pkix_pl_socket_traceLine(&bufptr[offset]);
+ bytesRemaining -= 16;
+ offset += 16;
+ }
+ pkix_pl_socket_tracePartialLine
+ (&bufptr[offset], bytesRemaining);
+ }
+}
+
+#endif
+
+/*
+ * FUNCTION: pkix_pl_Socket_SetNonBlocking
+ * DESCRIPTION:
+ *
+ * This functions sets the socket represented by the PRFileDesc "fileDesc"
+ * to nonblocking mode.
+ *
+ * PARAMETERS:
+ * "fileDesc"
+ * The address of the PRFileDesc whose I/O mode is to be set
+ * non-blocking. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_SetNonBlocking(
+ PRFileDesc *fileDesc,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking");
+ PKIX_NULLCHECK_ONE(fileDesc);
+
+ sockOptionData.option = PR_SockOpt_Nonblocking;
+ sockOptionData.value.non_blocking = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption,
+ (fileDesc, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateClient
+ * DESCRIPTION:
+ *
+ * This functions creates a client socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * client socket is set to use nonblocking I/O.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a client socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+
+static PKIX_Error *
+pkix_pl_Socket_CreateClient(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRFileDesc *mySock = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ());
+ if (!mySock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateClient: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", mySock);
+#endif
+
+ socket->clientSock = mySock;
+ socket->status = SOCKET_UNCONNECTED;
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateServer
+ * DESCRIPTION:
+ *
+ * This functions creates a server socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * server socket is set to use nonblocking I/O.
+ *
+ * Warning: there seems to be a problem with operating a server socket in
+ * non-blocking mode. If the server calls Recv prior to a corresponding
+ * Send, the message may be lost.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a server socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_CreateServer(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+/* #ifdef PKIX_SOCKETDEBUG */
+ PRErrorCode errorcode = 0;
+/* #endif */
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *serverSock = NULL;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ());
+ if (!serverSock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+ socket->serverSock = serverSock;
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", serverSock);
+#endif
+
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ sockOptionData.option = PR_SockOpt_Reuseaddr;
+ sockOptionData.value.reuse_addr = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption,
+ (serverSock, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr));
+
+ if (rv == PR_FAILURE) {
+/* #ifdef PKIX_SOCKETDEBUG */
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+/* #endif */
+ PKIX_ERROR(PKIX_PRBINDFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful bind!\n");
+#endif
+
+ socket->status = SOCKET_BOUND;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Connect
+ * DESCRIPTION:
+ *
+ * This functions performs the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be performed.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Connect(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect,
+ (socket->clientSock, socket->netAddr, socket->timeout));
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ socket->status = SOCKET_CONNECTPENDING;
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Connect: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This functions continues the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus". It is expected that
+ * the non-blocking connect has returned PR_IN_PROGRESS_ERROR.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be continued.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_ConnectContinue(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ pollDesc.fd = socket->clientSock;
+ pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ pollDesc.out_flags = 0;
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+
+ if (numEvents == 0) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue,
+ (socket->clientSock, pollDesc.out_flags));
+
+ /*
+ * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS
+ * even though the connection is not yet ready. But its deceit
+ * is betrayed by the contents of out_flags!
+ */
+ if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_ConnectContinue: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTANSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ if (socket->isServer) {
+ if (socket->serverSock) {
+ PR_Close(socket->serverSock);
+ }
+ } else {
+ if (socket->clientSock) {
+ PR_Close(socket->clientSock);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ *pHashcode = (((socket->timeout << 3) +
+ (socket->netAddr->inet.family << 3)) +
+ (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) +
+ socket->netAddr->inet.port;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_Socket *firstSocket = NULL;
+ PKIX_PL_Socket *secondSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ firstSocket = (PKIX_PL_Socket *)firstObject;
+ secondSocket = (PKIX_PL_Socket *)secondObject;
+
+ if (firstSocket->timeout != secondSocket->timeout) {
+ goto cleanup;
+ }
+
+ if (firstSocket->netAddr == secondSocket->netAddr) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ if ((firstSocket->netAddr->inet.family !=
+ secondSocket->netAddr->inet.family) ||
+ (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) !=
+ *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) ||
+ (firstSocket->netAddr->inet.port !=
+ secondSocket->netAddr->inet.port)) {
+
+ goto cleanup;
+
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_SOCKET_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Socket_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf");
+
+ entry.description = "Socket";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Socket);
+ entry.destructor = pkix_pl_Socket_Destroy;
+ entry.equalsFunction = pkix_pl_Socket_Equals;
+ entry.hashcodeFunction = pkix_pl_Socket_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_SOCKET_TYPE] = entry;
+
+#ifdef PKIX_SOCKETTRACE
+ {
+ char *val = NULL;
+ val = PR_GetEnvSecure("SOCKETTRACE");
+ /* Is SOCKETTRACE set in the environment? */
+ if ((val != NULL) && (*val != '\0')) {
+ socketTraceFlag =
+ ((*val == '1')?PKIX_TRUE:PKIX_FALSE);
+ }
+ }
+#endif
+
+ PKIX_RETURN(SOCKET);
+}
+
+/* --Public-Socket-Functions----------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Socket_Listen
+ * DESCRIPTION:
+ *
+ * This functions establishes a listening queue for the server Socket
+ * pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the server socket for which the queue is to be
+ * established. Must be non-NULL.
+ * "backlog"
+ * The UInt32 value of the length of the queue to be established.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Listen(
+ PKIX_PL_Socket *socket,
+ PKIX_UInt32 backlog,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen");
+ PKIX_NULLCHECK_TWO(socket, socket->serverSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen,
+ (socket->serverSock, (PRIntn)backlog));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Listen: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRLISTENFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful listen!\n");
+#endif
+
+ socket->status = SOCKET_LISTENING;
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Shutdown
+ * DESCRIPTION:
+ *
+ * This functions performs the shutdown of any connections controlled by the
+ * socket pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the socket to be shut down. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Shutdown(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *fileDesc = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown");
+ PKIX_NULLCHECK_ONE(socket);
+
+ fileDesc =
+ (socket->isServer)?(socket->serverSock):(socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown,
+ (fileDesc, PR_SHUTDOWN_BOTH));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Shutdown: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSHUTDOWNFAILED);
+ }
+ socket->status = SOCKET_SHUTDOWN;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Send
+ * DESCRIPTION:
+ *
+ * This functions sends a message using the socket pointed to by "sendSock",
+ * from the buffer pointed to by "buf", of the number of bytes given by
+ * "bytesToWrite", storing the number of bytes actually written at
+ * "pBytesWritten". If "socket" is in non-blocking mode, the send operation
+ * may store -1 at "pBytesWritten" and the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes written.
+ *
+ * PARAMETERS:
+ * "sendSock"
+ * The address of the Socket on which the message is to be sent. Must
+ * be non-NULL.
+ * "buf"
+ * The address of the data to be sent. Must be non-NULL.
+ * "bytesToWrite""
+ * The UInt32 value indicating the number of bytes to write.
+ * "pBytesWritten"
+ * The address at which the Int32 value indicating the number of bytes
+ * actually written is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Send(
+ PKIX_PL_Socket *sendSock,
+ void *buf,
+ PKIX_UInt32 bytesToWrite,
+ PKIX_Int32 *pBytesWritten,
+ void *plContext)
+{
+ PRInt32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send");
+ PKIX_NULLCHECK_TWO(buf, pBytesWritten);
+
+ fd = sendSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send,
+ (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout));
+
+ if (bytesWritten >= 0) {
+ if (sendSock->status == SOCKET_SENDRCVPENDING) {
+ sendSock->status = SOCKET_RCVPENDING;
+ } else {
+ sendSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesWritten);
+#endif
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Send: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSENDFAILED);
+ }
+
+ sendSock->writeBuf = buf;
+ sendSock->writeBufSize = bytesToWrite;
+ if (sendSock->status == SOCKET_RCVPENDING) {
+ sendSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ sendSock->status = SOCKET_SENDPENDING;
+ }
+ }
+
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Recv
+ * DESCRIPTION:
+ *
+ * This functions receives a message on the socket pointed to by "rcvSock",
+ * into the buffer pointed to by "buf", of capacity given by "capacity",
+ * storing the number of bytes actually received at "pBytesRead". If "socket"
+ * is in non-blocking mode, the receive operation may store -1 at
+ * "pBytesWritten". In that case the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes read.
+ *
+ * PARAMETERS:
+ * "rcvSock"
+ * The address of the Socket on which the message is to be received.
+ * Must be non-NULL.
+ * "buf"
+ * The address of the buffer into which the message is to be received.
+ * Must be non-NULL.
+ * "capacity"
+ * The UInt32 value of the size of the buffer; that is, the maximum
+ * number of bytes that can be received.
+ * "pBytesRead"
+ * The address at which is stored the Int32 value of the number of bytes
+ * actually received.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Recv(
+ PKIX_PL_Socket *rcvSock,
+ void *buf,
+ PKIX_UInt32 capacity,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRInt32 bytesRead = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv");
+ PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead);
+
+ fd = rcvSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv,
+ (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout));
+
+ if (bytesRead > 0) {
+ if (rcvSock->status == SOCKET_SENDRCVPENDING) {
+ rcvSock->status = SOCKET_SENDPENDING;
+ } else {
+ rcvSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesRead);
+#endif
+ } else if (bytesRead == 0) {
+ PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED);
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Recv: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRRECVFAILED);
+ }
+ rcvSock->readBuf = buf;
+ rcvSock->readBufSize = capacity;
+ if (rcvSock->status == SOCKET_SENDPENDING) {
+ rcvSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ rcvSock->status = SOCKET_RCVPENDING;
+ }
+
+ }
+
+ *pBytesRead = (PKIX_Int32)bytesRead;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Poll
+ * DESCRIPTION:
+ *
+ * This functions checks for completion of an earlier Send or Recv on the
+ * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes
+ * written by a completed Send and in "pBytesRead" the number of bytes
+ * received in a completed Recv. A value of -1 returned indicates the
+ * operation has still not completed. A NULL pointer may be supplied for
+ * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer
+ * may be supplied for "pBytesRead" to avoid checking for completion of a Recv.
+ *
+ * PARAMETERS:
+ * "sock"
+ * The address of the socket for which completions are to be checked.
+ * "pBytesWritten"
+ * The address at which the number of bytes written is to be stored, if
+ * a pending Send has completed. If NULL, Sends are not checked.
+ * "pBytesRead"
+ * The address at which the number of bytes read is to be stored, if
+ * a pending Recv has completed. If NULL, Recvs are not checked.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Poll(
+ PKIX_PL_Socket *sock,
+ PKIX_Int32 *pBytesWritten,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_Int32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll");
+ PKIX_NULLCHECK_ONE(sock);
+
+ pollDesc.fd = sock->clientSock;
+ pollDesc.in_flags = 0;
+ pollDesc.out_flags = 0;
+
+ if ((pBytesWritten) &&
+ ((sock->status == SOCKET_SENDPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags = PR_POLL_WRITE;
+ }
+
+ if ((pBytesRead) &&
+ ((sock->status == SOCKET_RCVPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags |= PR_POLL_READ;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ } else if (numEvents > 0) {
+ if (pollDesc.out_flags & PR_POLL_WRITE) {
+ PKIX_CHECK(pkix_pl_Socket_Send
+ (sock,
+ sock->writeBuf,
+ sock->writeBufSize,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+ if (bytesWritten >= 0) {
+ sock->writeBuf = NULL;
+ sock->writeBufSize = 0;
+ }
+ }
+
+ if (pollDesc.out_flags & PR_POLL_READ) {
+ PKIX_CHECK(pkix_pl_Socket_Recv
+ (sock,
+ sock->readBuf,
+ sock->readBufSize,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+ *pBytesRead = (PKIX_Int32)bytesRead;
+ if (bytesRead >= 0) {
+ sock->readBuf = NULL;
+ sock->readBufSize = 0;
+ }
+ }
+ } else if (numEvents == 0) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Poll: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+ if (pBytesWritten) {
+ *pBytesWritten = 0;
+ }
+ if (pBytesRead) {
+ *pBytesRead = 0;
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Accept
+ * DESCRIPTION:
+ *
+ * This functions accepts a client connection for the server Socket pointed
+ * to by "serverSocket", creating a new Socket and storing the result at
+ * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this
+ * function will return NULL if there is no client connection to accept.
+ * Otherwise this function will block until a connection is available.
+ * When a client connection is available the new Socket will have the same
+ * blocking/non-blocking property as "serverSocket".
+ *
+ * PARAMETERS:
+ * "serverSocket"
+ * The address of the Socket for which a client connection is to be
+ * accepted. Must be non-NULL.
+ * "pRendezvousSocket"
+ * The address at which the created Socket is stored, when a client
+ * connection is available, or at which NULL is stored, if no connection
+ * is available for a non-blocking "serverSocket". Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Accept(
+ PKIX_PL_Socket *serverSocket,
+ PKIX_PL_Socket **pRendezvousSocket,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRFileDesc *rendezvousSock = NULL;
+ PRNetAddr *clientAddr = NULL;
+ PKIX_PL_Socket *newSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept");
+ PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept,
+ (serverSocket->serverSock, clientAddr, serverSocket->timeout));
+
+ if (!rendezvousSock) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Accept: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRACCEPTFAILED);
+ }
+ serverSocket->status = SOCKET_ACCEPTPENDING;
+ *pRendezvousSocket = NULL;
+ goto cleanup;
+
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful accept!\n");
+#endif
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&newSocket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ newSocket->isServer = PKIX_FALSE;
+ newSocket->timeout = serverSocket->timeout;
+ newSocket->clientSock = rendezvousSock;
+ newSocket->serverSock = NULL;
+ newSocket->netAddr = NULL;
+ newSocket->status = SOCKET_CONNECTED;
+ newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+ newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ newSocket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ newSocket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+
+ if (serverSocket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking
+ (rendezvousSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ *pRendezvousSocket = newSocket;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address from "netAddr", and stores the created Socket
+ * at "pSocket".
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "netAddr"
+ * The PRNetAddr to be used for the Bind function, if this is a server
+ * socket, or for the Connect, if this is a client socket.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_Create(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ PRNetAddr *netAddr,
+ PRErrorCode *status,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create");
+ PKIX_NULLCHECK_ONE(pSocket);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *status = 0;
+ } else {
+ socket->timeout = timeout;
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByName
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address and port number from "serverName", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "serverName"
+ * Address of a character string consisting of the server's domain name
+ * followed by a colon and a port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_CreateByName(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *serverName,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRUint16 portNum = 0;
+ char *localCopyName = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName");
+ PKIX_NULLCHECK_TWO(serverName, pSocket);
+
+ localCopyName = PL_strdup(serverName);
+
+ sepPtr = strchr(localCopyName, ':');
+ /* First strip off the portnum, if present, from the end of the name */
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ portNum = (PRUint16)atoi(sepPtr);
+ } else {
+ portNum = (PRUint16)LDAP_PORT;
+ }
+
+ prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(localCopyName, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName
+ (localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portNum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_INADDR_ANY;
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ PL_strfree(localCopyName);
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByHostAndPort
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout", host from "hostname", and port number from "portNum", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "hostname"
+ * Address of a character string consisting of the server's domain name.
+ * "portNum"
+ * UInt16 value of the port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_CreateByHostAndPort(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort");
+ PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
+
+
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(hostname, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portnum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_INADDR_ANY;
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetCallbackList
+ */
+PKIX_Error *
+pkix_pl_Socket_GetCallbackList(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket_Callback **pCallbackList,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList");
+ PKIX_NULLCHECK_TWO(socket, pCallbackList);
+
+ *pCallbackList = &(socket->callbackList);
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetPRFileDesc
+ */
+PKIX_Error *
+pkix_pl_Socket_GetPRFileDesc(
+ PKIX_PL_Socket *socket,
+ PRFileDesc **pDesc,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc");
+ PKIX_NULLCHECK_TWO(socket, pDesc);
+
+ *pDesc = socket->clientSock;
+
+ PKIX_RETURN(SOCKET);
+}