10Sstevel@tonic-gate /* 2*10284SMilan.Jurik@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public 80Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file 90Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of 100Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/ 110Sstevel@tonic-gate * 120Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS 130Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 140Sstevel@tonic-gate * implied. See the License for the specific language governing 150Sstevel@tonic-gate * rights and limitations under the License. 160Sstevel@tonic-gate * 170Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released 180Sstevel@tonic-gate * March 31, 1998. 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape 210Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 220Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All 230Sstevel@tonic-gate * Rights Reserved. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * Contributor(s): 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Extended I/O callback functions for libldap that use 300Sstevel@tonic-gate * NSPR (Netscape Portable Runtime) I/O. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * High level strategy: we use the socket-specific arg to hold our own data 330Sstevel@tonic-gate * structure that includes the NSPR file handle (PRFileDesc *), among other 340Sstevel@tonic-gate * useful information. We use the default argument to hold an LDAP session 350Sstevel@tonic-gate * handle specific data structure. 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include "ldappr-int.h" 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate #define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * Local function prototypes: 450Sstevel@tonic-gate */ 460Sstevel@tonic-gate static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout ); 470Sstevel@tonic-gate static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize, 480Sstevel@tonic-gate struct lextiof_socket_private *socketarg ); 490Sstevel@tonic-gate static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len, 500Sstevel@tonic-gate struct lextiof_socket_private *socketarg ); 510Sstevel@tonic-gate static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds, 520Sstevel@tonic-gate int timeout, struct lextiof_session_private *sessionarg ); 530Sstevel@tonic-gate static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport, 540Sstevel@tonic-gate int timeout, unsigned long options, 550Sstevel@tonic-gate struct lextiof_session_private *sessionarg, 560Sstevel@tonic-gate struct lextiof_socket_private **socketargp 570Sstevel@tonic-gate #ifdef _SOLARIS_SDK 580Sstevel@tonic-gate , void **dhost ); 590Sstevel@tonic-gate #else 600Sstevel@tonic-gate ); 610Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 620Sstevel@tonic-gate static int LDAP_CALLBACK prldap_close( int s, 630Sstevel@tonic-gate struct lextiof_socket_private *socketarg ); 640Sstevel@tonic-gate static int LDAP_CALLBACK prldap_newhandle( LDAP *ld, 650Sstevel@tonic-gate struct lextiof_session_private *sessionarg ); 660Sstevel@tonic-gate static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld, 670Sstevel@tonic-gate struct lextiof_session_private *sessionarg ); 680Sstevel@tonic-gate static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld, 690Sstevel@tonic-gate struct lextiof_session_private *sessionarg ); 700Sstevel@tonic-gate static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld, 710Sstevel@tonic-gate struct lextiof_session_private *sessionarg ); 720Sstevel@tonic-gate static PRLDAPIOSessionArg *prldap_session_arg_alloc( void ); 730Sstevel@tonic-gate static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp ); 740Sstevel@tonic-gate static PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg ); 750Sstevel@tonic-gate static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp ); 760Sstevel@tonic-gate static void *prldap_safe_realloc( void *ptr, PRUint32 size ); 770Sstevel@tonic-gate 780Sstevel@tonic-gate 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Local macros: 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate /* given a socket-specific arg, return the corresponding PRFileDesc * */ 840Sstevel@tonic-gate #define PRLDAP_GET_PRFD( socketarg ) \ 850Sstevel@tonic-gate (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd) 860Sstevel@tonic-gate 870Sstevel@tonic-gate /* 880Sstevel@tonic-gate * Static variables. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT; 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Install NSPR I/O functions into ld (if ld is NULL, they are installed 940Sstevel@tonic-gate * as the default functions for new LDAP * handles). 950Sstevel@tonic-gate * 960Sstevel@tonic-gate * Returns 0 if all goes well and -1 if not. 970Sstevel@tonic-gate */ 980Sstevel@tonic-gate int 990Sstevel@tonic-gate prldap_install_io_functions( LDAP *ld, int shared ) 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 1040Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 1050Sstevel@tonic-gate iofns.lextiof_read = prldap_read; 1060Sstevel@tonic-gate iofns.lextiof_write = prldap_write; 1070Sstevel@tonic-gate iofns.lextiof_poll = prldap_poll; 1080Sstevel@tonic-gate iofns.lextiof_connect = prldap_connect; 1090Sstevel@tonic-gate iofns.lextiof_close = prldap_close; 1100Sstevel@tonic-gate if ( shared ) { 1110Sstevel@tonic-gate iofns.lextiof_newhandle = prldap_shared_newhandle; 1120Sstevel@tonic-gate iofns.lextiof_disposehandle = prldap_shared_disposehandle; 1130Sstevel@tonic-gate } else { 1140Sstevel@tonic-gate iofns.lextiof_newhandle = prldap_newhandle; 1150Sstevel@tonic-gate iofns.lextiof_disposehandle = prldap_disposehandle; 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate if ( NULL != ld ) { 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * If we are dealing with a real ld, we allocate the session specific 1200Sstevel@tonic-gate * data structure now. If not allocated here, it will be allocated 1210Sstevel@tonic-gate * inside prldap_newhandle() or prldap_shared_newhandle(). 1220Sstevel@tonic-gate */ 1230Sstevel@tonic-gate if ( NULL == 1240Sstevel@tonic-gate ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) { 1250Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL ); 1260Sstevel@tonic-gate return( -1 ); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate } else { 1290Sstevel@tonic-gate iofns.lextiof_session_arg = NULL; 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) { 1330Sstevel@tonic-gate prldap_session_arg_free( 1340Sstevel@tonic-gate (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg ); 1350Sstevel@tonic-gate return( -1 ); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate return( 0 ); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate static PRIntervalTime 1430Sstevel@tonic-gate prldap_timeout2it( int ms_timeout, int ms_maxtimeout ) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate PRIntervalTime prit; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) { 1480Sstevel@tonic-gate prit = PR_INTERVAL_NO_WAIT; 1490Sstevel@tonic-gate } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) { 1500Sstevel@tonic-gate prit = PR_INTERVAL_NO_TIMEOUT; 1510Sstevel@tonic-gate } else { 1520Sstevel@tonic-gate prit = PR_MillisecondsToInterval( ms_timeout ); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* cap at maximum I/O timeout */ 1560Sstevel@tonic-gate if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) { 1570Sstevel@tonic-gate prit = LDAP_X_IO_TIMEOUT_NO_WAIT; 1580Sstevel@tonic-gate } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) { 1590Sstevel@tonic-gate if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout || 1600Sstevel@tonic-gate ms_timeout > ms_maxtimeout ) { 1610Sstevel@tonic-gate prit = PR_MillisecondsToInterval( ms_maxtimeout ); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate #ifdef PRLDAP_DEBUG 1660Sstevel@tonic-gate if ( PR_INTERVAL_NO_WAIT == prit ) { 1670Sstevel@tonic-gate fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" ); 1680Sstevel@tonic-gate } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) { 1690Sstevel@tonic-gate fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" ); 1700Sstevel@tonic-gate } else { 1710Sstevel@tonic-gate fprintf( stderr, "prldap_timeout2it: %dms\n", 1720Sstevel@tonic-gate PR_IntervalToMilliseconds(prit)); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */ 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate return( prit ); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate static int LDAP_CALLBACK 1810Sstevel@tonic-gate prldap_read( int s, void *buf, int bufsize, 1820Sstevel@tonic-gate struct lextiof_socket_private *socketarg ) 1830Sstevel@tonic-gate { 1840Sstevel@tonic-gate PRIntervalTime prit; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT, 1870Sstevel@tonic-gate socketarg->prsock_io_max_timeout ); 1880Sstevel@tonic-gate return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit )); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate static int LDAP_CALLBACK 1930Sstevel@tonic-gate prldap_write( int s, const void *buf, int len, 1940Sstevel@tonic-gate struct lextiof_socket_private *socketarg ) 1950Sstevel@tonic-gate { 1960Sstevel@tonic-gate PRIntervalTime prit; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT, 1990Sstevel@tonic-gate socketarg->prsock_io_max_timeout ); 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Note the 4th parameter (flags) to PR_Send() has been obsoleted and 2030Sstevel@tonic-gate * must always be 0 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit )); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate struct prldap_eventmap_entry { 2100Sstevel@tonic-gate PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */ 2110Sstevel@tonic-gate int evm_ldap; /* LDAP poll event */ 2120Sstevel@tonic-gate }; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate static struct prldap_eventmap_entry prldap_eventmap[] = { 2150Sstevel@tonic-gate { PR_POLL_READ, LDAP_X_POLLIN }, 2160Sstevel@tonic-gate { PR_POLL_EXCEPT, LDAP_X_POLLPRI }, 2170Sstevel@tonic-gate { PR_POLL_WRITE, LDAP_X_POLLOUT }, 2180Sstevel@tonic-gate { PR_POLL_ERR, LDAP_X_POLLERR }, 2190Sstevel@tonic-gate { PR_POLL_HUP, LDAP_X_POLLHUP }, 2200Sstevel@tonic-gate { PR_POLL_NVAL, LDAP_X_POLLNVAL }, 2210Sstevel@tonic-gate }; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate #define PRLDAP_EVENTMAP_ENTRIES \ 2240Sstevel@tonic-gate sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry ) 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate static int LDAP_CALLBACK 2270Sstevel@tonic-gate prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout, 2280Sstevel@tonic-gate struct lextiof_session_private *sessionarg ) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate PRLDAPIOSessionArg *prsessp = sessionarg; 2310Sstevel@tonic-gate PRPollDesc *pds; 2320Sstevel@tonic-gate int i, j, rc; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if ( NULL == prsessp ) { 2350Sstevel@tonic-gate prldap_set_system_errno( EINVAL ); 2360Sstevel@tonic-gate return( -1 ); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* allocate or resize NSPR poll descriptor array */ 2400Sstevel@tonic-gate if ( prsessp->prsess_pollds_count < nfds ) { 2410Sstevel@tonic-gate pds = prldap_safe_realloc( prsessp->prsess_pollds, 2420Sstevel@tonic-gate ( nfds + PRLDAP_POLL_ARRAY_GROWTH ) 2430Sstevel@tonic-gate * sizeof( PRPollDesc )); 2440Sstevel@tonic-gate if ( NULL == pds ) { 2450Sstevel@tonic-gate prldap_set_system_errno( prldap_prerr2errno()); 2460Sstevel@tonic-gate return( -1 ); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate prsessp->prsess_pollds = pds; 2490Sstevel@tonic-gate prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH; 2500Sstevel@tonic-gate } else { 2510Sstevel@tonic-gate pds = prsessp->prsess_pollds; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* populate NSPR poll info. based on LDAP info. */ 2550Sstevel@tonic-gate for ( i = 0; i < nfds; ++i ) { 2560Sstevel@tonic-gate if ( NULL == fds[i].lpoll_socketarg ) { 2570Sstevel@tonic-gate pds[i].fd = NULL; 2580Sstevel@tonic-gate } else { 2590Sstevel@tonic-gate pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg ); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate pds[i].in_flags = pds[i].out_flags = 0; 2620Sstevel@tonic-gate if ( fds[i].lpoll_fd >= 0 ) { 2630Sstevel@tonic-gate for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) { 2640Sstevel@tonic-gate if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap ) 2650Sstevel@tonic-gate != 0 ) { 2660Sstevel@tonic-gate pds[i].in_flags |= prldap_eventmap[j].evm_nspr; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate fds[i].lpoll_revents = 0; /* clear revents */ 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* call PR_Poll() to do the real work */ 2740Sstevel@tonic-gate rc = PR_Poll( pds, nfds, 2750Sstevel@tonic-gate prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout )); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* populate LDAP info. based on NSPR results */ 2780Sstevel@tonic-gate for ( i = 0; i < nfds; ++i ) { 2790Sstevel@tonic-gate if ( pds[i].fd != NULL ) { 2800Sstevel@tonic-gate for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) { 2810Sstevel@tonic-gate if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr ) 2820Sstevel@tonic-gate != 0 ) { 2830Sstevel@tonic-gate fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap; 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate return( rc ); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * Utility function to try one TCP connect() 2950Sstevel@tonic-gate * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp. 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate static int 2980Sstevel@tonic-gate prldap_try_one_address( struct lextiof_socket_private *prsockp, 2990Sstevel@tonic-gate PRNetAddr *addrp, int port, int timeout, unsigned long options ) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate /* 3020Sstevel@tonic-gate * Set up address and open a TCP socket: 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */ 3050Sstevel@tonic-gate PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) { 3060Sstevel@tonic-gate return( -1 ); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate if (( prsockp->prsock_prfd = PR_OpenTCPSocket( 3100Sstevel@tonic-gate PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) { 3110Sstevel@tonic-gate return( -1 ); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * Set nonblocking option if requested: 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) { 3180Sstevel@tonic-gate PRSocketOptionData optdata; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate optdata.option = PR_SockOpt_Nonblocking; 3210Sstevel@tonic-gate optdata.value.non_blocking = PR_TRUE; 3220Sstevel@tonic-gate if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata ) 3230Sstevel@tonic-gate != PR_SUCCESS ) { 3240Sstevel@tonic-gate prldap_set_system_errno( prldap_prerr2errno()); 3250Sstevel@tonic-gate PR_Close( prsockp->prsock_prfd ); 3260Sstevel@tonic-gate return( -1 ); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate #ifdef PRLDAP_DEBUG 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate char buf[ 256 ], *p, *fmtstr; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) { 3350Sstevel@tonic-gate strcpy( buf, "conversion failed!" ); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate if ( strncmp( buf, "::ffff:", 7 ) == 0 ) { 3380Sstevel@tonic-gate /* IPv4 address mapped into IPv6 address space */ 3390Sstevel@tonic-gate p = buf + 7; 3400Sstevel@tonic-gate fmtstr = "prldap_try_one_address(): Trying %s:%d...\n"; 3410Sstevel@tonic-gate } else { 3420Sstevel@tonic-gate p = buf; 3430Sstevel@tonic-gate fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n"; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port )); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Try to open the TCP connection itself: 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp, 3530Sstevel@tonic-gate prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))) { 3540Sstevel@tonic-gate PR_Close( prsockp->prsock_prfd ); 3550Sstevel@tonic-gate prsockp->prsock_prfd = NULL; 3560Sstevel@tonic-gate return( -1 ); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate #ifdef PRLDAP_DEBUG 3600Sstevel@tonic-gate fputs( "prldap_try_one_address(): Connected.\n", stderr ); 3610Sstevel@tonic-gate #endif /* PRLDAP_DEBUG */ 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * Success. Return a valid file descriptor (1 is always valid) 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate return( 1 ); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * XXXmcs: At present, this code ignores the timeout when doing DNS lookups. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate static int LDAP_CALLBACK 3740Sstevel@tonic-gate prldap_connect( const char *hostlist, int defport, int timeout, 3750Sstevel@tonic-gate unsigned long options, struct lextiof_session_private *sessionarg, 3760Sstevel@tonic-gate struct lextiof_socket_private **socketargp 3770Sstevel@tonic-gate #ifdef _SOLARIS_SDK 3780Sstevel@tonic-gate , void **dhost ) 3790Sstevel@tonic-gate #else 3800Sstevel@tonic-gate ) 3810Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate int rc, parse_err, port; 3840Sstevel@tonic-gate char *host, hbuf[ PR_NETDB_BUF_SIZE ]; 3850Sstevel@tonic-gate struct ldap_x_hostlist_status *status; 3860Sstevel@tonic-gate struct lextiof_socket_private *prsockp; 3870Sstevel@tonic-gate PRNetAddr addr; 3880Sstevel@tonic-gate PRHostEnt hent; 3890Sstevel@tonic-gate #ifdef _SOLARIS_SDK 3900Sstevel@tonic-gate char *hostname = NULL; 3910Sstevel@tonic-gate char *nsldapi_strdup(char *); 3920Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) { 3950Sstevel@tonic-gate prldap_set_system_errno( EINVAL ); 3960Sstevel@tonic-gate return( -1 ); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) { 4000Sstevel@tonic-gate prldap_set_system_errno( prldap_prerr2errno()); 4010Sstevel@tonic-gate return( -1 ); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate rc = -1; /* pessimistic */ 4050Sstevel@tonic-gate for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port, 4060Sstevel@tonic-gate &status ); 4070Sstevel@tonic-gate rc < 0 && LDAP_SUCCESS == parse_err && NULL != host; 4080Sstevel@tonic-gate parse_err = ldap_x_hostlist_next( &host, &port, status )) { 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) { 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if ( PRLDAP_DEFAULT_ADDRESS_FAMILY == PR_AF_INET6 && 4130Sstevel@tonic-gate PR_AF_INET == PR_NetAddrFamily( &addr )) { 4140Sstevel@tonic-gate PRUint32 ipv4ip = addr.inet.ip; 4150Sstevel@tonic-gate memset( &addr, 0, sizeof(addr)); 4160Sstevel@tonic-gate PR_ConvertIPv4AddrToIPv6( ipv4ip, &addr.ipv6.ip ); 4170Sstevel@tonic-gate addr.ipv6.family = PR_AF_INET6; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate rc = prldap_try_one_address( prsockp, &addr, port, 4210Sstevel@tonic-gate timeout, options ); 4220Sstevel@tonic-gate } else { 4230Sstevel@tonic-gate if ( PR_SUCCESS == PR_GetIPNodeByName( host, 4240Sstevel@tonic-gate PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT | PR_AI_ALL, hbuf, 4250Sstevel@tonic-gate sizeof( hbuf ), &hent )) { 4260Sstevel@tonic-gate PRIntn enumIndex = 0; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt( 4290Sstevel@tonic-gate enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) { 4300Sstevel@tonic-gate rc = prldap_try_one_address( prsockp, &addr, port, 4310Sstevel@tonic-gate timeout, options ); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate #ifdef _SOLARIS_SDK 437*10284SMilan.Jurik@Sun.COM if ( NULL != hostname ) { 438*10284SMilan.Jurik@Sun.COM ldap_memfree(hostname); 439*10284SMilan.Jurik@Sun.COM hostname = NULL; 440*10284SMilan.Jurik@Sun.COM } 441*10284SMilan.Jurik@Sun.COM if ( rc >= 0 ) { 442*10284SMilan.Jurik@Sun.COM hostname = nsldapi_strdup(host); 443*10284SMilan.Jurik@Sun.COM } 4440Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 4450Sstevel@tonic-gate ldap_memfree( host ); 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate ldap_x_hostlist_statusfree( status ); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate if ( rc < 0 ) { 4510Sstevel@tonic-gate prldap_set_system_errno( prldap_prerr2errno()); 4520Sstevel@tonic-gate prldap_socket_arg_free( &prsockp ); 4530Sstevel@tonic-gate } else { 4540Sstevel@tonic-gate *socketargp = prsockp; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate #ifdef _SOLARIS_SDK 4580Sstevel@tonic-gate if ( NULL != hostname && NULL != dhost ) *dhost = hostname; 4590Sstevel@tonic-gate else if ( NULL != hostname ) ldap_memfree(hostname); 4600Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate return( rc ); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate static int LDAP_CALLBACK 4670Sstevel@tonic-gate prldap_close( int s, struct lextiof_socket_private *socketarg ) 4680Sstevel@tonic-gate { 4690Sstevel@tonic-gate int rc; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate rc = 0; 4720Sstevel@tonic-gate if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) { 4730Sstevel@tonic-gate rc = -1; 4740Sstevel@tonic-gate prldap_set_system_errno( prldap_prerr2errno()); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate prldap_socket_arg_free( &socketarg ); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate return( rc ); 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * LDAP session handle creation callback. 4840Sstevel@tonic-gate * 4850Sstevel@tonic-gate * Allocate a session argument if not already done, and then call the 4860Sstevel@tonic-gate * thread's new handle function. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate static int LDAP_CALLBACK 4890Sstevel@tonic-gate prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 4900Sstevel@tonic-gate { 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if ( NULL == sessionarg ) { 4930Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 4960Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 4970Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 4980Sstevel@tonic-gate (void *)&iofns ) < 0 ) { 4990Sstevel@tonic-gate return( ldap_get_lderrno( ld, NULL, NULL )); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate if ( NULL == 5020Sstevel@tonic-gate ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) { 5030Sstevel@tonic-gate return( LDAP_NO_MEMORY ); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 5060Sstevel@tonic-gate (void *)&iofns ) < 0 ) { 5070Sstevel@tonic-gate return( ldap_get_lderrno( ld, NULL, NULL )); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate return( LDAP_SUCCESS ); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* only called/installed if shared is non-zero. */ 5160Sstevel@tonic-gate static int LDAP_CALLBACK 5170Sstevel@tonic-gate prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 5180Sstevel@tonic-gate { 5190Sstevel@tonic-gate int rc; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) { 5220Sstevel@tonic-gate rc = prldap_thread_new_handle( ld, sessionarg ); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate return( rc ); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate static void LDAP_CALLBACK 5300Sstevel@tonic-gate prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg ) 5310Sstevel@tonic-gate { 5320Sstevel@tonic-gate prldap_session_arg_free( &sessionarg ); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* only called/installed if shared is non-zero */ 5370Sstevel@tonic-gate static void LDAP_CALLBACK 5380Sstevel@tonic-gate prldap_shared_disposehandle( LDAP *ld, 5390Sstevel@tonic-gate struct lextiof_session_private *sessionarg ) 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate prldap_thread_dispose_handle( ld, sessionarg ); 5420Sstevel@tonic-gate prldap_disposehandle( ld, sessionarg ); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * Allocate a session argument. 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate static PRLDAPIOSessionArg * 5500Sstevel@tonic-gate prldap_session_arg_alloc( void ) 5510Sstevel@tonic-gate { 5520Sstevel@tonic-gate PRLDAPIOSessionArg *prsessp; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg )); 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate if ( NULL != prsessp ) { 5570Sstevel@tonic-gate /* copy global defaults to the new session handle */ 5580Sstevel@tonic-gate prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate return( prsessp ); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate static void 5660Sstevel@tonic-gate prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp ) 5670Sstevel@tonic-gate { 5680Sstevel@tonic-gate if ( NULL != prsesspp && NULL != *prsesspp ) { 5690Sstevel@tonic-gate if ( NULL != (*prsesspp)->prsess_pollds ) { 5700Sstevel@tonic-gate PR_Free( (*prsesspp)->prsess_pollds ); 5710Sstevel@tonic-gate (*prsesspp)->prsess_pollds = NULL; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate PR_Free( *prsesspp ); 5740Sstevel@tonic-gate *prsesspp = NULL; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * Given an LDAP session handle, retrieve a session argument. 5810Sstevel@tonic-gate * Returns an LDAP error code. 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate int 5840Sstevel@tonic-gate prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp ) 5850Sstevel@tonic-gate { 5860Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate if ( NULL == ld || NULL == sessargpp ) { 5890Sstevel@tonic-gate /* XXXmcs: NULL ld's are not supported */ 5900Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 5910Sstevel@tonic-gate return( LDAP_PARAM_ERROR ); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 5950Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 5960Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) { 5970Sstevel@tonic-gate return( ldap_get_lderrno( ld, NULL, NULL )); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if ( NULL == iofns.lextiof_session_arg ) { 6010Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 6020Sstevel@tonic-gate return( LDAP_LOCAL_ERROR ); 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate *sessargpp = iofns.lextiof_session_arg; 6060Sstevel@tonic-gate return( LDAP_SUCCESS ); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * Given an LDAP session handle, retrieve a socket argument. 6120Sstevel@tonic-gate * Returns an LDAP error code. 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate int 6150Sstevel@tonic-gate prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp ) 6160Sstevel@tonic-gate { 6170Sstevel@tonic-gate Sockbuf *sbp; 6180Sstevel@tonic-gate struct lber_x_ext_io_fns extiofns; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if ( NULL == ld || NULL == sockargpp ) { 6210Sstevel@tonic-gate /* XXXmcs: NULL ld's are not supported */ 6220Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 6230Sstevel@tonic-gate return( LDAP_PARAM_ERROR ); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) { 6270Sstevel@tonic-gate return( ldap_get_lderrno( ld, NULL, NULL )); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate memset( &extiofns, 0, sizeof(extiofns)); 6310Sstevel@tonic-gate extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; 6320Sstevel@tonic-gate if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS, 6330Sstevel@tonic-gate (void *)&extiofns ) < 0 ) { 6340Sstevel@tonic-gate return( ldap_get_lderrno( ld, NULL, NULL )); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if ( NULL == extiofns.lbextiofn_socket_arg ) { 6380Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 6390Sstevel@tonic-gate return( LDAP_LOCAL_ERROR ); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate *sockargpp = extiofns.lbextiofn_socket_arg; 6430Sstevel@tonic-gate return( LDAP_SUCCESS ); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * Allocate a socket argument. 6490Sstevel@tonic-gate */ 6500Sstevel@tonic-gate static PRLDAPIOSocketArg * 6510Sstevel@tonic-gate prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg ) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate PRLDAPIOSocketArg *prsockp; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg )); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if ( NULL != prsockp && NULL != sessionarg ) { 6580Sstevel@tonic-gate /* copy socket defaults from the session */ 6590Sstevel@tonic-gate prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate return( prsockp ); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate static void 6670Sstevel@tonic-gate prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp ) 6680Sstevel@tonic-gate { 6690Sstevel@tonic-gate if ( NULL != prsockpp && NULL != *prsockpp ) { 6700Sstevel@tonic-gate PR_Free( *prsockpp ); 6710Sstevel@tonic-gate *prsockpp = NULL; 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate static void * 6770Sstevel@tonic-gate prldap_safe_realloc( void *ptr, PRUint32 size ) 6780Sstevel@tonic-gate { 6790Sstevel@tonic-gate void *p; 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate if ( NULL == ptr ) { 6820Sstevel@tonic-gate p = PR_Malloc( size ); 6830Sstevel@tonic-gate } else { 6840Sstevel@tonic-gate p = PR_Realloc( ptr, size ); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate return( p ); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate /* returns an LDAP result code */ 6930Sstevel@tonic-gate int 6940Sstevel@tonic-gate prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout ) 6950Sstevel@tonic-gate { 6960Sstevel@tonic-gate int rc = LDAP_SUCCESS; /* optimistic */ 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate if ( NULL == prsessp ) { 6990Sstevel@tonic-gate prldap_default_io_max_timeout = io_max_timeout; 7000Sstevel@tonic-gate } else { 7010Sstevel@tonic-gate prsessp->prsess_io_max_timeout = io_max_timeout; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate return( rc ); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* returns an LDAP result code */ 7090Sstevel@tonic-gate int 7100Sstevel@tonic-gate prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp ) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate int rc = LDAP_SUCCESS; /* optimistic */ 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate if ( NULL == io_max_timeoutp ) { 7150Sstevel@tonic-gate rc = LDAP_PARAM_ERROR; 7160Sstevel@tonic-gate } else if ( NULL == prsessp ) { 7170Sstevel@tonic-gate *io_max_timeoutp = prldap_default_io_max_timeout; 7180Sstevel@tonic-gate } else { 7190Sstevel@tonic-gate *io_max_timeoutp = prsessp->prsess_io_max_timeout; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate return( rc ); 7230Sstevel@tonic-gate } 724