Back to index

lightning-sunbird  0.9+nobinonly
ldappr-io.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Extended I/O callback functions for libldap that use
00040  * NSPR (Netscape Portable Runtime) I/O.
00041  *
00042  * High level strategy: we use the socket-specific arg to hold our own data
00043  * structure that includes the NSPR file handle (PRFileDesc *), among other
00044  * useful information.  We use the default argument to hold an LDAP session
00045  * handle specific data structure.
00046  */
00047 
00048 #include "ldappr-int.h"
00049 
00050 #define PRLDAP_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
00051 
00052 /*
00053  * Local function prototypes:
00054  */
00055 static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
00056 static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
00057        struct lextiof_socket_private *socketarg );
00058 static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
00059        struct lextiof_socket_private *socketarg );
00060 static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
00061        int timeout, struct lextiof_session_private *sessionarg );
00062 static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
00063        int timeout, unsigned long options,
00064        struct lextiof_session_private *sessionarg,
00065        struct lextiof_socket_private **socketargp );
00066 static int LDAP_CALLBACK prldap_close( int s,
00067        struct lextiof_socket_private *socketarg );
00068 static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
00069        struct lextiof_session_private *sessionarg );
00070 static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
00071        struct lextiof_session_private *sessionarg );
00072 static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
00073        struct lextiof_session_private *sessionarg );
00074 static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
00075        struct lextiof_session_private *sessionarg );
00076 static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
00077 static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
00078 static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
00079 static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
00080 static void *prldap_safe_realloc( void *ptr, PRUint32 size );
00081 
00082 
00083 
00084 /*
00085  * Local macros:
00086  */
00087 /* given a socket-specific arg, return the corresponding PRFileDesc * */
00088 #define PRLDAP_GET_PRFD( socketarg )      \
00089               (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
00090 
00091 /*
00092  * Static variables.
00093  */
00094 static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
00095 
00096 
00097 /*
00098  * Install NSPR I/O functions into ld (if ld is NULL, they are installed
00099  * as the default functions for new LDAP * handles).
00100  *
00101  * Returns 0 if all goes well and -1 if not.
00102  */
00103 int
00104 prldap_install_io_functions( LDAP *ld, int shared )
00105 {
00106     struct ldap_x_ext_io_fns       iofns;
00107 
00108     memset( &iofns, 0, sizeof(iofns));
00109     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
00110     iofns.lextiof_read = prldap_read;
00111     iofns.lextiof_write = prldap_write;
00112     iofns.lextiof_poll = prldap_poll;
00113     iofns.lextiof_connect = prldap_connect;
00114     iofns.lextiof_close = prldap_close;
00115     if ( shared ) {
00116        iofns.lextiof_newhandle = prldap_shared_newhandle;
00117        iofns.lextiof_disposehandle = prldap_shared_disposehandle;
00118     } else {
00119        iofns.lextiof_newhandle = prldap_newhandle;
00120        iofns.lextiof_disposehandle = prldap_disposehandle;
00121     }
00122     if ( NULL != ld ) {
00123        /*
00124         * If we are dealing with a real ld, we allocate the session specific
00125         * data structure now.  If not allocated here, it will be allocated
00126         * inside prldap_newhandle() or prldap_shared_newhandle().
00127         */
00128        if ( NULL ==
00129               ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
00130            ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
00131            return( -1 );
00132        }
00133     } else {
00134        iofns.lextiof_session_arg = NULL;
00135     }
00136 
00137     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
00138        prldap_session_arg_free(
00139               (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
00140        return( -1 );
00141     }
00142 
00143     return( 0 );
00144 }
00145 
00146 
00147 static PRIntervalTime
00148 prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
00149 {
00150     PRIntervalTime   prit;
00151 
00152     if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
00153        prit = PR_INTERVAL_NO_WAIT;
00154     } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
00155        prit = PR_INTERVAL_NO_TIMEOUT;
00156     } else {
00157        prit = PR_MillisecondsToInterval( ms_timeout );
00158     }
00159 
00160     /* cap at maximum I/O timeout */
00161     if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
00162        prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
00163     } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
00164        if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
00165                   ms_timeout > ms_maxtimeout ) {
00166            prit = PR_MillisecondsToInterval( ms_maxtimeout );
00167        }
00168     }
00169 
00170 #ifdef PRLDAP_DEBUG
00171     if ( PR_INTERVAL_NO_WAIT == prit ) {
00172        fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
00173     } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
00174        fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
00175     } else {
00176        fprintf( stderr, "prldap_timeout2it: %dms\n",
00177               PR_IntervalToMilliseconds(prit));
00178     }
00179 #endif /* PRLDAP_DEBUG */
00180 
00181     return( prit );
00182 }
00183 
00184 
00185 static int LDAP_CALLBACK
00186 prldap_read( int s, void *buf, int bufsize,
00187        struct lextiof_socket_private *socketarg )
00188 {
00189     PRIntervalTime   prit;
00190 
00191     prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
00192                      socketarg->prsock_io_max_timeout );
00193     return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
00194 }
00195 
00196 
00197 static int LDAP_CALLBACK
00198 prldap_write( int s, const void *buf, int len,
00199        struct lextiof_socket_private *socketarg )
00200 {
00201     PRIntervalTime   prit;
00202 
00203     prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
00204                      socketarg->prsock_io_max_timeout );
00205 
00206     /*
00207      * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
00208      * must always be 0
00209      */
00210     return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit ));
00211 }
00212 
00213 
00214 struct prldap_eventmap_entry {
00215     PRInt16   evm_nspr;     /* corresponding NSPR PR_Poll() event */
00216     int              evm_ldap;     /* LDAP poll event */
00217 };
00218 
00219 static struct prldap_eventmap_entry prldap_eventmap[] = {
00220     { PR_POLL_READ,  LDAP_X_POLLIN },
00221     { PR_POLL_EXCEPT,       LDAP_X_POLLPRI },
00222     { PR_POLL_WRITE, LDAP_X_POLLOUT },
00223     { PR_POLL_ERR,   LDAP_X_POLLERR },
00224     { PR_POLL_HUP,   LDAP_X_POLLHUP },
00225     { PR_POLL_NVAL,  LDAP_X_POLLNVAL },
00226 };
00227 
00228 #define PRLDAP_EVENTMAP_ENTRIES    \
00229        sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
00230 
00231 static int LDAP_CALLBACK
00232 prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
00233        struct lextiof_session_private *sessionarg )
00234 {
00235     PRLDAPIOSessionArg      *prsessp = sessionarg;
00236     PRPollDesc              *pds;
00237     int                     i, j, rc;
00238 
00239     if ( NULL == prsessp ) {
00240        prldap_set_system_errno( EINVAL );
00241        return( -1 );
00242     }
00243 
00244     /* allocate or resize NSPR poll descriptor array */
00245     if ( prsessp->prsess_pollds_count < nfds ) {
00246        pds = prldap_safe_realloc( prsessp->prsess_pollds,
00247               ( nfds + PRLDAP_POLL_ARRAY_GROWTH )
00248               * sizeof( PRPollDesc ));
00249        if ( NULL == pds ) {
00250            prldap_set_system_errno( prldap_prerr2errno());
00251            return( -1 );
00252        }
00253        prsessp->prsess_pollds = pds;
00254        prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
00255     } else {
00256        pds = prsessp->prsess_pollds;
00257     }
00258 
00259     /* populate NSPR poll info. based on LDAP info. */
00260     for ( i = 0; i < nfds; ++i ) {
00261        if ( NULL == fds[i].lpoll_socketarg ) {
00262            pds[i].fd = NULL;
00263        } else {
00264            pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
00265        }
00266        pds[i].in_flags = pds[i].out_flags = 0;
00267        if ( fds[i].lpoll_fd >= 0 ) {
00268            for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
00269               if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
00270                   != 0 ) {
00271                      pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
00272               }
00273            }
00274        }
00275        fds[i].lpoll_revents = 0;   /* clear revents */
00276     }
00277 
00278     /* call PR_Poll() to do the real work */
00279     rc = PR_Poll( pds, nfds,
00280            prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
00281 
00282     /* populate LDAP info. based on NSPR results */
00283     for ( i = 0; i < nfds; ++i ) {
00284        if ( pds[i].fd != NULL ) {
00285            for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
00286               if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
00287                      != 0 ) {
00288                   fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
00289               }
00290            }
00291        }
00292     }
00293 
00294     return( rc );
00295 }
00296 
00297 
00298 /*
00299  * Utility function to try one TCP connect()
00300  * Returns 1 if successful and -1 if not.  Sets the NSPR fd inside prsockp.
00301  */
00302 static int
00303 prldap_try_one_address( struct lextiof_socket_private *prsockp,
00304     PRNetAddr *addrp, int timeout, unsigned long options )
00305 {
00306     /*
00307      * Open a TCP socket:
00308      */
00309     if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
00310               PR_NetAddrFamily(addrp) )) == NULL ) {
00311        return( -1 );
00312     }
00313 
00314     /*
00315      * Set nonblocking option if requested:
00316      */
00317     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
00318        PRSocketOptionData   optdata;
00319 
00320        optdata.option = PR_SockOpt_Nonblocking;
00321        optdata.value.non_blocking = PR_TRUE;
00322        if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
00323                   != PR_SUCCESS ) {
00324            prldap_set_system_errno( prldap_prerr2errno());
00325            PR_Close( prsockp->prsock_prfd );
00326            return( -1 );
00327        }
00328     }
00329 
00330 #ifdef PRLDAP_DEBUG
00331     {
00332        char   buf[ 256 ], *p, *fmtstr;
00333 
00334        if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
00335               strcpy( buf, "conversion failed!" );
00336        }
00337        if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
00338               /* IPv4 address mapped into IPv6 address space */
00339               p = buf + 7;
00340               fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
00341        } else {
00342               p = buf;
00343               fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
00344        }
00345        fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
00346     }
00347 #endif /* PRLDAP_DEBUG */
00348 
00349     /*
00350      * Try to open the TCP connection itself:
00351      */
00352     if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
00353                 prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))
00354                 && PR_IN_PROGRESS_ERROR != PR_GetError() ) {
00355        PR_Close( prsockp->prsock_prfd );
00356        prsockp->prsock_prfd = NULL;
00357        return( -1 );
00358     }
00359 
00360 #ifdef PRLDAP_DEBUG
00361     fputs( "prldap_try_one_address(): Connected.\n", stderr );
00362 #endif /* PRLDAP_DEBUG */
00363 
00364     /*
00365      * Success.  Return a valid file descriptor (1 is always valid)
00366      */
00367     return( 1 );
00368 }
00369 
00370 
00371 /*
00372  * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
00373  */
00374 static int LDAP_CALLBACK
00375 prldap_connect( const char *hostlist, int defport, int timeout,
00376        unsigned long options, struct lextiof_session_private *sessionarg,
00377        struct lextiof_socket_private **socketargp )
00378 {
00379     int                                   rc, parse_err, port;
00380     char                           *host;
00381     struct ldap_x_hostlist_status  *status;
00382     struct lextiof_socket_private  *prsockp;
00383     PRNetAddr                      addr;
00384     PRAddrInfo                            *infop = NULL;
00385 
00386     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
00387        prldap_set_system_errno( EINVAL );
00388        return( -1 );
00389     }
00390 
00391     if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
00392        prldap_set_system_errno( prldap_prerr2errno());
00393        return( -1 );
00394     }
00395 
00396     rc = -1;  /* pessimistic */
00397     for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
00398               &status );
00399               rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
00400               parse_err = ldap_x_hostlist_next( &host, &port, status )) {
00401        /*
00402         * First, call PR_GetAddrInfoByName; PR_GetAddrInfoByName could 
00403         * support both IPv4 and IPv6 addresses depending upon the system's
00404         * configuration.  All available addresses are returned and each of
00405         * them is examined in prldap_try_one_address till it succeeds.
00406         * Then, try converting the string address, in case the string
00407         * address was not successfully handled in PR_GetAddrInfoByName.
00408         */
00409        if ( NULL != ( infop =
00410              PR_GetAddrInfoByName( host, PR_AF_UNSPEC, 
00411                                 (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME) ))) {
00412            void *enump = NULL;
00413            do {
00414               memset( &addr, 0, sizeof( addr ));
00415               enump = PR_EnumerateAddrInfo( enump, infop, port, &addr );
00416               if ( NULL == enump ) {
00417                   break;
00418               }
00419               rc = prldap_try_one_address( prsockp, &addr, timeout, options );
00420            } while ( rc < 0 );
00421            PR_FreeAddrInfo( infop );
00422        } else if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
00423            PRLDAP_SET_PORT( &addr, port );
00424            rc = prldap_try_one_address( prsockp, &addr, timeout, options );
00425        }
00426        ldap_memfree( host );
00427     }
00428 
00429     ldap_x_hostlist_statusfree( status );
00430 
00431     if ( rc < 0 ) {
00432        prldap_set_system_errno( prldap_prerr2errno());
00433        prldap_socket_arg_free( &prsockp );
00434     } else {
00435        *socketargp = prsockp;
00436     }
00437 
00438     return( rc );
00439 }
00440 
00441 
00442 static int LDAP_CALLBACK
00443 prldap_close( int s, struct lextiof_socket_private *socketarg )
00444 {
00445     int              rc;
00446 
00447     rc = 0;
00448     if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
00449        rc = -1;
00450        prldap_set_system_errno( prldap_prerr2errno());
00451     }
00452     prldap_socket_arg_free( &socketarg );
00453 
00454     return( rc );
00455 }
00456 
00457 
00458 /*
00459  * LDAP session handle creation callback.
00460  *
00461  * Allocate a session argument if not already done, and then call the
00462  * thread's new handle function.
00463  */
00464 static int LDAP_CALLBACK
00465 prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
00466 {
00467 
00468     if ( NULL == sessionarg ) {
00469        struct ldap_x_ext_io_fns    iofns;
00470 
00471        memset( &iofns, 0, sizeof(iofns));
00472        iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
00473        if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
00474               (void *)&iofns ) < 0 ) {
00475            return( ldap_get_lderrno( ld, NULL, NULL ));
00476        }
00477        if ( NULL ==
00478               ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
00479            return( LDAP_NO_MEMORY );
00480        }
00481        if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
00482                   (void *)&iofns ) < 0 ) {
00483            return( ldap_get_lderrno( ld, NULL, NULL ));
00484        }
00485     }
00486 
00487     return( LDAP_SUCCESS );
00488 }
00489 
00490 
00491 /* only called/installed if shared is non-zero. */
00492 static int LDAP_CALLBACK
00493 prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
00494 {
00495     int              rc;
00496 
00497     if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
00498        rc = prldap_thread_new_handle( ld, sessionarg );
00499     }
00500 
00501     return( rc );
00502 }
00503 
00504 
00505 static void LDAP_CALLBACK
00506 prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
00507 {
00508     prldap_session_arg_free( &sessionarg );
00509 }
00510 
00511 
00512 /* only called/installed if shared is non-zero */
00513 static void LDAP_CALLBACK
00514 prldap_shared_disposehandle( LDAP *ld,
00515        struct lextiof_session_private *sessionarg )
00516 {
00517     prldap_thread_dispose_handle( ld, sessionarg );
00518     prldap_disposehandle( ld, sessionarg );
00519 }
00520 
00521 
00522 /*
00523  * Allocate a session argument.
00524  */
00525 static PRLDAPIOSessionArg *
00526 prldap_session_arg_alloc( void )
00527 {
00528     PRLDAPIOSessionArg             *prsessp;
00529 
00530     prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
00531 
00532     if ( NULL != prsessp ) {
00533        /* copy global defaults to the new session handle */
00534        prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
00535     }
00536 
00537     return( prsessp );
00538 }
00539 
00540 
00541 static void
00542 prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
00543 {
00544     if ( NULL != prsesspp && NULL != *prsesspp ) {
00545        if ( NULL != (*prsesspp)->prsess_pollds ) {
00546            PR_Free( (*prsesspp)->prsess_pollds );
00547            (*prsesspp)->prsess_pollds = NULL;
00548        }
00549        PR_Free( *prsesspp );
00550        *prsesspp = NULL;
00551     }
00552 }
00553 
00554 
00555 /*
00556  * Given an LDAP session handle, retrieve a session argument.
00557  * Returns an LDAP error code.
00558  */
00559 int
00560 prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
00561 {
00562     struct ldap_x_ext_io_fns       iofns;
00563 
00564     if ( NULL == ld || NULL == sessargpp ) {
00565        /* XXXmcs: NULL ld's are not supported */
00566        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
00567        return( LDAP_PARAM_ERROR );
00568     }
00569 
00570     memset( &iofns, 0, sizeof(iofns));
00571     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
00572     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
00573        return( ldap_get_lderrno( ld, NULL, NULL ));
00574     }
00575 
00576     if ( NULL == iofns.lextiof_session_arg ) {
00577        ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
00578        return( LDAP_LOCAL_ERROR );
00579     }
00580 
00581     *sessargpp = iofns.lextiof_session_arg;
00582     return( LDAP_SUCCESS );
00583 }
00584 
00585 
00586 /*
00587  * Allocate a socket argument.
00588  */
00589 static PRLDAPIOSocketArg *
00590 prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
00591 {
00592     PRLDAPIOSocketArg              *prsockp;
00593 
00594     prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
00595 
00596     if ( NULL != prsockp && NULL != sessionarg ) {
00597        /* copy socket defaults from the session */
00598        prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
00599     }
00600 
00601     return( prsockp );
00602 }
00603 
00604 
00605 static void
00606 prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
00607 {
00608     if ( NULL != prsockpp && NULL != *prsockpp ) {
00609        PR_Free( *prsockpp );
00610        *prsockpp = NULL;
00611     }
00612 }
00613 
00614 
00615 static void *
00616 prldap_safe_realloc( void *ptr, PRUint32 size )
00617 {
00618     void      *p;
00619 
00620     if ( NULL == ptr ) {
00621        p = PR_Malloc( size );
00622     } else {
00623        p = PR_Realloc( ptr, size );
00624     }
00625 
00626     return( p );
00627 }
00628 
00629 
00630 
00631 /* returns an LDAP result code */
00632 int
00633 prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
00634 {
00635     int       rc = LDAP_SUCCESS;   /* optimistic */
00636 
00637     if ( NULL == prsessp ) {
00638        prldap_default_io_max_timeout = io_max_timeout;
00639     } else {
00640        prsessp->prsess_io_max_timeout = io_max_timeout;
00641     }
00642 
00643     return( rc );
00644 }
00645 
00646 
00647 /* returns an LDAP result code */
00648 int
00649 prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
00650 {
00651     int       rc = LDAP_SUCCESS;   /* optimistic */
00652 
00653     if ( NULL == io_max_timeoutp ) {
00654        rc = LDAP_PARAM_ERROR;
00655     } else if ( NULL == prsessp ) {
00656        *io_max_timeoutp = prldap_default_io_max_timeout;
00657     } else {
00658        *io_max_timeoutp = prsessp->prsess_io_max_timeout;
00659     }
00660 
00661     return( rc );
00662 }