tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_pl_socket.c (54293B)


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