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