1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * The contents of this file are subject to the Netscape Public 8 * License Version 1.1 (the "License"); you may not use this file 9 * except in compliance with the License. You may obtain a copy of 10 * the License at http://www.mozilla.org/NPL/ 11 * 12 * Software distributed under the License is distributed on an "AS 13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 * implied. See the License for the specific language governing 15 * rights and limitations under the License. 16 * 17 * The Original Code is Mozilla Communicator client code, released 18 * March 31, 1998. 19 * 20 * The Initial Developer of the Original Code is Netscape 21 * Communications Corporation. Portions created by Netscape are 22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 23 * Rights Reserved. 24 * 25 * Contributor(s): 26 */ 27 28 /* 29 * Extended I/O callback functions for libldap that use 30 * NSPR (Netscape Portable Runtime) I/O. 31 * 32 * High level strategy: we use the socket-specific arg to hold our own data 33 * structure that includes the NSPR file handle (PRFileDesc *), among other 34 * useful information. We use the default argument to hold an LDAP session 35 * handle specific data structure. 36 */ 37 38 #include "ldappr-int.h" 39 #include <string.h> 40 41 #define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */ 42 43 /* 44 * Local function prototypes: 45 */ 46 static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout ); 47 static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize, 48 struct lextiof_socket_private *socketarg ); 49 static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len, 50 struct lextiof_socket_private *socketarg ); 51 static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds, 52 int timeout, struct lextiof_session_private *sessionarg ); 53 static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport, 54 int timeout, unsigned long options, 55 struct lextiof_session_private *sessionarg, 56 struct lextiof_socket_private **socketargp 57 #ifdef _SOLARIS_SDK 58 , void **dhost ); 59 #else 60 ); 61 #endif /* _SOLARIS_SDK */ 62 static int LDAP_CALLBACK prldap_close( int s, 63 struct lextiof_socket_private *socketarg ); 64 static int LDAP_CALLBACK prldap_newhandle( LDAP *ld, 65 struct lextiof_session_private *sessionarg ); 66 static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld, 67 struct lextiof_session_private *sessionarg ); 68 static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld, 69 struct lextiof_session_private *sessionarg ); 70 static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld, 71 struct lextiof_session_private *sessionarg ); 72 static PRLDAPIOSessionArg *prldap_session_arg_alloc( void ); 73 static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp ); 74 static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg ); 75 static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp ); 76 static void *prldap_safe_realloc( void *ptr, PRUint32 size ); 77 78 79 80 /* 81 * Local macros: 82 */ 83 /* given a socket-specific arg, return the corresponding PRFileDesc * */ 84 #define PRLDAP_GET_PRFD( socketarg ) \ 85 (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd) 86 87 /* 88 * Static variables. 89 */ 90 static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT; 91 92 /* 93 * Install NSPR I/O functions into ld (if ld is NULL, they are installed 94 * as the default functions for new LDAP * handles). 95 * 96 * Returns 0 if all goes well and -1 if not. 97 */ 98 int 99 prldap_install_io_functions( LDAP *ld, int shared ) 100 { 101 struct ldap_x_ext_io_fns iofns; 102 103 memset( &iofns, 0, sizeof(iofns)); 104 iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 105 iofns.lextiof_read = prldap_read; 106 iofns.lextiof_write = prldap_write; 107 iofns.lextiof_poll = prldap_poll; 108 iofns.lextiof_connect = prldap_connect; 109 iofns.lextiof_close = prldap_close; 110 if ( shared ) { 111 iofns.lextiof_newhandle = prldap_shared_newhandle; 112 iofns.lextiof_disposehandle = prldap_shared_disposehandle; 113 } else { 114 iofns.lextiof_newhandle = prldap_newhandle; 115 iofns.lextiof_disposehandle = prldap_disposehandle; 116 } 117 if ( NULL != ld ) { 118 /* 119 * If we are dealing with a real ld, we allocate the session specific 120 * data structure now. If not allocated here, it will be allocated 121 * inside prldap_newhandle() or prldap_shared_newhandle(). 122 */ 123 if ( NULL == 124 ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) { 125 ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL ); 126 return( -1 ); 127 } 128 } else { 129 iofns.lextiof_session_arg = NULL; 130 } 131 132 if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) { 133 prldap_session_arg_free( 134 (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg ); 135 return( -1 ); 136 } 137 138 return( 0 ); 139 } 140 141 142 static PRIntervalTime 143 prldap_timeout2it( int ms_timeout, int ms_maxtimeout ) 144 { 145 PRIntervalTime prit; 146 147 if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) { 148 prit = PR_INTERVAL_NO_WAIT; 149 } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) { 150 prit = PR_INTERVAL_NO_TIMEOUT; 151 } else { 152 prit = PR_MillisecondsToInterval( ms_timeout ); 153 } 154 155 /* cap at maximum I/O timeout */ 156 if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) { 157 prit = LDAP_X_IO_TIMEOUT_NO_WAIT; 158 } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) { 159 if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout || 160 ms_timeout > ms_maxtimeout ) { 161 prit = PR_MillisecondsToInterval( ms_maxtimeout ); 162 } 163 } 164 165 #ifdef PRLDAP_DEBUG 166 if ( PR_INTERVAL_NO_WAIT == prit ) { 167 fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" ); 168 } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) { 169 fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" ); 170 } else { 171 fprintf( stderr, "prldap_timeout2it: %dms\n", 172 PR_IntervalToMilliseconds(prit)); 173 } 174 #endif /* PRLDAP_DEBUG */ 175 176 return( prit ); 177 } 178 179 180 static int LDAP_CALLBACK 181 prldap_read( int s, void *buf, int bufsize, 182 struct lextiof_socket_private *socketarg ) 183 { 184 PRIntervalTime prit; 185 186 prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT, 187 socketarg->prsock_io_max_timeout ); 188 return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit )); 189 } 190 191 192 static int LDAP_CALLBACK 193 prldap_write( int s, const void *buf, int len, 194 struct lextiof_socket_private *socketarg ) 195 { 196 PRIntervalTime prit; 197 198 prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT, 199 socketarg->prsock_io_max_timeout ); 200 201 /* 202 * Note the 4th parameter (flags) to PR_Send() has been obsoleted and 203 * must always be 0 204 */ 205 return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit )); 206 } 207 208 209 struct prldap_eventmap_entry { 210 PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */ 211 int evm_ldap; /* LDAP poll event */ 212 }; 213 214 static struct prldap_eventmap_entry prldap_eventmap[] = { 215 { PR_POLL_READ, LDAP_X_POLLIN }, 216 { PR_POLL_EXCEPT, LDAP_X_POLLPRI }, 217 { PR_POLL_WRITE, LDAP_X_POLLOUT }, 218 { PR_POLL_ERR, LDAP_X_POLLERR }, 219 { PR_POLL_HUP, LDAP_X_POLLHUP }, 220 { PR_POLL_NVAL, LDAP_X_POLLNVAL }, 221 }; 222 223 #define PRLDAP_EVENTMAP_ENTRIES \ 224 sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry ) 225 226 static int LDAP_CALLBACK 227 prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout, 228 struct lextiof_session_private *sessionarg ) 229 { 230 PRLDAPIOSessionArg *prsessp = sessionarg; 231 PRPollDesc *pds; 232 int i, j, rc; 233 234 if ( NULL == prsessp ) { 235 prldap_set_system_errno( EINVAL ); 236 return( -1 ); 237 } 238 239 /* allocate or resize NSPR poll descriptor array */ 240 if ( prsessp->prsess_pollds_count < nfds ) { 241 pds = prldap_safe_realloc( prsessp->prsess_pollds, 242 ( nfds + PRLDAP_POLL_ARRAY_GROWTH ) 243 * sizeof( PRPollDesc )); 244 if ( NULL == pds ) { 245 prldap_set_system_errno( prldap_prerr2errno()); 246 return( -1 ); 247 } 248 prsessp->prsess_pollds = pds; 249 prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH; 250 } else { 251 pds = prsessp->prsess_pollds; 252 } 253 254 /* populate NSPR poll info. based on LDAP info. */ 255 for ( i = 0; i < nfds; ++i ) { 256 if ( NULL == fds[i].lpoll_socketarg ) { 257 pds[i].fd = NULL; 258 } else { 259 pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg ); 260 } 261 pds[i].in_flags = pds[i].out_flags = 0; 262 if ( fds[i].lpoll_fd >= 0 ) { 263 for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) { 264 if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap ) 265 != 0 ) { 266 pds[i].in_flags |= prldap_eventmap[j].evm_nspr; 267 } 268 } 269 } 270 fds[i].lpoll_revents = 0; /* clear revents */ 271 } 272 273 /* call PR_Poll() to do the real work */ 274 rc = PR_Poll( pds, nfds, 275 prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout )); 276 277 /* populate LDAP info. based on NSPR results */ 278 for ( i = 0; i < nfds; ++i ) { 279 if ( pds[i].fd != NULL ) { 280 for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) { 281 if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr ) 282 != 0 ) { 283 fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap; 284 } 285 } 286 } 287 } 288 289 return( rc ); 290 } 291 292 293 /* 294 * Utility function to try one TCP connect() 295 * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp. 296 */ 297 static int 298 prldap_try_one_address( struct lextiof_socket_private *prsockp, 299 PRNetAddr *addrp, int port, int timeout, unsigned long options ) 300 { 301 /* 302 * Set up address and open a TCP socket: 303 */ 304 if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */ 305 PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) { 306 return( -1 ); 307 } 308 309 if (( prsockp->prsock_prfd = PR_OpenTCPSocket( 310 PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) { 311 return( -1 ); 312 } 313 314 /* 315 * Set nonblocking option if requested: 316 */ 317 if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) { 318 PRSocketOptionData optdata; 319 320 optdata.option = PR_SockOpt_Nonblocking; 321 optdata.value.non_blocking = PR_TRUE; 322 if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata ) 323 != PR_SUCCESS ) { 324 prldap_set_system_errno( prldap_prerr2errno()); 325 PR_Close( prsockp->prsock_prfd ); 326 return( -1 ); 327 } 328 } 329 330 #ifdef PRLDAP_DEBUG 331 { 332 char buf[ 256 ], *p, *fmtstr; 333 334 if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) { 335 strcpy( buf, "conversion failed!" ); 336 } 337 if ( strncmp( buf, "::ffff:", 7 ) == 0 ) { 338 /* IPv4 address mapped into IPv6 address space */ 339 p = buf + 7; 340 fmtstr = "prldap_try_one_address(): Trying %s:%d...\n"; 341 } else { 342 p = buf; 343 fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n"; 344 } 345 fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port )); 346 } 347 #endif /* PRLDAP_DEBUG */ 348 349 /* 350 * Try to open the TCP connection itself: 351 */ 352 if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp, 353 prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) { 354 PR_Close( prsockp->prsock_prfd ); 355 prsockp->prsock_prfd = NULL; 356 return( -1 ); 357 } 358 359 #ifdef PRLDAP_DEBUG 360 fputs( "prldap_try_one_address(): Connected.\n", stderr ); 361 #endif /* PRLDAP_DEBUG */ 362 363 /* 364 * Success. Return a valid file descriptor (1 is always valid) 365 */ 366 return( 1 ); 367 } 368 369 370 /* 371 * XXXmcs: At present, this code ignores the timeout when doing DNS lookups. 372 */ 373 static int LDAP_CALLBACK 374 prldap_connect( const char *hostlist, int defport, int timeout, 375 unsigned long options, struct lextiof_session_private *sessionarg, 376 struct lextiof_socket_private **socketargp 377 #ifdef _SOLARIS_SDK 378 , void **dhost ) 379 #else 380 ) 381 #endif /* _SOLARIS_SDK */ 382 { 383 int rc, parse_err, port; 384 char *host, hbuf[ PR_NETDB_BUF_SIZE ]; 385 struct ldap_x_hostlist_status *status; 386 struct lextiof_socket_private *prsockp; 387 PRNetAddr addr; 388 PRHostEnt hent; 389 #ifdef _SOLARIS_SDK 390 char *hostname = NULL; 391 char *nsldapi_strdup(char *); 392 #endif /* _SOLARIS_SDK */ 393 394 if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) { 395 prldap_set_system_errno( EINVAL ); 396 return( -1 ); 397 } 398 399 if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) { 400 prldap_set_system_errno( prldap_prerr2errno()); 401 return( -1 ); 402 } 403 404 rc = -1; /* pessimistic */ 405 for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port, 406 &status ); 407 rc < 0 && LDAP_SUCCESS == parse_err && NULL != host; 408 parse_err = ldap_x_hostlist_next( &host, &port, status )) { 409 410 if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) { 411 412 if ( PRLDAP_DEFAULT_ADDRESS_FAMILY == PR_AF_INET6 && 413 PR_AF_INET == PR_NetAddrFamily( &addr )) { 414 PRUint32 ipv4ip = addr.inet.ip; 415 memset( &addr, 0, sizeof(addr)); 416 PR_ConvertIPv4AddrToIPv6( ipv4ip, &addr.ipv6.ip ); 417 addr.ipv6.family = PR_AF_INET6; 418 419 } 420 rc = prldap_try_one_address( prsockp, &addr, port, 421 timeout, options ); 422 } else { 423 if ( PR_SUCCESS == PR_GetIPNodeByName( host, 424 PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT | PR_AI_ALL, hbuf, 425 sizeof( hbuf ), &hent )) { 426 PRIntn enumIndex = 0; 427 428 while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt( 429 enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) { 430 rc = prldap_try_one_address( prsockp, &addr, port, 431 timeout, options ); 432 } 433 } 434 } 435 436 #ifdef _SOLARIS_SDK 437 if ( NULL != hostname ) { 438 ldap_memfree(hostname); 439 hostname = NULL; 440 } 441 if ( rc >= 0 ) { 442 hostname = nsldapi_strdup(host); 443 } 444 #endif /* _SOLARIS_SDK */ 445 ldap_memfree( host ); 446 } 447 448 ldap_x_hostlist_statusfree( status ); 449 450 if ( rc < 0 ) { 451 prldap_set_system_errno( prldap_prerr2errno()); 452 prldap_socket_arg_free( &prsockp ); 453 } else { 454 *socketargp = prsockp; 455 } 456 457 #ifdef _SOLARIS_SDK 458 if ( NULL != hostname && NULL != dhost ) *dhost = hostname; 459 else if ( NULL != hostname ) ldap_memfree(hostname); 460 #endif /* _SOLARIS_SDK */ 461 462 return( rc ); 463 } 464 465 466 static int LDAP_CALLBACK 467 prldap_close( int s, struct lextiof_socket_private *socketarg ) 468 { 469 int rc; 470 471 rc = 0; 472 if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) { 473 rc = -1; 474 prldap_set_system_errno( prldap_prerr2errno()); 475 } 476 prldap_socket_arg_free( &socketarg ); 477 478 return( rc ); 479 } 480 481 482 /* 483 * LDAP session handle creation callback. 484 * 485 * Allocate a session argument if not already done, and then call the 486 * thread's new handle function. 487 */ 488 static int LDAP_CALLBACK 489 prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 490 { 491 492 if ( NULL == sessionarg ) { 493 struct ldap_x_ext_io_fns iofns; 494 495 memset( &iofns, 0, sizeof(iofns)); 496 iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 497 if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 498 (void *)&iofns ) < 0 ) { 499 return( ldap_get_lderrno( ld, NULL, NULL )); 500 } 501 if ( NULL == 502 ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) { 503 return( LDAP_NO_MEMORY ); 504 } 505 if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 506 (void *)&iofns ) < 0 ) { 507 return( ldap_get_lderrno( ld, NULL, NULL )); 508 } 509 } 510 511 return( LDAP_SUCCESS ); 512 } 513 514 515 /* only called/installed if shared is non-zero. */ 516 static int LDAP_CALLBACK 517 prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 518 { 519 int rc; 520 521 if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) { 522 rc = prldap_thread_new_handle( ld, sessionarg ); 523 } 524 525 return( rc ); 526 } 527 528 529 static void LDAP_CALLBACK 530 prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 531 { 532 prldap_session_arg_free( &sessionarg ); 533 } 534 535 536 /* only called/installed if shared is non-zero */ 537 static void LDAP_CALLBACK 538 prldap_shared_disposehandle( LDAP *ld, 539 struct lextiof_session_private *sessionarg ) 540 { 541 prldap_thread_dispose_handle( ld, sessionarg ); 542 prldap_disposehandle( ld, sessionarg ); 543 } 544 545 546 /* 547 * Allocate a session argument. 548 */ 549 static PRLDAPIOSessionArg * 550 prldap_session_arg_alloc( void ) 551 { 552 PRLDAPIOSessionArg *prsessp; 553 554 prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg )); 555 556 if ( NULL != prsessp ) { 557 /* copy global defaults to the new session handle */ 558 prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout; 559 } 560 561 return( prsessp ); 562 } 563 564 565 static void 566 prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp ) 567 { 568 if ( NULL != prsesspp && NULL != *prsesspp ) { 569 if ( NULL != (*prsesspp)->prsess_pollds ) { 570 PR_Free( (*prsesspp)->prsess_pollds ); 571 (*prsesspp)->prsess_pollds = NULL; 572 } 573 PR_Free( *prsesspp ); 574 *prsesspp = NULL; 575 } 576 } 577 578 579 /* 580 * Given an LDAP session handle, retrieve a session argument. 581 * Returns an LDAP error code. 582 */ 583 int 584 prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp ) 585 { 586 struct ldap_x_ext_io_fns iofns; 587 588 if ( NULL == ld || NULL == sessargpp ) { 589 /* XXXmcs: NULL ld's are not supported */ 590 ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 591 return( LDAP_PARAM_ERROR ); 592 } 593 594 memset( &iofns, 0, sizeof(iofns)); 595 iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 596 if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) { 597 return( ldap_get_lderrno( ld, NULL, NULL )); 598 } 599 600 if ( NULL == iofns.lextiof_session_arg ) { 601 ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 602 return( LDAP_LOCAL_ERROR ); 603 } 604 605 *sessargpp = iofns.lextiof_session_arg; 606 return( LDAP_SUCCESS ); 607 } 608 609 610 /* 611 * Given an LDAP session handle, retrieve a socket argument. 612 * Returns an LDAP error code. 613 */ 614 int 615 prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp ) 616 { 617 Sockbuf *sbp; 618 struct lber_x_ext_io_fns extiofns; 619 620 if ( NULL == ld || NULL == sockargpp ) { 621 /* XXXmcs: NULL ld's are not supported */ 622 ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 623 return( LDAP_PARAM_ERROR ); 624 } 625 626 if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) { 627 return( ldap_get_lderrno( ld, NULL, NULL )); 628 } 629 630 memset( &extiofns, 0, sizeof(extiofns)); 631 extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; 632 if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS, 633 (void *)&extiofns ) < 0 ) { 634 return( ldap_get_lderrno( ld, NULL, NULL )); 635 } 636 637 if ( NULL == extiofns.lbextiofn_socket_arg ) { 638 ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 639 return( LDAP_LOCAL_ERROR ); 640 } 641 642 *sockargpp = extiofns.lbextiofn_socket_arg; 643 return( LDAP_SUCCESS ); 644 } 645 646 647 /* 648 * Allocate a socket argument. 649 */ 650 static PRLDAPIOSocketArg * 651 prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg ) 652 { 653 PRLDAPIOSocketArg *prsockp; 654 655 prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg )); 656 657 if ( NULL != prsockp && NULL != sessionarg ) { 658 /* copy socket defaults from the session */ 659 prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout; 660 } 661 662 return( prsockp ); 663 } 664 665 666 static void 667 prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp ) 668 { 669 if ( NULL != prsockpp && NULL != *prsockpp ) { 670 PR_Free( *prsockpp ); 671 *prsockpp = NULL; 672 } 673 } 674 675 676 static void * 677 prldap_safe_realloc( void *ptr, PRUint32 size ) 678 { 679 void *p; 680 681 if ( NULL == ptr ) { 682 p = PR_Malloc( size ); 683 } else { 684 p = PR_Realloc( ptr, size ); 685 } 686 687 return( p ); 688 } 689 690 691 692 /* returns an LDAP result code */ 693 int 694 prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout ) 695 { 696 int rc = LDAP_SUCCESS; /* optimistic */ 697 698 if ( NULL == prsessp ) { 699 prldap_default_io_max_timeout = io_max_timeout; 700 } else { 701 prsessp->prsess_io_max_timeout = io_max_timeout; 702 } 703 704 return( rc ); 705 } 706 707 708 /* returns an LDAP result code */ 709 int 710 prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp ) 711 { 712 int rc = LDAP_SUCCESS; /* optimistic */ 713 714 if ( NULL == io_max_timeoutp ) { 715 rc = LDAP_PARAM_ERROR; 716 } else if ( NULL == prsessp ) { 717 *io_max_timeoutp = prldap_default_io_max_timeout; 718 } else { 719 *io_max_timeoutp = prsessp->prsess_io_max_timeout; 720 } 721 722 return( rc ); 723 } 724