| Index: nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
|
| ===================================================================
|
| --- nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c (revision 0)
|
| +++ nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c (revision 0)
|
| @@ -0,0 +1,1723 @@
|
| +/* ***** BEGIN LICENSE BLOCK *****
|
| + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
| + *
|
| + * The contents of this file are subject to the Mozilla Public License Version
|
| + * 1.1 (the "License"); you may not use this file except in compliance with
|
| + * the License. You may obtain a copy of the License at
|
| + * http://www.mozilla.org/MPL/
|
| + *
|
| + * Software distributed under the License is distributed on an "AS IS" basis,
|
| + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
| + * for the specific language governing rights and limitations under the
|
| + * License.
|
| + *
|
| + * The Original Code is the PKIX-C library.
|
| + *
|
| + * The Initial Developer of the Original Code is
|
| + * Sun Microsystems, Inc.
|
| + * Portions created by the Initial Developer are
|
| + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
|
| + *
|
| + * Contributor(s):
|
| + * Sun Microsystems, Inc.
|
| + *
|
| + * Alternatively, the contents of this file may be used under the terms of
|
| + * either the GNU General Public License Version 2 or later (the "GPL"), or
|
| + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
| + * in which case the provisions of the GPL or the LGPL are applicable instead
|
| + * of those above. If you wish to allow use of your version of this file only
|
| + * under the terms of either the GPL or the LGPL, and not to allow others to
|
| + * use your version of this file under the terms of the MPL, indicate your
|
| + * decision by deleting the provisions above and replace them with the notice
|
| + * and other provisions required by the GPL or the LGPL. If you do not delete
|
| + * the provisions above, a recipient may use your version of this file under
|
| + * the terms of any one of the MPL, the GPL or the LGPL.
|
| + *
|
| + * ***** END LICENSE BLOCK ***** */
|
| +/*
|
| + * 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();
|
| + printf("%lld:\n", prTime);
|
| +}
|
| +
|
| +/*
|
| + * 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)ptr);
|
| + 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)ptr);
|
| + }
|
| + 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)buf);
|
| + 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_GetEnv("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);
|
| +}
|
|
|
| Property changes on: nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|