summaryrefslogtreecommitdiff
path: root/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c')
-rw-r--r--usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c721
1 files changed, 721 insertions, 0 deletions
diff --git a/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
new file mode 100644
index 0000000000..824a8ca212
--- /dev/null
+++ b/usr/src/lib/libldap5/sources/ldap/prldap/ldappr-io.c
@@ -0,0 +1,721 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * The contents of this file are subject to the Netscape Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998-1999 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+/*
+ * Extended I/O callback functions for libldap that use
+ * NSPR (Netscape Portable Runtime) I/O.
+ *
+ * High level strategy: we use the socket-specific arg to hold our own data
+ * structure that includes the NSPR file handle (PRFileDesc *), among other
+ * useful information. We use the default argument to hold an LDAP session
+ * handle specific data structure.
+ */
+
+#include "ldappr-int.h"
+#include <string.h>
+
+#define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
+
+/*
+ * Local function prototypes:
+ */
+static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
+static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
+ int timeout, struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
+ int timeout, unsigned long options,
+ struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp
+#ifdef _SOLARIS_SDK
+ , void **dhost );
+#else
+ );
+#endif /* _SOLARIS_SDK */
+static int LDAP_CALLBACK prldap_close( int s,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
+static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
+static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
+static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
+static void *prldap_safe_realloc( void *ptr, PRUint32 size );
+
+
+
+/*
+ * Local macros:
+ */
+/* given a socket-specific arg, return the corresponding PRFileDesc * */
+#define PRLDAP_GET_PRFD( socketarg ) \
+ (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
+
+/*
+ * Static variables.
+ */
+static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+/*
+ * Install NSPR I/O functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_io_functions( LDAP *ld, int shared )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ iofns.lextiof_read = prldap_read;
+ iofns.lextiof_write = prldap_write;
+ iofns.lextiof_poll = prldap_poll;
+ iofns.lextiof_connect = prldap_connect;
+ iofns.lextiof_close = prldap_close;
+ if ( shared ) {
+ iofns.lextiof_newhandle = prldap_shared_newhandle;
+ iofns.lextiof_disposehandle = prldap_shared_disposehandle;
+ } else {
+ iofns.lextiof_newhandle = prldap_newhandle;
+ iofns.lextiof_disposehandle = prldap_disposehandle;
+ }
+ if ( NULL != ld ) {
+ /*
+ * If we are dealing with a real ld, we allocate the session specific
+ * data structure now. If not allocated here, it will be allocated
+ * inside prldap_newhandle() or prldap_shared_newhandle().
+ */
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ } else {
+ iofns.lextiof_session_arg = NULL;
+ }
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
+ prldap_session_arg_free(
+ (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static PRIntervalTime
+prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
+{
+ PRIntervalTime prit;
+
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_TIMEOUT;
+ } else {
+ prit = PR_MillisecondsToInterval( ms_timeout );
+ }
+
+ /* cap at maximum I/O timeout */
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
+ prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
+ if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
+ ms_timeout > ms_maxtimeout ) {
+ prit = PR_MillisecondsToInterval( ms_maxtimeout );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ if ( PR_INTERVAL_NO_WAIT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
+ } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
+ } else {
+ fprintf( stderr, "prldap_timeout2it: %dms\n",
+ PR_IntervalToMilliseconds(prit));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ return( prit );
+}
+
+
+static int LDAP_CALLBACK
+prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+ return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
+}
+
+
+static int LDAP_CALLBACK
+prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+
+ /*
+ * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
+ * must always be 0
+ */
+ return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit ));
+}
+
+
+struct prldap_eventmap_entry {
+ PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */
+ int evm_ldap; /* LDAP poll event */
+};
+
+static struct prldap_eventmap_entry prldap_eventmap[] = {
+ { PR_POLL_READ, LDAP_X_POLLIN },
+ { PR_POLL_EXCEPT, LDAP_X_POLLPRI },
+ { PR_POLL_WRITE, LDAP_X_POLLOUT },
+ { PR_POLL_ERR, LDAP_X_POLLERR },
+ { PR_POLL_HUP, LDAP_X_POLLHUP },
+ { PR_POLL_NVAL, LDAP_X_POLLNVAL },
+};
+
+#define PRLDAP_EVENTMAP_ENTRIES \
+ sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
+
+static int LDAP_CALLBACK
+prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+ struct lextiof_session_private *sessionarg )
+{
+ PRLDAPIOSessionArg *prsessp = sessionarg;
+ PRPollDesc *pds;
+ int i, j, rc;
+
+ if ( NULL == prsessp ) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ /* allocate or resize NSPR poll descriptor array */
+ if ( prsessp->prsess_pollds_count < nfds ) {
+ pds = prldap_safe_realloc( prsessp->prsess_pollds,
+ ( nfds + PRLDAP_POLL_ARRAY_GROWTH )
+ * sizeof( PRPollDesc ));
+ if ( NULL == pds ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+ prsessp->prsess_pollds = pds;
+ prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
+ } else {
+ pds = prsessp->prsess_pollds;
+ }
+
+ /* populate NSPR poll info. based on LDAP info. */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( NULL == fds[i].lpoll_socketarg ) {
+ pds[i].fd = NULL;
+ } else {
+ pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
+ }
+ pds[i].in_flags = pds[i].out_flags = 0;
+ if ( fds[i].lpoll_fd >= 0 ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
+ != 0 ) {
+ pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
+ }
+ }
+ }
+ fds[i].lpoll_revents = 0; /* clear revents */
+ }
+
+ /* call PR_Poll() to do the real work */
+ rc = PR_Poll( pds, nfds,
+ prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
+
+ /* populate LDAP info. based on NSPR results */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( pds[i].fd != NULL ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
+ != 0 ) {
+ fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
+ }
+ }
+ }
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Utility function to try one TCP connect()
+ * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp.
+ */
+static int
+prldap_try_one_address( struct lextiof_socket_private *prsockp,
+ PRNetAddr *addrp, int port, int timeout, unsigned long options )
+{
+ /*
+ * Set up address and open a TCP socket:
+ */
+ if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) {
+ return( -1 );
+ }
+
+ if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
+ PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) {
+ return( -1 );
+ }
+
+ /*
+ * Set nonblocking option if requested:
+ */
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
+ PRSocketOptionData optdata;
+
+ optdata.option = PR_SockOpt_Nonblocking;
+ optdata.value.non_blocking = PR_TRUE;
+ if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
+ != PR_SUCCESS ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ PR_Close( prsockp->prsock_prfd );
+ return( -1 );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ {
+ char buf[ 256 ], *p, *fmtstr;
+
+ if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
+ strcpy( buf, "conversion failed!" );
+ }
+ if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
+ /* IPv4 address mapped into IPv6 address space */
+ p = buf + 7;
+ fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
+ } else {
+ p = buf;
+ fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
+ }
+ fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Try to open the TCP connection itself:
+ */
+ if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
+ prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) {
+ PR_Close( prsockp->prsock_prfd );
+ prsockp->prsock_prfd = NULL;
+ return( -1 );
+ }
+
+#ifdef PRLDAP_DEBUG
+ fputs( "prldap_try_one_address(): Connected.\n", stderr );
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Success. Return a valid file descriptor (1 is always valid)
+ */
+ return( 1 );
+}
+
+
+/*
+ * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
+ */
+static int LDAP_CALLBACK
+prldap_connect( const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp
+#ifdef _SOLARIS_SDK
+ , void **dhost )
+#else
+ )
+#endif /* _SOLARIS_SDK */
+{
+ int rc, parse_err, port;
+ char *host, hbuf[ PR_NETDB_BUF_SIZE ];
+ struct ldap_x_hostlist_status *status;
+ struct lextiof_socket_private *prsockp;
+ PRNetAddr addr;
+ PRHostEnt hent;
+#ifdef _SOLARIS_SDK
+ char *hostname = NULL;
+ char *nsldapi_strdup(char *);
+#endif /* _SOLARIS_SDK */
+
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+
+ rc = -1; /* pessimistic */
+ for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+ &status );
+ rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
+ parse_err = ldap_x_hostlist_next( &host, &port, status )) {
+
+ if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
+
+ if ( PRLDAP_DEFAULT_ADDRESS_FAMILY == PR_AF_INET6 &&
+ PR_AF_INET == PR_NetAddrFamily( &addr )) {
+ PRUint32 ipv4ip = addr.inet.ip;
+ memset( &addr, 0, sizeof(addr));
+ PR_ConvertIPv4AddrToIPv6( ipv4ip, &addr.ipv6.ip );
+ addr.ipv6.family = PR_AF_INET6;
+
+ }
+ rc = prldap_try_one_address( prsockp, &addr, port,
+ timeout, options );
+ } else {
+ if ( PR_SUCCESS == PR_GetIPNodeByName( host,
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT | PR_AI_ALL, hbuf,
+ sizeof( hbuf ), &hent )) {
+ PRIntn enumIndex = 0;
+
+ while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt(
+ enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) {
+ rc = prldap_try_one_address( prsockp, &addr, port,
+ timeout, options );
+ }
+ }
+ }
+
+#ifdef _SOLARIS_SDK
+ if ( NULL != hostname ) ldap_memfree(hostname);
+ hostname = nsldapi_strdup(host);
+#endif /* _SOLARIS_SDK */
+ ldap_memfree( host );
+ }
+
+ ldap_x_hostlist_statusfree( status );
+
+ if ( rc < 0 ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ prldap_socket_arg_free( &prsockp );
+ } else {
+ *socketargp = prsockp;
+ }
+
+#ifdef _SOLARIS_SDK
+ if ( NULL != hostname && NULL != dhost ) *dhost = hostname;
+ else if ( NULL != hostname ) ldap_memfree(hostname);
+#endif /* _SOLARIS_SDK */
+
+ return( rc );
+}
+
+
+static int LDAP_CALLBACK
+prldap_close( int s, struct lextiof_socket_private *socketarg )
+{
+ int rc;
+
+ rc = 0;
+ if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
+ rc = -1;
+ prldap_set_system_errno( prldap_prerr2errno());
+ }
+ prldap_socket_arg_free( &socketarg );
+
+ return( rc );
+}
+
+
+/*
+ * LDAP session handle creation callback.
+ *
+ * Allocate a session argument if not already done, and then call the
+ * thread's new handle function.
+ */
+static int LDAP_CALLBACK
+prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+
+ if ( NULL == sessionarg ) {
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ return( LDAP_NO_MEMORY );
+ }
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/* only called/installed if shared is non-zero. */
+static int LDAP_CALLBACK
+prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ int rc;
+
+ if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
+ rc = prldap_thread_new_handle( ld, sessionarg );
+ }
+
+ return( rc );
+}
+
+
+static void LDAP_CALLBACK
+prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ prldap_session_arg_free( &sessionarg );
+}
+
+
+/* only called/installed if shared is non-zero */
+static void LDAP_CALLBACK
+prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg )
+{
+ prldap_thread_dispose_handle( ld, sessionarg );
+ prldap_disposehandle( ld, sessionarg );
+}
+
+
+/*
+ * Allocate a session argument.
+ */
+static PRLDAPIOSessionArg *
+prldap_session_arg_alloc( void )
+{
+ PRLDAPIOSessionArg *prsessp;
+
+ prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
+
+ if ( NULL != prsessp ) {
+ /* copy global defaults to the new session handle */
+ prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
+ }
+
+ return( prsessp );
+}
+
+
+static void
+prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
+{
+ if ( NULL != prsesspp && NULL != *prsesspp ) {
+ if ( NULL != (*prsesspp)->prsess_pollds ) {
+ PR_Free( (*prsesspp)->prsess_pollds );
+ (*prsesspp)->prsess_pollds = NULL;
+ }
+ PR_Free( *prsesspp );
+ *prsesspp = NULL;
+ }
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a session argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ if ( NULL == ld || NULL == sessargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == iofns.lextiof_session_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sessargpp = iofns.lextiof_session_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a socket argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
+{
+ Sockbuf *sbp;
+ struct lber_x_ext_io_fns extiofns;
+
+ if ( NULL == ld || NULL == sockargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ memset( &extiofns, 0, sizeof(extiofns));
+ extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&extiofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == extiofns.lbextiofn_socket_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sockargpp = extiofns.lbextiofn_socket_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Allocate a socket argument.
+ */
+static PRLDAPIOSocketArg *
+prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
+
+ if ( NULL != prsockp && NULL != sessionarg ) {
+ /* copy socket defaults from the session */
+ prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
+ }
+
+ return( prsockp );
+}
+
+
+static void
+prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
+{
+ if ( NULL != prsockpp && NULL != *prsockpp ) {
+ PR_Free( *prsockpp );
+ *prsockpp = NULL;
+ }
+}
+
+
+static void *
+prldap_safe_realloc( void *ptr, PRUint32 size )
+{
+ void *p;
+
+ if ( NULL == ptr ) {
+ p = PR_Malloc( size );
+ } else {
+ p = PR_Realloc( ptr, size );
+ }
+
+ return( p );
+}
+
+
+
+/* returns an LDAP result code */
+int
+prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == prsessp ) {
+ prldap_default_io_max_timeout = io_max_timeout;
+ } else {
+ prsessp->prsess_io_max_timeout = io_max_timeout;
+ }
+
+ return( rc );
+}
+
+
+/* returns an LDAP result code */
+int
+prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == io_max_timeoutp ) {
+ rc = LDAP_PARAM_ERROR;
+ } else if ( NULL == prsessp ) {
+ *io_max_timeoutp = prldap_default_io_max_timeout;
+ } else {
+ *io_max_timeoutp = prsessp->prsess_io_max_timeout;
+ }
+
+ return( rc );
+}