17c478bd9Sstevel@tonic-gate /*
2*e944850bSMilan Jurik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
87c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
97c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
107c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
137c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
147c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
157c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
187c478bd9Sstevel@tonic-gate  * March 31, 1998.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
217c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
227c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
237c478bd9Sstevel@tonic-gate  * Rights Reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Contributor(s):
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Extended I/O callback functions for libldap that use
307c478bd9Sstevel@tonic-gate  * NSPR (Netscape Portable Runtime) I/O.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * High level strategy: we use the socket-specific arg to hold our own data
337c478bd9Sstevel@tonic-gate  * structure that includes the NSPR file handle (PRFileDesc *), among other
347c478bd9Sstevel@tonic-gate  * useful information.  We use the default argument to hold an LDAP session
357c478bd9Sstevel@tonic-gate  * handle specific data structure.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "ldappr-int.h"
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #define PRLDAP_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Local function prototypes:
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
477c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
487c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *socketarg );
497c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
507c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *socketarg );
517c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
527c478bd9Sstevel@tonic-gate 	int timeout, struct lextiof_session_private *sessionarg );
537c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
547c478bd9Sstevel@tonic-gate 	int timeout, unsigned long options,
557c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg,
567c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private **socketargp
577c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
587c478bd9Sstevel@tonic-gate 	, void **dhost );
597c478bd9Sstevel@tonic-gate #else
607c478bd9Sstevel@tonic-gate 	);
617c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
627c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_close( int s,
637c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *socketarg );
647c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
657c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg );
667c478bd9Sstevel@tonic-gate static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
677c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg );
687c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
697c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg );
707c478bd9Sstevel@tonic-gate static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
717c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg );
727c478bd9Sstevel@tonic-gate static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
737c478bd9Sstevel@tonic-gate static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
747c478bd9Sstevel@tonic-gate static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
757c478bd9Sstevel@tonic-gate static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
767c478bd9Sstevel@tonic-gate static void *prldap_safe_realloc( void *ptr, PRUint32 size );
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * Local macros:
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate /* given a socket-specific arg, return the corresponding PRFileDesc * */
847c478bd9Sstevel@tonic-gate #define PRLDAP_GET_PRFD( socketarg )	\
857c478bd9Sstevel@tonic-gate 		(((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Static variables.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Install NSPR I/O functions into ld (if ld is NULL, they are installed
947c478bd9Sstevel@tonic-gate  * as the default functions for new LDAP * handles).
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  * Returns 0 if all goes well and -1 if not.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate int
997c478bd9Sstevel@tonic-gate prldap_install_io_functions( LDAP *ld, int shared )
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate     struct ldap_x_ext_io_fns	iofns;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate     memset( &iofns, 0, sizeof(iofns));
1047c478bd9Sstevel@tonic-gate     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
1057c478bd9Sstevel@tonic-gate     iofns.lextiof_read = prldap_read;
1067c478bd9Sstevel@tonic-gate     iofns.lextiof_write = prldap_write;
1077c478bd9Sstevel@tonic-gate     iofns.lextiof_poll = prldap_poll;
1087c478bd9Sstevel@tonic-gate     iofns.lextiof_connect = prldap_connect;
1097c478bd9Sstevel@tonic-gate     iofns.lextiof_close = prldap_close;
1107c478bd9Sstevel@tonic-gate     if ( shared ) {
1117c478bd9Sstevel@tonic-gate 	iofns.lextiof_newhandle = prldap_shared_newhandle;
1127c478bd9Sstevel@tonic-gate 	iofns.lextiof_disposehandle = prldap_shared_disposehandle;
1137c478bd9Sstevel@tonic-gate     } else {
1147c478bd9Sstevel@tonic-gate 	iofns.lextiof_newhandle = prldap_newhandle;
1157c478bd9Sstevel@tonic-gate 	iofns.lextiof_disposehandle = prldap_disposehandle;
1167c478bd9Sstevel@tonic-gate     }
1177c478bd9Sstevel@tonic-gate     if ( NULL != ld ) {
1187c478bd9Sstevel@tonic-gate 	/*
1197c478bd9Sstevel@tonic-gate 	 * If we are dealing with a real ld, we allocate the session specific
1207c478bd9Sstevel@tonic-gate 	 * data structure now.  If not allocated here, it will be allocated
1217c478bd9Sstevel@tonic-gate 	 * inside prldap_newhandle() or prldap_shared_newhandle().
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if ( NULL ==
1247c478bd9Sstevel@tonic-gate 		( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
1257c478bd9Sstevel@tonic-gate 	    ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
1267c478bd9Sstevel@tonic-gate 	    return( -1 );
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate     } else {
1297c478bd9Sstevel@tonic-gate 	iofns.lextiof_session_arg = NULL;
1307c478bd9Sstevel@tonic-gate     }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
1337c478bd9Sstevel@tonic-gate 	prldap_session_arg_free(
1347c478bd9Sstevel@tonic-gate 		(PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
1357c478bd9Sstevel@tonic-gate 	return( -1 );
1367c478bd9Sstevel@tonic-gate     }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate     return( 0 );
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static PRIntervalTime
1437c478bd9Sstevel@tonic-gate prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate     PRIntervalTime	prit;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate     if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
1487c478bd9Sstevel@tonic-gate 	prit = PR_INTERVAL_NO_WAIT;
1497c478bd9Sstevel@tonic-gate     } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
1507c478bd9Sstevel@tonic-gate 	prit = PR_INTERVAL_NO_TIMEOUT;
1517c478bd9Sstevel@tonic-gate     } else {
1527c478bd9Sstevel@tonic-gate 	prit = PR_MillisecondsToInterval( ms_timeout );
1537c478bd9Sstevel@tonic-gate     }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate     /* cap at maximum I/O timeout */
1567c478bd9Sstevel@tonic-gate     if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
1577c478bd9Sstevel@tonic-gate 	prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
1587c478bd9Sstevel@tonic-gate     } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
1597c478bd9Sstevel@tonic-gate 	if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
1607c478bd9Sstevel@tonic-gate 		    ms_timeout > ms_maxtimeout ) {
1617c478bd9Sstevel@tonic-gate 	    prit = PR_MillisecondsToInterval( ms_maxtimeout );
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate     }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate #ifdef PRLDAP_DEBUG
1667c478bd9Sstevel@tonic-gate     if ( PR_INTERVAL_NO_WAIT == prit ) {
1677c478bd9Sstevel@tonic-gate 	fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
1687c478bd9Sstevel@tonic-gate     } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
1697c478bd9Sstevel@tonic-gate 	fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
1707c478bd9Sstevel@tonic-gate     } else {
1717c478bd9Sstevel@tonic-gate 	fprintf( stderr, "prldap_timeout2it: %dms\n",
1727c478bd9Sstevel@tonic-gate 		PR_IntervalToMilliseconds(prit));
1737c478bd9Sstevel@tonic-gate     }
1747c478bd9Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate     return( prit );
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
1817c478bd9Sstevel@tonic-gate prldap_read( int s, void *buf, int bufsize,
1827c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *socketarg )
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate     PRIntervalTime	prit;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate     prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
1877c478bd9Sstevel@tonic-gate 			socketarg->prsock_io_max_timeout );
1887c478bd9Sstevel@tonic-gate     return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
1937c478bd9Sstevel@tonic-gate prldap_write( int s, const void *buf, int len,
1947c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private *socketarg )
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate     PRIntervalTime	prit;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate     prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
1997c478bd9Sstevel@tonic-gate 			socketarg->prsock_io_max_timeout );
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate     /*
2027c478bd9Sstevel@tonic-gate      * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
2037c478bd9Sstevel@tonic-gate      * must always be 0
2047c478bd9Sstevel@tonic-gate      */
2057c478bd9Sstevel@tonic-gate     return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit ));
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate struct prldap_eventmap_entry {
2107c478bd9Sstevel@tonic-gate     PRInt16	evm_nspr;	/* corresponding NSPR PR_Poll() event */
2117c478bd9Sstevel@tonic-gate     int		evm_ldap;	/* LDAP poll event */
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static struct prldap_eventmap_entry prldap_eventmap[] = {
2157c478bd9Sstevel@tonic-gate     { PR_POLL_READ,	LDAP_X_POLLIN },
2167c478bd9Sstevel@tonic-gate     { PR_POLL_EXCEPT,	LDAP_X_POLLPRI },
2177c478bd9Sstevel@tonic-gate     { PR_POLL_WRITE,	LDAP_X_POLLOUT },
2187c478bd9Sstevel@tonic-gate     { PR_POLL_ERR,	LDAP_X_POLLERR },
2197c478bd9Sstevel@tonic-gate     { PR_POLL_HUP,	LDAP_X_POLLHUP },
2207c478bd9Sstevel@tonic-gate     { PR_POLL_NVAL,	LDAP_X_POLLNVAL },
2217c478bd9Sstevel@tonic-gate };
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #define PRLDAP_EVENTMAP_ENTRIES	\
2247c478bd9Sstevel@tonic-gate 	sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
2277c478bd9Sstevel@tonic-gate prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
2287c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg )
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate     PRLDAPIOSessionArg	*prsessp = sessionarg;
2317c478bd9Sstevel@tonic-gate     PRPollDesc		*pds;
2327c478bd9Sstevel@tonic-gate     int			i, j, rc;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate     if ( NULL == prsessp ) {
2357c478bd9Sstevel@tonic-gate 	prldap_set_system_errno( EINVAL );
2367c478bd9Sstevel@tonic-gate 	return( -1 );
2377c478bd9Sstevel@tonic-gate     }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     /* allocate or resize NSPR poll descriptor array */
2407c478bd9Sstevel@tonic-gate     if ( prsessp->prsess_pollds_count < nfds ) {
2417c478bd9Sstevel@tonic-gate 	pds = prldap_safe_realloc( prsessp->prsess_pollds,
2427c478bd9Sstevel@tonic-gate 		( nfds + PRLDAP_POLL_ARRAY_GROWTH )
2437c478bd9Sstevel@tonic-gate 		* sizeof( PRPollDesc ));
2447c478bd9Sstevel@tonic-gate 	if ( NULL == pds ) {
2457c478bd9Sstevel@tonic-gate 	    prldap_set_system_errno( prldap_prerr2errno());
2467c478bd9Sstevel@tonic-gate 	    return( -1 );
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 	prsessp->prsess_pollds = pds;
2497c478bd9Sstevel@tonic-gate 	prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
2507c478bd9Sstevel@tonic-gate     } else {
2517c478bd9Sstevel@tonic-gate 	pds = prsessp->prsess_pollds;
2527c478bd9Sstevel@tonic-gate     }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate     /* populate NSPR poll info. based on LDAP info. */
2557c478bd9Sstevel@tonic-gate     for ( i = 0; i < nfds; ++i ) {
2567c478bd9Sstevel@tonic-gate 	if ( NULL == fds[i].lpoll_socketarg ) {
2577c478bd9Sstevel@tonic-gate 	    pds[i].fd = NULL;
2587c478bd9Sstevel@tonic-gate 	} else {
2597c478bd9Sstevel@tonic-gate 	    pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 	pds[i].in_flags = pds[i].out_flags = 0;
2627c478bd9Sstevel@tonic-gate 	if ( fds[i].lpoll_fd >= 0 ) {
2637c478bd9Sstevel@tonic-gate 	    for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
2647c478bd9Sstevel@tonic-gate 		if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
2657c478bd9Sstevel@tonic-gate 		    != 0 ) {
2667c478bd9Sstevel@tonic-gate 			pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 	    }
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	fds[i].lpoll_revents = 0;	/* clear revents */
2717c478bd9Sstevel@tonic-gate     }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate     /* call PR_Poll() to do the real work */
2747c478bd9Sstevel@tonic-gate     rc = PR_Poll( pds, nfds,
2757c478bd9Sstevel@tonic-gate 	    prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate     /* populate LDAP info. based on NSPR results */
2787c478bd9Sstevel@tonic-gate     for ( i = 0; i < nfds; ++i ) {
2797c478bd9Sstevel@tonic-gate 	if ( pds[i].fd != NULL ) {
2807c478bd9Sstevel@tonic-gate 	    for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
2817c478bd9Sstevel@tonic-gate 		if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
2827c478bd9Sstevel@tonic-gate 			!= 0 ) {
2837c478bd9Sstevel@tonic-gate 		    fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 	    }
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate     }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate     return( rc );
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * Utility function to try one TCP connect()
2957c478bd9Sstevel@tonic-gate  * Returns 1 if successful and -1 if not.  Sets the NSPR fd inside prsockp.
2967c478bd9Sstevel@tonic-gate  */
2977c478bd9Sstevel@tonic-gate static int
2987c478bd9Sstevel@tonic-gate prldap_try_one_address( struct lextiof_socket_private *prsockp,
2997c478bd9Sstevel@tonic-gate     PRNetAddr *addrp, int port, int timeout, unsigned long options )
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate     /*
3027c478bd9Sstevel@tonic-gate      * Set up address and open a TCP socket:
3037c478bd9Sstevel@tonic-gate      */
3047c478bd9Sstevel@tonic-gate     if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */
3057c478bd9Sstevel@tonic-gate 		PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) {
3067c478bd9Sstevel@tonic-gate 	return( -1 );
3077c478bd9Sstevel@tonic-gate     }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate     if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
3107c478bd9Sstevel@tonic-gate 		PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) {
3117c478bd9Sstevel@tonic-gate 	return( -1 );
3127c478bd9Sstevel@tonic-gate     }
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate     /*
3157c478bd9Sstevel@tonic-gate      * Set nonblocking option if requested:
3167c478bd9Sstevel@tonic-gate      */
3177c478bd9Sstevel@tonic-gate     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
3187c478bd9Sstevel@tonic-gate 	PRSocketOptionData	optdata;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	optdata.option = PR_SockOpt_Nonblocking;
3217c478bd9Sstevel@tonic-gate 	optdata.value.non_blocking = PR_TRUE;
3227c478bd9Sstevel@tonic-gate 	if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
3237c478bd9Sstevel@tonic-gate 		    != PR_SUCCESS ) {
3247c478bd9Sstevel@tonic-gate 	    prldap_set_system_errno( prldap_prerr2errno());
3257c478bd9Sstevel@tonic-gate 	    PR_Close( prsockp->prsock_prfd );
3267c478bd9Sstevel@tonic-gate 	    return( -1 );
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate     }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate #ifdef PRLDAP_DEBUG
3317c478bd9Sstevel@tonic-gate     {
3327c478bd9Sstevel@tonic-gate 	char	buf[ 256 ], *p, *fmtstr;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
3357c478bd9Sstevel@tonic-gate 		strcpy( buf, "conversion failed!" );
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 	if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
3387c478bd9Sstevel@tonic-gate 		/* IPv4 address mapped into IPv6 address space */
3397c478bd9Sstevel@tonic-gate 		p = buf + 7;
3407c478bd9Sstevel@tonic-gate 		fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
3417c478bd9Sstevel@tonic-gate 	} else {
3427c478bd9Sstevel@tonic-gate 		p = buf;
3437c478bd9Sstevel@tonic-gate 		fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
3467c478bd9Sstevel@tonic-gate     }
3477c478bd9Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate     /*
3507c478bd9Sstevel@tonic-gate      * Try to open the TCP connection itself:
3517c478bd9Sstevel@tonic-gate      */
3527c478bd9Sstevel@tonic-gate     if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
3537c478bd9Sstevel@tonic-gate 		prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) {
3547c478bd9Sstevel@tonic-gate 	PR_Close( prsockp->prsock_prfd );
3557c478bd9Sstevel@tonic-gate 	prsockp->prsock_prfd = NULL;
3567c478bd9Sstevel@tonic-gate 	return( -1 );
3577c478bd9Sstevel@tonic-gate     }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate #ifdef PRLDAP_DEBUG
3607c478bd9Sstevel@tonic-gate     fputs( "prldap_try_one_address(): Connected.\n", stderr );
3617c478bd9Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate     /*
3647c478bd9Sstevel@tonic-gate      * Success.  Return a valid file descriptor (1 is always valid)
3657c478bd9Sstevel@tonic-gate      */
3667c478bd9Sstevel@tonic-gate     return( 1 );
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
3727c478bd9Sstevel@tonic-gate  */
3737c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
3747c478bd9Sstevel@tonic-gate prldap_connect( const char *hostlist, int defport, int timeout,
3757c478bd9Sstevel@tonic-gate 	unsigned long options, struct lextiof_session_private *sessionarg,
3767c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private **socketargp
3777c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
3787c478bd9Sstevel@tonic-gate 	, void **dhost )
3797c478bd9Sstevel@tonic-gate #else
3807c478bd9Sstevel@tonic-gate 	)
3817c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate     int					rc, parse_err, port;
3847c478bd9Sstevel@tonic-gate     char				*host, hbuf[ PR_NETDB_BUF_SIZE ];
3857c478bd9Sstevel@tonic-gate     struct ldap_x_hostlist_status	*status;
3867c478bd9Sstevel@tonic-gate     struct lextiof_socket_private	*prsockp;
3877c478bd9Sstevel@tonic-gate     PRNetAddr				addr;
3887c478bd9Sstevel@tonic-gate     PRHostEnt				hent;
3897c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
3907c478bd9Sstevel@tonic-gate     char				*hostname = NULL;
3917c478bd9Sstevel@tonic-gate     char				*nsldapi_strdup(char *);
3927c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
3957c478bd9Sstevel@tonic-gate 	prldap_set_system_errno( EINVAL );
3967c478bd9Sstevel@tonic-gate 	return( -1 );
3977c478bd9Sstevel@tonic-gate     }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate     if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
4007c478bd9Sstevel@tonic-gate 	prldap_set_system_errno( prldap_prerr2errno());
4017c478bd9Sstevel@tonic-gate 	return( -1 );
4027c478bd9Sstevel@tonic-gate     }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate     rc = -1;	/* pessimistic */
4057c478bd9Sstevel@tonic-gate     for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
4067c478bd9Sstevel@tonic-gate 		&status );
4077c478bd9Sstevel@tonic-gate 		rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
4087c478bd9Sstevel@tonic-gate 		parse_err = ldap_x_hostlist_next( &host, &port, status )) {
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 		if ( PRLDAP_DEFAULT_ADDRESS_FAMILY == PR_AF_INET6 &&
4137c478bd9Sstevel@tonic-gate 				PR_AF_INET == PR_NetAddrFamily( &addr )) {
4147c478bd9Sstevel@tonic-gate 			PRUint32	ipv4ip = addr.inet.ip;
4157c478bd9Sstevel@tonic-gate 			memset( &addr, 0, sizeof(addr));
4167c478bd9Sstevel@tonic-gate 			PR_ConvertIPv4AddrToIPv6( ipv4ip, &addr.ipv6.ip );
4177c478bd9Sstevel@tonic-gate 			addr.ipv6.family = PR_AF_INET6;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 	    rc = prldap_try_one_address( prsockp, &addr, port,
4217c478bd9Sstevel@tonic-gate 			timeout, options );
4227c478bd9Sstevel@tonic-gate 	} else {
4237c478bd9Sstevel@tonic-gate 	    if ( PR_SUCCESS == PR_GetIPNodeByName( host,
4247c478bd9Sstevel@tonic-gate 			PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT | PR_AI_ALL, hbuf,
4257c478bd9Sstevel@tonic-gate 			sizeof( hbuf ), &hent )) {
4267c478bd9Sstevel@tonic-gate 		PRIntn enumIndex = 0;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt(
4297c478bd9Sstevel@tonic-gate 			    enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) {
4307c478bd9Sstevel@tonic-gate 		    rc = prldap_try_one_address( prsockp, &addr, port,
4317c478bd9Sstevel@tonic-gate 				timeout, options );
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate 	    }
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
437*e944850bSMilan Jurik 	if ( NULL != hostname ) {
438*e944850bSMilan Jurik 		ldap_memfree(hostname);
439*e944850bSMilan Jurik 		hostname = NULL;
440*e944850bSMilan Jurik 	}
441*e944850bSMilan Jurik 	if ( rc >= 0 ) {
442*e944850bSMilan Jurik 		hostname = nsldapi_strdup(host);
443*e944850bSMilan Jurik 	}
4447c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
4457c478bd9Sstevel@tonic-gate 	ldap_memfree( host );
4467c478bd9Sstevel@tonic-gate     }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate     ldap_x_hostlist_statusfree( status );
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate     if ( rc < 0 ) {
4517c478bd9Sstevel@tonic-gate 	prldap_set_system_errno( prldap_prerr2errno());
4527c478bd9Sstevel@tonic-gate 	prldap_socket_arg_free( &prsockp );
4537c478bd9Sstevel@tonic-gate     } else {
4547c478bd9Sstevel@tonic-gate 	*socketargp = prsockp;
4557c478bd9Sstevel@tonic-gate     }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
4587c478bd9Sstevel@tonic-gate     if ( NULL != hostname && NULL != dhost ) *dhost = hostname;
4597c478bd9Sstevel@tonic-gate     else if ( NULL != hostname ) ldap_memfree(hostname);
4607c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate     return( rc );
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
4677c478bd9Sstevel@tonic-gate prldap_close( int s, struct lextiof_socket_private *socketarg )
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate     int		rc;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate     rc = 0;
4727c478bd9Sstevel@tonic-gate     if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
4737c478bd9Sstevel@tonic-gate 	rc = -1;
4747c478bd9Sstevel@tonic-gate 	prldap_set_system_errno( prldap_prerr2errno());
4757c478bd9Sstevel@tonic-gate     }
4767c478bd9Sstevel@tonic-gate     prldap_socket_arg_free( &socketarg );
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate     return( rc );
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate  * LDAP session handle creation callback.
4847c478bd9Sstevel@tonic-gate  *
4857c478bd9Sstevel@tonic-gate  * Allocate a session argument if not already done, and then call the
4867c478bd9Sstevel@tonic-gate  * thread's new handle function.
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
4897c478bd9Sstevel@tonic-gate prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate     if ( NULL == sessionarg ) {
4937c478bd9Sstevel@tonic-gate 	struct ldap_x_ext_io_fns	iofns;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	memset( &iofns, 0, sizeof(iofns));
4967c478bd9Sstevel@tonic-gate 	iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
4977c478bd9Sstevel@tonic-gate 	if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
4987c478bd9Sstevel@tonic-gate 		(void *)&iofns ) < 0 ) {
4997c478bd9Sstevel@tonic-gate 	    return( ldap_get_lderrno( ld, NULL, NULL ));
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	if ( NULL ==
5027c478bd9Sstevel@tonic-gate 		( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
5037c478bd9Sstevel@tonic-gate 	    return( LDAP_NO_MEMORY );
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 	if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
5067c478bd9Sstevel@tonic-gate 		    (void *)&iofns ) < 0 ) {
5077c478bd9Sstevel@tonic-gate 	    return( ldap_get_lderrno( ld, NULL, NULL ));
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate     }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate     return( LDAP_SUCCESS );
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /* only called/installed if shared is non-zero. */
5167c478bd9Sstevel@tonic-gate static int LDAP_CALLBACK
5177c478bd9Sstevel@tonic-gate prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate     int		rc;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate     if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
5227c478bd9Sstevel@tonic-gate 	rc = prldap_thread_new_handle( ld, sessionarg );
5237c478bd9Sstevel@tonic-gate     }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate     return( rc );
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate static void LDAP_CALLBACK
5307c478bd9Sstevel@tonic-gate prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate     prldap_session_arg_free( &sessionarg );
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /* only called/installed if shared is non-zero */
5377c478bd9Sstevel@tonic-gate static void LDAP_CALLBACK
5387c478bd9Sstevel@tonic-gate prldap_shared_disposehandle( LDAP *ld,
5397c478bd9Sstevel@tonic-gate 	struct lextiof_session_private *sessionarg )
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate     prldap_thread_dispose_handle( ld, sessionarg );
5427c478bd9Sstevel@tonic-gate     prldap_disposehandle( ld, sessionarg );
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate  * Allocate a session argument.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate static PRLDAPIOSessionArg *
5507c478bd9Sstevel@tonic-gate prldap_session_arg_alloc( void )
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate     PRLDAPIOSessionArg		*prsessp;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate     prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate     if ( NULL != prsessp ) {
5577c478bd9Sstevel@tonic-gate 	/* copy global defaults to the new session handle */
5587c478bd9Sstevel@tonic-gate 	prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
5597c478bd9Sstevel@tonic-gate     }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate     return( prsessp );
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate static void
5667c478bd9Sstevel@tonic-gate prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate     if ( NULL != prsesspp && NULL != *prsesspp ) {
5697c478bd9Sstevel@tonic-gate 	if ( NULL != (*prsesspp)->prsess_pollds ) {
5707c478bd9Sstevel@tonic-gate 	    PR_Free( (*prsesspp)->prsess_pollds );
5717c478bd9Sstevel@tonic-gate 	    (*prsesspp)->prsess_pollds = NULL;
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 	PR_Free( *prsesspp );
5747c478bd9Sstevel@tonic-gate 	*prsesspp = NULL;
5757c478bd9Sstevel@tonic-gate     }
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * Given an LDAP session handle, retrieve a session argument.
5817c478bd9Sstevel@tonic-gate  * Returns an LDAP error code.
5827c478bd9Sstevel@tonic-gate  */
5837c478bd9Sstevel@tonic-gate int
5847c478bd9Sstevel@tonic-gate prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate     struct ldap_x_ext_io_fns	iofns;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate     if ( NULL == ld || NULL == sessargpp ) {
5897c478bd9Sstevel@tonic-gate 	/* XXXmcs: NULL ld's are not supported */
5907c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
5917c478bd9Sstevel@tonic-gate 	return( LDAP_PARAM_ERROR );
5927c478bd9Sstevel@tonic-gate     }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate     memset( &iofns, 0, sizeof(iofns));
5957c478bd9Sstevel@tonic-gate     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
5967c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
5977c478bd9Sstevel@tonic-gate 	return( ldap_get_lderrno( ld, NULL, NULL ));
5987c478bd9Sstevel@tonic-gate     }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate     if ( NULL == iofns.lextiof_session_arg ) {
6017c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6027c478bd9Sstevel@tonic-gate 	return( LDAP_LOCAL_ERROR );
6037c478bd9Sstevel@tonic-gate     }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate     *sessargpp = iofns.lextiof_session_arg;
6067c478bd9Sstevel@tonic-gate     return( LDAP_SUCCESS );
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate  * Given an LDAP session handle, retrieve a socket argument.
6127c478bd9Sstevel@tonic-gate  * Returns an LDAP error code.
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate int
6157c478bd9Sstevel@tonic-gate prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate     Sockbuf *sbp;
6187c478bd9Sstevel@tonic-gate     struct lber_x_ext_io_fns    extiofns;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate     if ( NULL == ld || NULL == sockargpp ) {
6217c478bd9Sstevel@tonic-gate         /* XXXmcs: NULL ld's are not supported */
6227c478bd9Sstevel@tonic-gate         ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
6237c478bd9Sstevel@tonic-gate         return( LDAP_PARAM_ERROR );
6247c478bd9Sstevel@tonic-gate     }
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
6277c478bd9Sstevel@tonic-gate         return( ldap_get_lderrno( ld, NULL, NULL ));
6287c478bd9Sstevel@tonic-gate     }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate     memset( &extiofns, 0, sizeof(extiofns));
6317c478bd9Sstevel@tonic-gate     extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
6327c478bd9Sstevel@tonic-gate     if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
6337c478bd9Sstevel@tonic-gate         (void *)&extiofns ) < 0 ) {
6347c478bd9Sstevel@tonic-gate         return( ldap_get_lderrno( ld, NULL, NULL ));
6357c478bd9Sstevel@tonic-gate     }
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate     if ( NULL == extiofns.lbextiofn_socket_arg ) {
6387c478bd9Sstevel@tonic-gate         ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6397c478bd9Sstevel@tonic-gate         return( LDAP_LOCAL_ERROR );
6407c478bd9Sstevel@tonic-gate     }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate     *sockargpp = extiofns.lbextiofn_socket_arg;
6437c478bd9Sstevel@tonic-gate     return( LDAP_SUCCESS );
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate /*
6487c478bd9Sstevel@tonic-gate  * Allocate a socket argument.
6497c478bd9Sstevel@tonic-gate  */
6507c478bd9Sstevel@tonic-gate static PRLDAPIOSocketArg *
6517c478bd9Sstevel@tonic-gate prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate     PRLDAPIOSocketArg		*prsockp;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate     prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate     if ( NULL != prsockp && NULL != sessionarg ) {
6587c478bd9Sstevel@tonic-gate 	/* copy socket defaults from the session */
6597c478bd9Sstevel@tonic-gate 	prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
6607c478bd9Sstevel@tonic-gate     }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate     return( prsockp );
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate static void
6677c478bd9Sstevel@tonic-gate prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate     if ( NULL != prsockpp && NULL != *prsockpp ) {
6707c478bd9Sstevel@tonic-gate 	PR_Free( *prsockpp );
6717c478bd9Sstevel@tonic-gate 	*prsockpp = NULL;
6727c478bd9Sstevel@tonic-gate     }
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate static void *
6777c478bd9Sstevel@tonic-gate prldap_safe_realloc( void *ptr, PRUint32 size )
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate     void	*p;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate     if ( NULL == ptr ) {
6827c478bd9Sstevel@tonic-gate 	p = PR_Malloc( size );
6837c478bd9Sstevel@tonic-gate     } else {
6847c478bd9Sstevel@tonic-gate 	p = PR_Realloc( ptr, size );
6857c478bd9Sstevel@tonic-gate     }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate     return( p );
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate /* returns an LDAP result code */
6937c478bd9Sstevel@tonic-gate int
6947c478bd9Sstevel@tonic-gate prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate     int	rc = LDAP_SUCCESS;	/* optimistic */
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate     if ( NULL == prsessp ) {
6997c478bd9Sstevel@tonic-gate 	prldap_default_io_max_timeout = io_max_timeout;
7007c478bd9Sstevel@tonic-gate     } else {
7017c478bd9Sstevel@tonic-gate 	prsessp->prsess_io_max_timeout = io_max_timeout;
7027c478bd9Sstevel@tonic-gate     }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate     return( rc );
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /* returns an LDAP result code */
7097c478bd9Sstevel@tonic-gate int
7107c478bd9Sstevel@tonic-gate prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
7117c478bd9Sstevel@tonic-gate {
7127c478bd9Sstevel@tonic-gate     int	rc = LDAP_SUCCESS;	/* optimistic */
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate     if ( NULL == io_max_timeoutp ) {
7157c478bd9Sstevel@tonic-gate 	rc = LDAP_PARAM_ERROR;
7167c478bd9Sstevel@tonic-gate     } else if ( NULL == prsessp ) {
7177c478bd9Sstevel@tonic-gate 	*io_max_timeoutp = prldap_default_io_max_timeout;
7187c478bd9Sstevel@tonic-gate     } else {
7197c478bd9Sstevel@tonic-gate 	*io_max_timeoutp = prsessp->prsess_io_max_timeout;
7207c478bd9Sstevel@tonic-gate     }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate     return( rc );
7237c478bd9Sstevel@tonic-gate }
724