PageRenderTime 118ms CodeModel.GetById 27ms app.highlight 81ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c

https://bitbucket.org/dineshkummarc/mozilla-1.9.0-win64
C | 1723 lines | 931 code | 203 blank | 589 comment | 157 complexity | 7ca7b61521ef18f809afc31f14ac3276 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file