| /* 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); |
| } |