| OLD | NEW |
| (Empty) |
| 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 *)NU
LL)); | |
| 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 *)NU
LL)); | |
| 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 PKIX_PL_Socket *socket = NULL; | |
| 1326 | |
| 1327 PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create"); | |
| 1328 PKIX_NULLCHECK_ONE(pSocket); | |
| 1329 | |
| 1330 PKIX_CHECK(PKIX_PL_Object_Alloc | |
| 1331 (PKIX_SOCKET_TYPE, | |
| 1332 sizeof (PKIX_PL_Socket), | |
| 1333 (PKIX_PL_Object **)&socket, | |
| 1334 plContext), | |
| 1335 PKIX_COULDNOTCREATESOCKETOBJECT); | |
| 1336 | |
| 1337 socket->isServer = isServer; | |
| 1338 socket->timeout = timeout; | |
| 1339 socket->clientSock = NULL; | |
| 1340 socket->serverSock = NULL; | |
| 1341 socket->netAddr = netAddr; | |
| 1342 | |
| 1343 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
| 1344 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
| 1345 socket->callbackList.connectcontinueCallback = | |
| 1346 pkix_pl_Socket_ConnectContinue; | |
| 1347 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
| 1348 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
| 1349 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
| 1350 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
| 1351 | |
| 1352 if (isServer) { | |
| 1353 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
| 1354 PKIX_SOCKETCREATESERVERFAILED); | |
| 1355 *status = 0; | |
| 1356 } else { | |
| 1357 socket->timeout = timeout; | |
| 1358 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
| 1359 PKIX_SOCKETCREATECLIENTFAILED); | |
| 1360 PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext), | |
| 1361 PKIX_SOCKETCONNECTFAILED); | |
| 1362 } | |
| 1363 | |
| 1364 *pSocket = socket; | |
| 1365 | |
| 1366 cleanup: | |
| 1367 if (PKIX_ERROR_RECEIVED) { | |
| 1368 PKIX_DECREF(socket); | |
| 1369 } | |
| 1370 | |
| 1371 PKIX_RETURN(SOCKET); | |
| 1372 } | |
| 1373 | |
| 1374 /* | |
| 1375 * FUNCTION: pkix_pl_Socket_CreateByName | |
| 1376 * DESCRIPTION: | |
| 1377 * | |
| 1378 * This function creates a new Socket, setting it to be a server or a client | |
| 1379 * according to the value of "isServer", setting its timeout value from | |
| 1380 * "timeout" and server address and port number from "serverName", and stores | |
| 1381 * the status at "pStatus" and the created Socket at "pSocket". | |
| 1382 * | |
| 1383 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip | |
| 1384 * address of PR_INADDR_ANY. | |
| 1385 * | |
| 1386 * PARAMETERS: | |
| 1387 * "isServer" | |
| 1388 * The Boolean value indicating if PKIX_TRUE, that a server socket (using | |
| 1389 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a | |
| 1390 * client socket (using Connect) is to be created. | |
| 1391 * "timeout" | |
| 1392 * A PRTimeInterval value to be used for I/O waits for this socket. If | |
| 1393 * zero, non-blocking I/O is to be used. | |
| 1394 * "serverName" | |
| 1395 * Address of a character string consisting of the server's domain name | |
| 1396 * followed by a colon and a port number for the desired socket. | |
| 1397 * "pStatus" | |
| 1398 * Address at which the PRErrorCode resulting from the create is | |
| 1399 * stored. Must be non-NULL. | |
| 1400 * "pSocket" | |
| 1401 * The address at which the Socket is to be stored. Must be non-NULL. | |
| 1402 * "plContext" | |
| 1403 * Platform-specific context pointer. | |
| 1404 * THREAD SAFETY: | |
| 1405 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
| 1406 * RETURNS: | |
| 1407 * Returns NULL if the function succeeds. | |
| 1408 * Returns a Socket Error if the function fails in | |
| 1409 * a non-fatal way. | |
| 1410 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
| 1411 */ | |
| 1412 PKIX_Error * | |
| 1413 pkix_pl_Socket_CreateByName( | |
| 1414 PKIX_Boolean isServer, | |
| 1415 PRIntervalTime timeout, | |
| 1416 char *serverName, | |
| 1417 PRErrorCode *pStatus, | |
| 1418 PKIX_PL_Socket **pSocket, | |
| 1419 void *plContext) | |
| 1420 { | |
| 1421 PRNetAddr netAddr; | |
| 1422 PKIX_PL_Socket *socket = NULL; | |
| 1423 char *sepPtr = NULL; | |
| 1424 PRHostEnt hostent; | |
| 1425 PRIntn hostenum; | |
| 1426 PRStatus prstatus = PR_FAILURE; | |
| 1427 char buf[PR_NETDB_BUF_SIZE]; | |
| 1428 PRUint16 portNum = 0; | |
| 1429 char *localCopyName = NULL; | |
| 1430 | |
| 1431 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName"); | |
| 1432 PKIX_NULLCHECK_TWO(serverName, pSocket); | |
| 1433 | |
| 1434 localCopyName = PL_strdup(serverName); | |
| 1435 | |
| 1436 sepPtr = strchr(localCopyName, ':'); | |
| 1437 /* First strip off the portnum, if present, from the end of the name */ | |
| 1438 if (sepPtr) { | |
| 1439 *sepPtr++ = '\0'; | |
| 1440 portNum = (PRUint16)atoi(sepPtr); | |
| 1441 } else { | |
| 1442 portNum = (PRUint16)LDAP_PORT; | |
| 1443 } | |
| 1444 | |
| 1445 prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent); | |
| 1446 | |
| 1447 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
| 1448 /* | |
| 1449 * The hostname may be a fully-qualified name. Try using just | |
| 1450 * the leftmost component in our lookup. | |
| 1451 */ | |
| 1452 sepPtr = strchr(localCopyName, '.'); | |
| 1453 if (sepPtr) { | |
| 1454 *sepPtr++ = '\0'; | |
| 1455 } | |
| 1456 prstatus = PR_GetHostByName | |
| 1457 (localCopyName, buf, sizeof(buf), &hostent); | |
| 1458 | |
| 1459 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
| 1460 PKIX_ERROR | |
| 1461 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); | |
| 1462 } | |
| 1463 } | |
| 1464 | |
| 1465 netAddr.inet.family = PR_AF_INET; | |
| 1466 netAddr.inet.port = PR_htons(portNum); | |
| 1467 | |
| 1468 if (isServer) { | |
| 1469 | |
| 1470 netAddr.inet.ip = PR_INADDR_ANY; | |
| 1471 | |
| 1472 } else { | |
| 1473 | |
| 1474 hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr); | |
| 1475 if (hostenum == -1) { | |
| 1476 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); | |
| 1477 } | |
| 1478 } | |
| 1479 | |
| 1480 PKIX_CHECK(PKIX_PL_Object_Alloc | |
| 1481 (PKIX_SOCKET_TYPE, | |
| 1482 sizeof (PKIX_PL_Socket), | |
| 1483 (PKIX_PL_Object **)&socket, | |
| 1484 plContext), | |
| 1485 PKIX_COULDNOTCREATESOCKETOBJECT); | |
| 1486 | |
| 1487 socket->isServer = isServer; | |
| 1488 socket->timeout = timeout; | |
| 1489 socket->clientSock = NULL; | |
| 1490 socket->serverSock = NULL; | |
| 1491 socket->netAddr = &netAddr; | |
| 1492 | |
| 1493 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
| 1494 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
| 1495 socket->callbackList.connectcontinueCallback = | |
| 1496 pkix_pl_Socket_ConnectContinue; | |
| 1497 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
| 1498 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
| 1499 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
| 1500 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
| 1501 | |
| 1502 if (isServer) { | |
| 1503 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
| 1504 PKIX_SOCKETCREATESERVERFAILED); | |
| 1505 *pStatus = 0; | |
| 1506 } else { | |
| 1507 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
| 1508 PKIX_SOCKETCREATECLIENTFAILED); | |
| 1509 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), | |
| 1510 PKIX_SOCKETCONNECTFAILED); | |
| 1511 } | |
| 1512 | |
| 1513 *pSocket = socket; | |
| 1514 | |
| 1515 cleanup: | |
| 1516 PL_strfree(localCopyName); | |
| 1517 | |
| 1518 if (PKIX_ERROR_RECEIVED) { | |
| 1519 PKIX_DECREF(socket); | |
| 1520 } | |
| 1521 | |
| 1522 PKIX_RETURN(SOCKET); | |
| 1523 } | |
| 1524 | |
| 1525 /* | |
| 1526 * FUNCTION: pkix_pl_Socket_CreateByHostAndPort | |
| 1527 * DESCRIPTION: | |
| 1528 * | |
| 1529 * This function creates a new Socket, setting it to be a server or a client | |
| 1530 * according to the value of "isServer", setting its timeout value from | |
| 1531 * "timeout", host from "hostname", and port number from "portNum", and stores | |
| 1532 * the status at "pStatus" and the created Socket at "pSocket". | |
| 1533 * | |
| 1534 * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip | |
| 1535 * address of PR_INADDR_ANY. | |
| 1536 * | |
| 1537 * PARAMETERS: | |
| 1538 * "isServer" | |
| 1539 * The Boolean value indicating if PKIX_TRUE, that a server socket (using | |
| 1540 * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a | |
| 1541 * client socket (using Connect) is to be created. | |
| 1542 * "timeout" | |
| 1543 * A PRTimeInterval value to be used for I/O waits for this socket. If | |
| 1544 * zero, non-blocking I/O is to be used. | |
| 1545 * "hostname" | |
| 1546 * Address of a character string consisting of the server's domain name. | |
| 1547 * "portNum" | |
| 1548 * UInt16 value of the port number for the desired socket. | |
| 1549 * "pStatus" | |
| 1550 * Address at which the PRErrorCode resulting from the create is | |
| 1551 * stored. Must be non-NULL. | |
| 1552 * "pSocket" | |
| 1553 * The address at which the Socket is to be stored. Must be non-NULL. | |
| 1554 * "plContext" | |
| 1555 * Platform-specific context pointer. | |
| 1556 * THREAD SAFETY: | |
| 1557 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
| 1558 * RETURNS: | |
| 1559 * Returns NULL if the function succeeds. | |
| 1560 * Returns a Socket Error if the function fails in | |
| 1561 * a non-fatal way. | |
| 1562 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
| 1563 */ | |
| 1564 PKIX_Error * | |
| 1565 pkix_pl_Socket_CreateByHostAndPort( | |
| 1566 PKIX_Boolean isServer, | |
| 1567 PRIntervalTime timeout, | |
| 1568 char *hostname, | |
| 1569 PRUint16 portnum, | |
| 1570 PRErrorCode *pStatus, | |
| 1571 PKIX_PL_Socket **pSocket, | |
| 1572 void *plContext) | |
| 1573 { | |
| 1574 PRNetAddr netAddr; | |
| 1575 PKIX_PL_Socket *socket = NULL; | |
| 1576 char *sepPtr = NULL; | |
| 1577 PRHostEnt hostent; | |
| 1578 PRIntn hostenum; | |
| 1579 PRStatus prstatus = PR_FAILURE; | |
| 1580 char buf[PR_NETDB_BUF_SIZE]; | |
| 1581 | |
| 1582 PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort"); | |
| 1583 PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); | |
| 1584 | |
| 1585 | |
| 1586 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent); | |
| 1587 | |
| 1588 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
| 1589 /* | |
| 1590 * The hostname may be a fully-qualified name. Try using just | |
| 1591 * the leftmost component in our lookup. | |
| 1592 */ | |
| 1593 sepPtr = strchr(hostname, '.'); | |
| 1594 if (sepPtr) { | |
| 1595 *sepPtr++ = '\0'; | |
| 1596 } | |
| 1597 prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent
); | |
| 1598 | |
| 1599 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { | |
| 1600 PKIX_ERROR | |
| 1601 (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); | |
| 1602 } | |
| 1603 } | |
| 1604 | |
| 1605 netAddr.inet.family = PR_AF_INET; | |
| 1606 netAddr.inet.port = PR_htons(portnum); | |
| 1607 | |
| 1608 if (isServer) { | |
| 1609 | |
| 1610 netAddr.inet.ip = PR_INADDR_ANY; | |
| 1611 | |
| 1612 } else { | |
| 1613 | |
| 1614 hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr); | |
| 1615 if (hostenum == -1) { | |
| 1616 PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); | |
| 1617 } | |
| 1618 } | |
| 1619 | |
| 1620 PKIX_CHECK(PKIX_PL_Object_Alloc | |
| 1621 (PKIX_SOCKET_TYPE, | |
| 1622 sizeof (PKIX_PL_Socket), | |
| 1623 (PKIX_PL_Object **)&socket, | |
| 1624 plContext), | |
| 1625 PKIX_COULDNOTCREATESOCKETOBJECT); | |
| 1626 | |
| 1627 socket->isServer = isServer; | |
| 1628 socket->timeout = timeout; | |
| 1629 socket->clientSock = NULL; | |
| 1630 socket->serverSock = NULL; | |
| 1631 socket->netAddr = &netAddr; | |
| 1632 | |
| 1633 socket->callbackList.listenCallback = pkix_pl_Socket_Listen; | |
| 1634 socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; | |
| 1635 socket->callbackList.connectcontinueCallback = | |
| 1636 pkix_pl_Socket_ConnectContinue; | |
| 1637 socket->callbackList.sendCallback = pkix_pl_Socket_Send; | |
| 1638 socket->callbackList.recvCallback = pkix_pl_Socket_Recv; | |
| 1639 socket->callbackList.pollCallback = pkix_pl_Socket_Poll; | |
| 1640 socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; | |
| 1641 | |
| 1642 if (isServer) { | |
| 1643 PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), | |
| 1644 PKIX_SOCKETCREATESERVERFAILED); | |
| 1645 *pStatus = 0; | |
| 1646 } else { | |
| 1647 PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), | |
| 1648 PKIX_SOCKETCREATECLIENTFAILED); | |
| 1649 PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), | |
| 1650 PKIX_SOCKETCONNECTFAILED); | |
| 1651 } | |
| 1652 | |
| 1653 *pSocket = socket; | |
| 1654 | |
| 1655 cleanup: | |
| 1656 if (PKIX_ERROR_RECEIVED) { | |
| 1657 PKIX_DECREF(socket); | |
| 1658 } | |
| 1659 | |
| 1660 PKIX_RETURN(SOCKET); | |
| 1661 } | |
| 1662 | |
| 1663 /* | |
| 1664 * FUNCTION: pkix_pl_Socket_GetCallbackList | |
| 1665 */ | |
| 1666 PKIX_Error * | |
| 1667 pkix_pl_Socket_GetCallbackList( | |
| 1668 PKIX_PL_Socket *socket, | |
| 1669 PKIX_PL_Socket_Callback **pCallbackList, | |
| 1670 void *plContext) | |
| 1671 { | |
| 1672 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList"); | |
| 1673 PKIX_NULLCHECK_TWO(socket, pCallbackList); | |
| 1674 | |
| 1675 *pCallbackList = &(socket->callbackList); | |
| 1676 | |
| 1677 PKIX_RETURN(SOCKET); | |
| 1678 } | |
| 1679 | |
| 1680 /* | |
| 1681 * FUNCTION: pkix_pl_Socket_GetPRFileDesc | |
| 1682 */ | |
| 1683 PKIX_Error * | |
| 1684 pkix_pl_Socket_GetPRFileDesc( | |
| 1685 PKIX_PL_Socket *socket, | |
| 1686 PRFileDesc **pDesc, | |
| 1687 void *plContext) | |
| 1688 { | |
| 1689 PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc"); | |
| 1690 PKIX_NULLCHECK_TWO(socket, pDesc); | |
| 1691 | |
| 1692 *pDesc = socket->clientSock; | |
| 1693 | |
| 1694 PKIX_RETURN(SOCKET); | |
| 1695 } | |
| OLD | NEW |