Back to index

lightning-sunbird  0.9+nobinonly
os-ip.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  *  Copyright (c) 1995 Regents of the University of Michigan.
00039  *  All rights reserved.
00040  */
00041 /*
00042  *  os-ip.c -- platform-specific TCP & UDP related code
00043  */
00044 
00045 #if 0
00046 #ifndef lint 
00047 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
00048 #endif
00049 #endif
00050 
00051 /*
00052  * On platforms where poll() does not exist, we use select().
00053  * Therefore, we should increase the number of file descriptors
00054  * we can use by #defining FD_SETSIZE to a large number before
00055  * we include <sys/select.h> or its equivalent.  We do not need
00056  * to do this for Windows, because on that platform there is no
00057  * relationship between FD_SETSIZE and the highest numbered file
00058  * descriptor we can use.  See the document fdsetsize.txt in
00059  * this directory for a description of the setting of FD_SETSIZE
00060  * for the OS'es we care about.
00061  */
00062 #ifndef NSLDAPI_HAVE_POLL
00063 /* XXX value for BSDI? */
00064 /* XXX value for macintosh (if applicable)? */
00065 #endif
00066 
00067 #include "ldap-int.h"
00068 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
00069 #include <signal.h>
00070 #endif
00071 
00072 #ifdef NSLDAPI_HAVE_POLL
00073 #include <poll.h>
00074 #endif
00075 
00076 
00077 #ifdef _WINDOWS
00078 #define NSLDAPI_INVALID_OS_SOCKET( s )    ((s) == INVALID_SOCKET)
00079 #else
00080 #define NSLDAPI_INVALID_OS_SOCKET( s )    ((s) < 0 )    
00081 #endif
00082 
00083 
00084 #define NSLDAPI_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
00085 
00086 
00087 /*
00088  * Structures and union for tracking status of network sockets
00089  */
00090 #ifdef NSLDAPI_HAVE_POLL
00091 struct nsldapi_os_statusinfo {            /* used with native OS poll() */
00092        struct pollfd        *ossi_pollfds;
00093        int                  ossi_pollfds_size;
00094 };
00095 #else /* NSLDAPI_HAVE_POLL */
00096 struct nsldapi_os_statusinfo {            /* used with native OS select() */
00097        fd_set               ossi_readfds;
00098        fd_set               ossi_writefds;
00099        fd_set               ossi_use_readfds;
00100        fd_set               ossi_use_writefds;
00101 };
00102 #endif /* else NSLDAPI_HAVE_POLL */
00103 
00104 struct nsldapi_cb_statusinfo {            /* used with ext. I/O poll() callback */
00105     LDAP_X_PollFD           *cbsi_pollfds;
00106     int                            cbsi_pollfds_size;
00107 };
00108 
00109 /*
00110  * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
00111  * matches the LDAP_X_PollFD pollfd.
00112  */
00113 #ifdef _WINDOWS
00114 #define NSLDAPI_CB_POLL_SD_CAST           (unsigned int)
00115 #else
00116 #define NSLDAPI_CB_POLL_SD_CAST
00117 #endif
00118 #define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
00119     ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd) && \
00120     (sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg)
00121 
00122 
00123 struct nsldapi_iostatus_info {
00124        int                         ios_type;
00125 #define NSLDAPI_IOSTATUS_TYPE_OSNATIVE           1   /* poll() or select() */
00126 #define NSLDAPI_IOSTATUS_TYPE_CALLBACK           2   /* poll()-like */
00127        int                         ios_read_count;
00128        int                         ios_write_count;
00129        union {
00130            struct nsldapi_os_statusinfo   ios_osinfo;
00131            struct nsldapi_cb_statusinfo   ios_cbinfo;
00132        } ios_status;
00133 };
00134 
00135 #ifndef NSLDAPI_AVOID_OS_SOCKETS
00136 #ifdef NSLDAPI_HAVE_POLL
00137 static int nsldapi_add_to_os_pollfds( int fd,
00138     struct nsldapi_os_statusinfo *pip, short events );
00139 static int nsldapi_clear_from_os_pollfds( int fd,
00140     struct nsldapi_os_statusinfo *pip, short events );
00141 static int nsldapi_find_in_os_pollfds( int fd,
00142     struct nsldapi_os_statusinfo *pip, short revents );
00143 #endif /* NSLDAPI_HAVE_POLL */
00144 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00145 
00146 static int nsldapi_iostatus_init_nolock( LDAP *ld );
00147 static int nsldapi_add_to_cb_pollfds( Sockbuf *sb,
00148     struct nsldapi_cb_statusinfo *pip, short events );
00149 static int nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
00150     struct nsldapi_cb_statusinfo *pip, short events );
00151 static int nsldapi_find_in_cb_pollfds( Sockbuf *sb,
00152     struct nsldapi_cb_statusinfo *pip, short revents );
00153 
00154 
00155 #ifdef irix
00156 #ifndef _PR_THREADS
00157 /*
00158  * XXXmcs: on IRIX NSPR's poll() and select() wrappers will crash if NSPR
00159  * has not been initialized.  We work around the problem by bypassing
00160  * the NSPR wrapper functions and going directly to the OS' functions.
00161  */
00162 #define NSLDAPI_POLL        _poll
00163 #define NSLDAPI_SELECT             _select
00164 extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
00165 extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
00166         fd_set *exceptfds, struct timeval *timeout);
00167 #else /* _PR_THREADS */
00168 #define NSLDAPI_POLL        poll
00169 #define NSLDAPI_SELECT             select
00170 #endif /* else _PR_THREADS */
00171 #else /* irix */
00172 #define NSLDAPI_POLL        poll
00173 #define NSLDAPI_SELECT             select
00174 #endif /* else irix */
00175 
00176 
00177 static LBER_SOCKET nsldapi_os_socket( LDAP *ld, int secure, int domain,
00178        int type, int protocol );
00179 static int nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp );
00180 static int nsldapi_os_connect_with_to( LBER_SOCKET s, struct sockaddr *name,
00181        int namelen, int msec_timeout );
00182 
00183 /*
00184  * Function typedefs used by nsldapi_try_each_host()
00185  */
00186 typedef LBER_SOCKET (NSLDAPI_SOCKET_FN)( LDAP *ld, int secure, int domain,
00187            int type, int protocol );
00188 typedef int (NSLDAPI_IOCTL_FN)( LBER_SOCKET s, int option, int *statusp );
00189 typedef int (NSLDAPI_CONNECT_WITH_TO_FN )( LBER_SOCKET s, struct sockaddr *name,
00190        int namelen, int msec_timeout );
00191 typedef int (NSLDAPI_CONNECT_FN )( LBER_SOCKET s, struct sockaddr *name,
00192        int namelen );
00193 typedef int (NSLDAPI_CLOSE_FN )( LBER_SOCKET s );
00194 
00195 static int nsldapi_try_each_host( LDAP *ld, const char *hostlist, int defport,
00196        int secure, NSLDAPI_SOCKET_FN *socketfn, NSLDAPI_IOCTL_FN *ioctlfn,
00197        NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
00198        NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn );
00199 
00200 
00201 static int
00202 nsldapi_os_closesocket( LBER_SOCKET s )
00203 {
00204        int    rc;
00205 
00206 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00207        rc = -1;
00208 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00209 #ifdef _WINDOWS
00210        rc = closesocket( s );
00211 #else /* _WINDOWS */
00212        rc = close( s );
00213 #endif /* _WINDOWS */
00214 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00215        return( rc );
00216 }
00217 
00218 
00219 static LBER_SOCKET
00220 nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
00221 {
00222 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00223        return -1;
00224 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00225        int           s, invalid_socket;
00226        char          *errmsg = NULL;
00227 
00228        if ( secure ) {
00229               LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
00230                          nsldapi_strdup( "secure mode not supported" ));
00231               return( -1 );
00232        }
00233 
00234        s = socket( domain, type, protocol );
00235 
00236        /*
00237         * if the socket() call failed or it returned a socket larger
00238         * than we can deal with, return a "local error."
00239         */
00240        if ( NSLDAPI_INVALID_OS_SOCKET( s )) {
00241               errmsg = "unable to create a socket";
00242               invalid_socket = 1;
00243        } else {      /* valid socket -- check for overflow */
00244               invalid_socket = 0;
00245 #if !defined(NSLDAPI_HAVE_POLL) && !defined(_WINDOWS)
00246               /* not on Windows and do not have poll() */
00247               if ( s >= FD_SETSIZE ) {
00248                      errmsg = "can't use socket >= FD_SETSIZE";
00249               }
00250 #endif
00251        }
00252 
00253        if ( errmsg != NULL ) {     /* local socket error */
00254               if ( !invalid_socket ) {
00255                      nsldapi_os_closesocket( s );
00256               }
00257               errmsg = nsldapi_strdup( errmsg );
00258               LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
00259               return( -1 );
00260        }
00261 
00262        return( s );
00263 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00264 }
00265 
00266 
00267 
00268 /*
00269  * Non-blocking connect call function
00270  */
00271 static int
00272 nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
00273        int salen, int msec)
00274 {
00275 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00276        return -1;
00277 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00278        int           n, error;
00279        int           len;
00280 #if defined(_WINDOWS) || defined(XP_OS2)
00281        int           nonblock = 1;
00282        int           block = 0;
00283 #else
00284        int           flags;
00285 #endif /* _WINDOWS */
00286 #ifdef NSLDAPI_HAVE_POLL
00287        struct pollfd   pfd;
00288 #else
00289        struct timeval       tval;
00290        fd_set        rset, wset;
00291 #ifdef _WINDOWS
00292        fd_set        eset;
00293 #endif
00294 #endif /* NSLDAPI_HAVE_POLL */
00295 
00296 
00297        LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
00298               msec, 0, 0);
00299 
00300 #ifdef _WINDOWS
00301        ioctlsocket(sockfd, FIONBIO, &nonblock);
00302 #elif defined(XP_OS2)
00303   ioctl( sockfd, FIONBIO, &nonblock, sizeof(nonblock) );
00304 #else
00305        flags = fcntl(sockfd, F_GETFL, 0);
00306        fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
00307 #endif /* _WINDOWS */
00308 
00309        error = 0;
00310        if ((n = connect(sockfd, saptr, salen)) < 0)
00311 #ifdef _WINDOWS
00312               if ((n != SOCKET_ERROR) &&  (WSAGetLastError() != WSAEWOULDBLOCK)) {
00313 #else
00314               if (errno != EINPROGRESS) {
00315 #endif /* _WINDOWS */
00316 #ifdef LDAP_DEBUG
00317                      if ( ldap_debug & LDAP_DEBUG_TRACE ) {
00318                             perror("connect");
00319                      }
00320 #endif
00321                      return (-1);
00322               }
00323 
00324        /* success */
00325        if (n == 0)
00326               goto done;
00327 
00328 #ifdef NSLDAPI_HAVE_POLL
00329        pfd.fd = sockfd;
00330        pfd.events = POLLOUT;
00331 #else
00332        FD_ZERO(&rset);
00333        FD_SET(sockfd, &rset);
00334        wset = rset;
00335 
00336 #ifdef _WINDOWS
00337        eset = rset;
00338 #endif /* _WINDOWS */
00339 #endif /* NSLDAPI_HAVE_POLL */
00340 
00341        if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
00342               LDAPDebug( LDAP_DEBUG_TRACE, "Invalid timeout value detected.."
00343                      "resetting connect timeout to default value "
00344                      "(LDAP_X_IO_TIMEOUT_NO_TIMEOUT\n", 0, 0, 0);
00345               msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
00346 #ifndef NSLDAPI_HAVE_POLL
00347        } else {
00348               if (msec != 0) {
00349                      tval.tv_sec = msec / 1000;
00350                      tval.tv_usec = 1000 * ( msec % 1000 );
00351               } else {
00352                      tval.tv_sec = 0;
00353               }
00354               tval.tv_usec = 0;
00355 #endif /* NSLDAPI_HAVE_POLL */
00356        }
00357 
00358 #ifdef NSLDAPI_HAVE_POLL
00359        if ((n = poll(&pfd, 1,
00360               (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? msec : -1)) == 0) {
00361               errno = ETIMEDOUT;
00362               return (-1);
00363        }
00364        if (pfd.revents & POLLOUT) {
00365               len = sizeof(error);
00366               if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
00367                      < 0)
00368                      return (-1);
00369 #ifdef LDAP_DEBUG
00370        } else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
00371               perror("poll error: sockfd not set");
00372 #endif
00373        }
00374 
00375 #else /* NSLDAPI_HAVE_POLL */
00376        /* if timeval structure == NULL, select will block indefinitely */
00377        /*                   != NULL, and value == 0, select will */
00378        /*                            not block */
00379        /* Windows is a bit quirky on how it behaves w.r.t nonblocking */
00380        /* connects.  If the connect fails, the exception fd, eset, is */
00381        /* set to show the failure.  The first argument in select is */
00382        /* ignored */
00383 
00384 #ifdef _WINDOWS
00385        if ((n = select(sockfd +1, &rset, &wset, &eset,
00386               (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
00387               errno = WSAETIMEDOUT;
00388               return (-1);
00389        }
00390        /* if wset is set, the connect worked */
00391        if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
00392               len = sizeof(error);
00393               if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
00394                      < 0)
00395                      return (-1);
00396               goto done;
00397        }
00398 
00399        /* if eset is set, the connect failed */
00400        if (FD_ISSET(sockfd, &eset)) {
00401               return (-1);
00402        }
00403 
00404        /* failure on select call */
00405        if (n == SOCKET_ERROR) {
00406               perror("select error: SOCKET_ERROR returned");
00407               return (-1);         
00408        }
00409 #else
00410        if ((n = select(sockfd +1, &rset, &wset, NULL,
00411               (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
00412               errno = ETIMEDOUT;
00413               return (-1);
00414        }
00415        if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
00416               len = sizeof(error);
00417               if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
00418                      < 0)
00419                      return (-1);
00420 #ifdef LDAP_DEBUG
00421        } else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
00422               perror("select error: sockfd not set");
00423 #endif
00424        }
00425 #endif /* _WINDOWS */
00426 #endif /* NSLDAPI_HAVE_POLL */
00427 
00428 done:
00429 #ifdef _WINDOWS
00430        ioctlsocket(sockfd, FIONBIO, &block);
00431 #elif defined(XP_OS2)
00432   ioctl( sockfd, FIONBIO, &nonblock, sizeof(block) );
00433 #else
00434        fcntl(sockfd, F_SETFL, flags);
00435 #endif /* _WINDOWS */
00436 
00437        if (error) {
00438               errno = error;
00439               return (-1);
00440        }
00441 
00442        return (0);
00443 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00444 }
00445 
00446 
00447 static int
00448 nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
00449 {
00450 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00451        return -1;
00452 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00453        int           err;
00454 #if defined(_WINDOWS) || defined(XP_OS2)
00455        u_long        iostatus;
00456 #endif
00457 
00458        if ( FIONBIO != option ) {
00459               return( -1 );
00460        }
00461 
00462 #ifdef _WINDOWS
00463        iostatus = *(u_long *)statusp;
00464        err = ioctlsocket( s, FIONBIO, &iostatus );
00465 #else
00466 #ifdef XP_OS2
00467        err = ioctl( s, FIONBIO, (caddr_t)&iostatus, sizeof(iostatus) );
00468 #else
00469        err = ioctl( s, FIONBIO, (caddr_t)statusp );
00470 #endif
00471 #endif
00472 
00473        return( err );
00474 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00475 }
00476 
00477 
00478 int
00479 nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
00480               int defport, int secure, char **krbinstancep )
00481 /*
00482  * "defport" must be in host byte order
00483  * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
00484  * if -1 is returned, ld_errno is set
00485  */
00486 {
00487        int           s;
00488 
00489        LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
00490            NULL == hostlist ? "NULL" : hostlist, defport, 0 );
00491 
00492        /*
00493         * If an extended I/O connect callback has been defined, just use it.
00494         */
00495        if ( NULL != ld->ld_extconnect_fn ) {
00496               unsigned long connect_opts = 0;
00497 
00498               if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
00499                      connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
00500               }
00501               if ( secure ) {
00502                      connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
00503               }
00504               s = ld->ld_extconnect_fn( hostlist, defport,
00505                   ld->ld_connect_timeout, connect_opts,
00506                   ld->ld_ext_session_arg,
00507                   &sb->sb_ext_io_fns.lbextiofn_socket_arg );
00508 
00509        } else {
00510 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00511               return( -1 );
00512 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00513               s = nsldapi_try_each_host( ld, hostlist,
00514                      defport, secure, nsldapi_os_socket,
00515                      nsldapi_os_ioctl, nsldapi_os_connect_with_to,
00516                      NULL, nsldapi_os_closesocket );
00517 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00518        }
00519 
00520        if ( s < 0 ) {
00521               LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
00522               return( -1 );
00523        }
00524 
00525        sb->sb_sd = s;
00526 
00527        /*
00528         * Set krbinstancep (canonical name of host for use by Kerberos).
00529         */
00530 #ifdef KERBEROS
00531        char   *p;
00532 
00533        if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
00534            && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
00535               *p = '\0';
00536        }
00537 #else /* KERBEROS */
00538        *krbinstancep = NULL;
00539 #endif /* KERBEROS */
00540 
00541        return( 0 );
00542 }
00543 
00544 
00545 /*
00546  * Returns a socket number if successful and -1 if an error occurs.
00547  */
00548 static int
00549 nsldapi_try_each_host( LDAP *ld, const char *hostlist,
00550        int defport, int secure, NSLDAPI_SOCKET_FN *socketfn,
00551        NSLDAPI_IOCTL_FN *ioctlfn, NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
00552        NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn )
00553 {
00554 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00555        return -1;
00556 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00557        int                  rc, i, s, err, connected, use_hp;
00558        int                  parse_err, port;
00559        struct sockaddr_in   sin;
00560        nsldapi_in_addr_t    address;
00561        char                 **addrlist, *ldhpbuf, *ldhpbuf_allocd;
00562        char                 *host;
00563        LDAPHostEnt          ldhent, *ldhp;
00564        struct hostent              *hp;
00565        struct ldap_x_hostlist_status      *status;
00566 #ifdef GETHOSTBYNAME_BUF_T
00567        GETHOSTBYNAME_BUF_T  hbuf;
00568        struct hostent              hent;
00569 #endif /* GETHOSTBYNAME_BUF_T */
00570 
00571        connected = 0;
00572        parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
00573             &status );
00574        while ( !connected && LDAP_SUCCESS == parse_err && host != NULL ) {
00575               ldhpbuf_allocd = NULL;
00576               ldhp = NULL;
00577               hp = NULL;
00578               s = 0;
00579               use_hp = 0;
00580               addrlist = NULL;
00581 
00582 
00583               if (( address = inet_addr( host )) == -1 ) {
00584                      if ( ld->ld_dns_gethostbyname_fn == NULL ) {
00585                             if (( hp = GETHOSTBYNAME( host, &hent, hbuf,
00586                                 sizeof(hbuf), &err )) != NULL ) {
00587                                    addrlist = hp->h_addr_list;
00588                             }
00589                      } else {
00590                             /*
00591                              * DNS callback installed... use it.
00592                              */
00593 #ifdef GETHOSTBYNAME_buf_t
00594                             /* avoid allocation by using hbuf if large enough */
00595                             if ( sizeof( hbuf ) < ld->ld_dns_bufsize ) {
00596                                    ldhpbuf = ldhpbuf_allocd
00597                                        = NSLDAPI_MALLOC( ld->ld_dns_bufsize );
00598                             } else {
00599                                    ldhpbuf = (char *)hbuf;
00600                             }
00601 #else /* GETHOSTBYNAME_buf_t */
00602                             ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
00603                                 ld->ld_dns_bufsize );
00604 #endif /* else GETHOSTBYNAME_buf_t */
00605 
00606                             if ( ldhpbuf == NULL ) {
00607                                    LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY,
00608                                        NULL, NULL );
00609                                    ldap_memfree( host );
00610                                    ldap_x_hostlist_statusfree( status );
00611                                    return( -1 );
00612                             }
00613 
00614                             if (( ldhp = ld->ld_dns_gethostbyname_fn( host,
00615                                 &ldhent, ldhpbuf, ld->ld_dns_bufsize, &err,
00616                                 ld->ld_dns_extradata )) != NULL ) {
00617                                    addrlist = ldhp->ldaphe_addr_list;
00618                             }
00619                      }
00620 
00621                      if ( addrlist == NULL ) {
00622                             LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
00623                             LDAP_SET_ERRNO( ld, EHOSTUNREACH );  /* close enough */
00624                             if ( ldhpbuf_allocd != NULL ) {
00625                                    NSLDAPI_FREE( ldhpbuf_allocd );
00626                             }
00627                             ldap_memfree( host );
00628                             ldap_x_hostlist_statusfree( status );
00629                             return( -1 );
00630                      }
00631                      use_hp = 1;
00632               }
00633 
00634               rc = -1;
00635               for ( i = 0; !use_hp || ( addrlist[ i ] != 0 ); i++ ) {
00636                      if ( -1 == ( s = (*socketfn)( ld, secure, AF_INET,
00637                                    SOCK_STREAM, 0 ))) {
00638                             if ( ldhpbuf_allocd != NULL ) {
00639                                    NSLDAPI_FREE( ldhpbuf_allocd );
00640                             }
00641                             ldap_memfree( host );
00642                             ldap_x_hostlist_statusfree( status );
00643                             return( -1 );
00644                      }
00645 
00646                      if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
00647                             int    iostatus = 1;
00648 
00649                             err = (*ioctlfn)( s, FIONBIO, &iostatus );
00650                             if ( err == -1 ) {
00651                                    LDAPDebug( LDAP_DEBUG_ANY,
00652                                        "FIONBIO ioctl failed on %d\n",
00653                                        s, 0, 0 );
00654                             }
00655                      }
00656 
00657                      (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
00658                      sin.sin_family = AF_INET;
00659                      sin.sin_port = htons( (unsigned short)port );
00660 
00661                      SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
00662                          ( use_hp ? (char *) addrlist[ i ] :
00663                          (char *) &address ), sizeof( sin.sin_addr.s_addr) );
00664 
00665                      {
00666 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
00667 /*
00668  * Block all of the signals that might interrupt connect() since there
00669  * is an OS bug that causes connect() to fail if it is restarted.  Look in
00670  * ns/netsite/ldap/include/portable.h for the definition of
00671  * LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
00672  */
00673                             sigset_t      ints_off, oldset;
00674 
00675                             sigemptyset( &ints_off );
00676                             sigaddset( &ints_off, SIGALRM );
00677                             sigaddset( &ints_off, SIGIO );
00678                             sigaddset( &ints_off, SIGCLD );
00679 
00680                             sigprocmask( SIG_BLOCK, &ints_off, &oldset );
00681 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
00682 
00683                             if ( NULL != connectwithtofn  ) {  
00684                                    err = (*connectwithtofn)(s,
00685                                           (struct sockaddr *)&sin,
00686                                           sizeof(struct sockaddr_in),
00687                                           ld->ld_connect_timeout);
00688                             } else {
00689                                    err = (*connectfn)(s,
00690                                           (struct sockaddr *)&sin,
00691                                           sizeof(struct sockaddr_in));
00692                             }
00693 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
00694 /*
00695  * restore original signal mask
00696  */
00697                             sigprocmask( SIG_SETMASK, &oldset, 0 );
00698 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
00699 
00700                      }
00701                      if ( err >= 0 ) {
00702                             connected = 1;
00703                             rc = 0;
00704                             break;
00705                      } else {
00706                             if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
00707 #ifdef _WINDOWS
00708                                    if (err == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
00709                                           LDAP_SET_ERRNO( ld, EWOULDBLOCK );
00710 #endif /* _WINDOWS */
00711                                    err = LDAP_GET_ERRNO( ld );
00712                                    if ( NSLDAPI_ERRNO_IO_INPROGRESS( err )) {
00713                                           LDAPDebug( LDAP_DEBUG_TRACE, "connect would block...\n",
00714                                                     0, 0, 0 );
00715                                           rc = -2;
00716                                           break;
00717                                    }
00718                             }
00719 
00720 #ifdef LDAP_DEBUG
00721                             if ( ldap_debug & LDAP_DEBUG_TRACE ) {
00722                                    perror( (char *)inet_ntoa( sin.sin_addr ));
00723                             }
00724 #endif
00725                             (*closefn)( s );
00726                             if ( !use_hp ) {
00727                                    break;
00728                             }
00729                      }
00730               }
00731 
00732               ldap_memfree( host );
00733               parse_err = ldap_x_hostlist_next( &host, &port, status );
00734        }
00735 
00736        if ( ldhpbuf_allocd != NULL ) {
00737               NSLDAPI_FREE( ldhpbuf_allocd );
00738        }
00739        ldap_memfree( host );
00740        ldap_x_hostlist_statusfree( status );
00741 
00742        if ( connected ) {
00743               LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
00744                   s, inet_ntoa( sin.sin_addr ), 0 );
00745        }
00746 
00747        return( rc == 0 ? s : -1 );
00748 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00749 }
00750 
00751 void
00752 nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
00753 {
00754        if ( ld->ld_extclose_fn == NULL ) {
00755 #ifndef NSLDAPI_AVOID_OS_SOCKETS
00756               nsldapi_os_closesocket( sb->sb_sd );
00757 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00758        } else {
00759               ld->ld_extclose_fn( sb->sb_sd,
00760                          sb->sb_ext_io_fns.lbextiofn_socket_arg );
00761        }
00762 }
00763 
00764 
00765 #ifdef KERBEROS
00766 char *
00767 nsldapi_host_connected_to( Sockbuf *sb )
00768 {
00769        struct hostent              *hp;
00770        char                 *p;
00771        int                  len;
00772        struct sockaddr_in   sin;
00773 
00774        (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
00775        len = sizeof( sin );
00776        if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
00777               return( NULL );
00778        }
00779 
00780        /*
00781         * do a reverse lookup on the addr to get the official hostname.
00782         * this is necessary for kerberos to work right, since the official
00783         * hostname is used as the kerberos instance.
00784         */
00785 #error XXXmcs: need to use DNS callbacks here
00786        if (( hp = gethostbyaddr( (char *) &sin.sin_addr,
00787            sizeof( sin.sin_addr ), AF_INET )) != NULL ) {
00788               if ( hp->h_name != NULL ) {
00789                      return( nsldapi_strdup( hp->h_name ));
00790               }
00791        }
00792 
00793        return( NULL );
00794 }
00795 #endif /* KERBEROS */
00796 
00797 
00798 /*
00799  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
00800  * Also allocates initializes ld->ld_iostatus if needed..
00801  */
00802 int
00803 nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
00804 {
00805        NSLDAPIIOStatus      *iosp;
00806 
00807        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
00808 
00809        if ( ld->ld_iostatus == NULL
00810            && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
00811               LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00812               return( -1 );
00813        }
00814 
00815        iosp = ld->ld_iostatus;
00816 
00817        if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
00818 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00819               return( -1 );
00820 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00821 #ifdef NSLDAPI_HAVE_POLL
00822               if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
00823                   &iosp->ios_status.ios_osinfo, POLLOUT )) {
00824                      ++iosp->ios_write_count;
00825               }
00826 #else /* NSLDAPI_HAVE_POLL */
00827               if ( !FD_ISSET( sb->sb_sd,
00828                   &iosp->ios_status.ios_osinfo.ossi_writefds )) {
00829                      FD_SET( sb->sb_sd,
00830                          &iosp->ios_status.ios_osinfo.ossi_writefds );
00831                      ++iosp->ios_write_count;
00832               }
00833 #endif /* else NSLDAPI_HAVE_POLL */
00834 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00835 
00836        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
00837               if ( nsldapi_add_to_cb_pollfds( sb,
00838                   &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
00839                      ++iosp->ios_write_count;
00840               }
00841 
00842        } else {
00843               LDAPDebug( LDAP_DEBUG_ANY,
00844                   "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
00845                    iosp->ios_type, 0, 0 );
00846        }
00847 
00848        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00849 
00850        return( 0 );
00851 }
00852 
00853 
00854 /*
00855  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
00856  * Also allocates initializes ld->ld_iostatus if needed..
00857  */
00858 int
00859 nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
00860 {
00861        NSLDAPIIOStatus      *iosp;
00862 
00863        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
00864 
00865        if ( ld->ld_iostatus == NULL
00866            && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
00867               LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00868               return( -1 );
00869        }
00870 
00871        iosp = ld->ld_iostatus;
00872 
00873        if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
00874 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00875               return( -1 );
00876 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00877 #ifdef NSLDAPI_HAVE_POLL
00878               if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
00879                   &iosp->ios_status.ios_osinfo, POLLIN )) {
00880                      ++iosp->ios_read_count;
00881               }
00882 #else /* NSLDAPI_HAVE_POLL */
00883               if ( !FD_ISSET( sb->sb_sd,
00884                   &iosp->ios_status.ios_osinfo.ossi_readfds )) {
00885                      FD_SET( sb->sb_sd,
00886                          &iosp->ios_status.ios_osinfo.ossi_readfds );
00887                      ++iosp->ios_read_count;
00888               }
00889 #endif /* else NSLDAPI_HAVE_POLL */
00890 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00891 
00892        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
00893               if ( nsldapi_add_to_cb_pollfds( sb,
00894                   &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
00895                      ++iosp->ios_read_count;
00896               }
00897        } else {
00898               LDAPDebug( LDAP_DEBUG_ANY,
00899                   "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
00900                    iosp->ios_type, 0, 0 );
00901        }
00902 
00903        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00904 
00905        return( 0 );
00906 }
00907 
00908 
00909 /*
00910  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
00911  * Also allocates initializes ld->ld_iostatus if needed..
00912  */
00913 int
00914 nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
00915 {
00916        NSLDAPIIOStatus      *iosp;
00917 
00918        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
00919 
00920        if ( ld->ld_iostatus == NULL
00921            && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
00922               LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00923               return( -1 );
00924        }
00925 
00926        iosp = ld->ld_iostatus;
00927 
00928        if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
00929 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00930               return( -1 );
00931 #else /* NSLDAPI_AVOID_OS_SOCKETS */
00932 #ifdef NSLDAPI_HAVE_POLL
00933               if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
00934                   &iosp->ios_status.ios_osinfo, POLLOUT )) {
00935                      --iosp->ios_write_count;
00936               }
00937               if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
00938                   &iosp->ios_status.ios_osinfo, POLLIN )) {
00939                      --iosp->ios_read_count;
00940               }
00941 #else /* NSLDAPI_HAVE_POLL */
00942               if ( FD_ISSET( sb->sb_sd,
00943                   &iosp->ios_status.ios_osinfo.ossi_writefds )) {
00944                      FD_CLR( sb->sb_sd,
00945                          &iosp->ios_status.ios_osinfo.ossi_writefds );
00946                      --iosp->ios_write_count;
00947               }
00948               if ( FD_ISSET( sb->sb_sd,
00949                   &iosp->ios_status.ios_osinfo.ossi_readfds )) {
00950                      FD_CLR( sb->sb_sd,
00951                          &iosp->ios_status.ios_osinfo.ossi_readfds );
00952                      --iosp->ios_read_count;
00953               }
00954 #endif /* else NSLDAPI_HAVE_POLL */
00955 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
00956 
00957        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
00958               if ( nsldapi_clear_from_cb_pollfds( sb,
00959                   &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
00960                      --iosp->ios_write_count;
00961               }
00962               if ( nsldapi_clear_from_cb_pollfds( sb,
00963                   &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
00964                      --iosp->ios_read_count;
00965               }
00966        } else {
00967               LDAPDebug( LDAP_DEBUG_ANY,
00968                   "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
00969                    iosp->ios_type, 0, 0 );
00970        }
00971 
00972        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
00973 
00974        return( 0 );
00975 }
00976 
00977 
00978 /*
00979  * Return a non-zero value if sb is ready for write.
00980  */
00981 int
00982 nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
00983 {
00984        int           rc;
00985        NSLDAPIIOStatus      *iosp;
00986 
00987        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
00988        iosp = ld->ld_iostatus;
00989 
00990        if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
00991 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00992               return 0;
00993 #else  /* NSLDAPI_AVOID_OS_SOCKETS */
00994 #ifdef NSLDAPI_HAVE_POLL
00995               /*
00996                * if we are using poll() we do something a little tricky: if
00997                * any bits in the socket's returned events field other than
00998                * POLLIN (ready for read) are set, we return true.  This
00999                * is done so we notice when a server closes a connection
01000                * or when another error occurs.  The actual error will be
01001                * noticed later when we call write() or send().
01002                */
01003               rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
01004                   &iosp->ios_status.ios_osinfo, ~POLLIN );
01005 
01006 #else /* NSLDAPI_HAVE_POLL */
01007               rc = FD_ISSET( sb->sb_sd,
01008                      &iosp->ios_status.ios_osinfo.ossi_use_writefds );
01009 #endif /* else NSLDAPI_HAVE_POLL */
01010 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
01011 
01012        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
01013               rc = nsldapi_find_in_cb_pollfds( sb,
01014                   &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLIN );
01015 
01016        } else {
01017               LDAPDebug( LDAP_DEBUG_ANY,
01018                   "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
01019                    iosp->ios_type, 0, 0 );
01020               rc = 0;
01021        }
01022 
01023        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
01024        return( rc );
01025 }
01026 
01027 
01028 /*
01029  * Return a non-zero value if sb is ready for read.
01030  */
01031 int
01032 nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
01033 {
01034        int           rc;
01035        NSLDAPIIOStatus      *iosp;
01036 
01037        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
01038        iosp = ld->ld_iostatus;
01039 
01040        if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
01041 #ifdef NSLDAPI_AVOID_OS_SOCKETS
01042               return 0;
01043 #else /* NSLDAPI_AVOID_OS_SOCKETS */
01044 #ifdef NSLDAPI_HAVE_POLL
01045               /*
01046                * if we are using poll() we do something a little tricky: if
01047                * any bits in the socket's returned events field other than
01048                * POLLOUT (ready for write) are set, we return true.  This
01049                * is done so we notice when a server closes a connection
01050                * or when another error occurs.  The actual error will be
01051                * noticed later when we call read() or recv().
01052                */
01053               rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
01054                   &iosp->ios_status.ios_osinfo, ~POLLOUT );
01055 
01056 #else /* NSLDAPI_HAVE_POLL */
01057               rc = FD_ISSET( sb->sb_sd,
01058                   &iosp->ios_status.ios_osinfo.ossi_use_readfds );
01059 #endif /* else NSLDAPI_HAVE_POLL */
01060 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
01061 
01062        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
01063               rc = nsldapi_find_in_cb_pollfds( sb,
01064                   &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLOUT );
01065 
01066        } else {
01067               LDAPDebug( LDAP_DEBUG_ANY,
01068                   "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
01069                    iosp->ios_type, 0, 0 );
01070               rc = 0;
01071        }
01072 
01073        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
01074        return( rc );
01075 }
01076 
01077 
01078 /*
01079  * Allocate and initialize ld->ld_iostatus if not already done.
01080  * Should be called with LDAP_IOSTATUS_LOCK locked.
01081  * Returns 0 if all goes well and -1 if not (sets error in ld)
01082  */
01083 static int
01084 nsldapi_iostatus_init_nolock( LDAP *ld )
01085 {
01086        NSLDAPIIOStatus      *iosp;
01087 
01088        if ( ld->ld_iostatus != NULL ) {
01089               return( 0 );
01090        }
01091 
01092        if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
01093            sizeof( NSLDAPIIOStatus ))) == NULL ) {
01094               LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
01095               return( -1 );
01096        }
01097 
01098        if ( ld->ld_extpoll_fn == NULL ) {
01099               iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_OSNATIVE;
01100 #ifdef NSLDAPI_AVOID_OS_SOCKETS
01101               return( -1 );
01102 #else /* NSLDAPI_AVOID_OS_SOCKETS */
01103 #ifndef NSLDAPI_HAVE_POLL
01104               FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_readfds );
01105               FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_writefds );
01106 #endif /* !NSLDAPI_HAVE_POLL */
01107 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
01108 
01109        } else {
01110               iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
01111        }
01112 
01113        ld->ld_iostatus = iosp;
01114        return( 0 );
01115 }
01116 
01117 
01118 void
01119 nsldapi_iostatus_free( LDAP *ld )
01120 {
01121        if ( ld == NULL ) {
01122               return;
01123        }
01124 
01125               
01126        /* clean up classic I/O compatibility glue */
01127        if ( ld->ld_io_fns_ptr != NULL ) {
01128               if ( ld->ld_ext_session_arg != NULL ) {
01129                      NSLDAPI_FREE( ld->ld_ext_session_arg );
01130               }
01131               NSLDAPI_FREE( ld->ld_io_fns_ptr );
01132        }
01133 
01134        /* clean up I/O status tracking info. */
01135        if ( ld->ld_iostatus != NULL ) {
01136               NSLDAPIIOStatus      *iosp = ld->ld_iostatus;
01137 
01138               if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
01139 #ifdef NSLDAPI_HAVE_POLL
01140                      if ( iosp->ios_status.ios_osinfo.ossi_pollfds
01141                          != NULL ) {
01142                             NSLDAPI_FREE(
01143                                 iosp->ios_status.ios_osinfo.ossi_pollfds );
01144                      }
01145 #endif /* NSLDAPI_HAVE_POLL */
01146 
01147               } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
01148                      if ( iosp->ios_status.ios_cbinfo.cbsi_pollfds
01149                          != NULL ) {
01150                             NSLDAPI_FREE(
01151                                 iosp->ios_status.ios_cbinfo.cbsi_pollfds );
01152                      }
01153               } else {
01154                      LDAPDebug( LDAP_DEBUG_ANY,
01155                          "nsldapi_iostatus_free: unknown I/O type %d\n",
01156                           iosp->ios_type, 0, 0 );
01157               }
01158 
01159               NSLDAPI_FREE( iosp );
01160        }
01161 }
01162 
01163 
01164 
01165 #if !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS)
01166 static int
01167 nsldapi_get_select_table_size( void )
01168 {
01169        static int    tblsize = 0;  /* static */
01170 
01171        if ( tblsize == 0 ) {
01172 #if defined(_WINDOWS) || defined(XP_OS2)
01173               tblsize = FOPEN_MAX; /* ANSI spec. */
01174 #else
01175 #ifdef USE_SYSCONF
01176               tblsize = sysconf( _SC_OPEN_MAX );
01177 #else /* USE_SYSCONF */
01178               tblsize = getdtablesize();
01179 #endif /* else USE_SYSCONF */
01180 #endif /* else _WINDOWS */
01181 
01182               if ( tblsize >= FD_SETSIZE ) {
01183                      /*
01184                       * clamp value so we don't overrun the fd_set structure
01185                       */
01186                      tblsize = FD_SETSIZE - 1;
01187               }
01188        }
01189 
01190        return( tblsize );
01191 }
01192 #endif /* !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS) */
01193 
01194 
01195 static int
01196 nsldapi_tv2ms( struct timeval *tv )
01197 {
01198        if ( tv == NULL ) {
01199               return( -1 ); /* infinite timout for poll() */
01200        }
01201 
01202        return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
01203 }
01204 
01205 
01206 int
01207 nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
01208 {
01209        int                  rc;
01210        NSLDAPIIOStatus             *iosp;
01211 
01212        LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
01213 
01214        LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
01215        iosp = ld->ld_iostatus;
01216 
01217        if ( iosp == NULL ||
01218            ( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
01219               rc = 0;              /* simulate a timeout */
01220 
01221        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
01222 #ifndef NSLDAPI_AVOID_OS_SOCKETS
01223 #ifdef NSLDAPI_HAVE_POLL
01224 
01225               rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
01226                   iosp->ios_status.ios_osinfo.ossi_pollfds_size,
01227                   nsldapi_tv2ms( timeout ));
01228 
01229 #else /* NSLDAPI_HAVE_POLL */
01230 
01231               /* two (potentially large) struct copies */
01232               iosp->ios_status.ios_osinfo.ossi_use_readfds
01233                   = iosp->ios_status.ios_osinfo.ossi_readfds;
01234               iosp->ios_status.ios_osinfo.ossi_use_writefds
01235                   = iosp->ios_status.ios_osinfo.ossi_writefds;
01236 
01237 #ifdef HPUX9
01238               rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
01239                   (int *)&iosp->ios_status.ios_osinfo.ossi_use_readfds
01240                   (int *)&iosp->ios_status.ios_osinfo.ossi_use_writefds,
01241                   NULL, timeout );
01242 #else
01243               rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
01244                   &iosp->ios_status.ios_osinfo.ossi_use_readfds,
01245                   &iosp->ios_status.ios_osinfo.ossi_use_writefds,
01246                   NULL, timeout );
01247 #endif /* else HPUX9 */
01248 #endif /* else NSLDAPI_HAVE_POLL */
01249 #endif /* NSLDAPI_AVOID_OS_SOCKETS */
01250 
01251        } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
01252               /*
01253                * We always pass the session extended I/O argument to
01254                * the extended poll() callback.
01255                */
01256               rc = ld->ld_extpoll_fn( 
01257                   iosp->ios_status.ios_cbinfo.cbsi_pollfds,
01258                   iosp->ios_status.ios_cbinfo.cbsi_pollfds_size,
01259                   nsldapi_tv2ms( timeout ), ld->ld_ext_session_arg );
01260 
01261        } else {
01262               LDAPDebug( LDAP_DEBUG_ANY,
01263                   "nsldapi_iostatus_poll: unknown I/O type %d\n",
01264                    iosp->ios_type, 0, 0 );
01265               rc = 0;       /* simulate a timeout (what else to do?) */
01266        }
01267 
01268        LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
01269        return( rc );
01270 }
01271 
01272 #if defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS)
01273 /*
01274  * returns 1 if "fd" was added to pollfds.
01275  * returns 1 if some of the bits in "events" were added to pollfds.
01276  * returns 0 if no changes were made.
01277  */
01278 static int
01279 nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
01280        short events )
01281 {
01282        int    i, openslot;
01283 
01284        /* first we check to see if "fd" is already in our pollfds */
01285        openslot = -1;
01286        for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
01287               if ( pip->ossi_pollfds[ i ].fd == fd ) {
01288                      if (( pip->ossi_pollfds[ i ].events & events )
01289                          != events ) {
01290                             pip->ossi_pollfds[ i ].events |= events;
01291                             return( 1 );
01292                      } else {
01293                             return( 0 );
01294                      }
01295               }
01296               if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
01297                      openslot = i; /* remember for later */
01298               }
01299        }
01300 
01301        /*
01302         * "fd" is not currently being poll'd on -- add to array.
01303         * if we need to expand the pollfds array, we do it in increments of
01304         * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
01305         */
01306        if ( openslot == -1 ) {
01307               struct pollfd *newpollfds;
01308 
01309               if ( pip->ossi_pollfds_size == 0 ) {
01310                      newpollfds = (struct pollfd *)NSLDAPI_MALLOC(
01311                          NSLDAPI_POLL_ARRAY_GROWTH
01312                          * sizeof( struct pollfd ));
01313               } else {
01314                      newpollfds = (struct pollfd *)NSLDAPI_REALLOC(
01315                          pip->ossi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
01316                          + pip->ossi_pollfds_size)
01317                          * sizeof( struct pollfd ));
01318               }
01319               if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
01320                      return( 0 );
01321               }
01322               pip->ossi_pollfds = newpollfds;
01323               openslot = pip->ossi_pollfds_size;
01324               pip->ossi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
01325               for ( i = openslot + 1; i < pip->ossi_pollfds_size; ++i ) {
01326                      pip->ossi_pollfds[ i ].fd = -1;
01327                      pip->ossi_pollfds[ i ].events =
01328                          pip->ossi_pollfds[ i ].revents = 0;
01329               }
01330        }
01331        pip->ossi_pollfds[ openslot ].fd = fd;
01332        pip->ossi_pollfds[ openslot ].events = events;
01333        pip->ossi_pollfds[ openslot ].revents = 0;
01334        return( 1 );
01335 }
01336 
01337 
01338 /*
01339  * returns 1 if any "events" from "fd" were removed from pollfds
01340  * returns 0 of "fd" wasn't in pollfds or if events did not overlap.
01341  */
01342 static int
01343 nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
01344     short events )
01345 {
01346        int    i;
01347 
01348        for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
01349               if ( pip->ossi_pollfds[i].fd == fd ) {
01350                      if (( pip->ossi_pollfds[ i ].events & events ) != 0 ) {
01351                             pip->ossi_pollfds[ i ].events &= ~events;
01352                             if ( pip->ossi_pollfds[ i ].events == 0 ) {
01353                                    pip->ossi_pollfds[i].fd = -1;
01354                             }
01355                             return( 1 );  /* events overlap */
01356                      } else {
01357                             return( 0 );  /* events do not overlap */
01358                      }
01359               }
01360        }
01361 
01362        return( 0 );  /* "fd" was not found */
01363 }
01364 
01365 
01366 /*
01367  * returns 1 if any "revents" from "fd" were set in pollfds revents field.
01368  * returns 0 if not.
01369  */
01370 static int
01371 nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
01372        short revents )
01373 {
01374        int    i;
01375 
01376        for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
01377               if ( pip->ossi_pollfds[i].fd == fd ) {
01378                      if (( pip->ossi_pollfds[ i ].revents & revents ) != 0 ) {
01379                             return( 1 );  /* revents overlap */
01380                      } else {
01381                             return( 0 );  /* revents do not overlap */
01382                      }
01383               }
01384        }
01385 
01386        return( 0 );  /* "fd" was not found */
01387 }
01388 #endif /* !defined(NSLDAPI_HAVE_POLL) && !defined(NSLDAPI_AVOID_OS_SOCKETS) */
01389 
01390 /*
01391  * returns 1 if "sb" was added to pollfds.
01392  * returns 1 if some of the bits in "events" were added to pollfds.
01393  * returns 0 if no changes were made.
01394  */
01395 static int
01396 nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
01397     short events )
01398 {
01399        int    i, openslot;
01400 
01401        /* first we check to see if "sb" is already in our pollfds */
01402        openslot = -1;
01403        for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
01404               if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
01405                      if (( pip->cbsi_pollfds[ i ].lpoll_events & events )
01406                          != events ) {
01407                             pip->cbsi_pollfds[ i ].lpoll_events |= events;
01408                             return( 1 );
01409                      } else {
01410                             return( 0 );
01411                      }
01412               }
01413               if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
01414                      openslot = i; /* remember for later */
01415               }
01416        }
01417 
01418        /*
01419         * "sb" is not currently being poll'd on -- add to array.
01420         * if we need to expand the pollfds array, we do it in increments of
01421         * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
01422         */
01423        if ( openslot == -1 ) {
01424               LDAP_X_PollFD *newpollfds;
01425 
01426               if ( pip->cbsi_pollfds_size == 0 ) {
01427                      newpollfds = (LDAP_X_PollFD *)NSLDAPI_MALLOC(
01428                          NSLDAPI_POLL_ARRAY_GROWTH
01429                          * sizeof( LDAP_X_PollFD ));
01430               } else {
01431                      newpollfds = (LDAP_X_PollFD *)NSLDAPI_REALLOC(
01432                          pip->cbsi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
01433                          + pip->cbsi_pollfds_size)
01434                          * sizeof( LDAP_X_PollFD ));
01435               }
01436               if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
01437                      return( 0 );
01438               }
01439               pip->cbsi_pollfds = newpollfds;
01440               openslot = pip->cbsi_pollfds_size;
01441               pip->cbsi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
01442               for ( i = openslot + 1; i < pip->cbsi_pollfds_size; ++i ) {
01443                      pip->cbsi_pollfds[ i ].lpoll_fd = -1;
01444                      pip->cbsi_pollfds[ i ].lpoll_socketarg = NULL;
01445                      pip->cbsi_pollfds[ i ].lpoll_events =
01446                          pip->cbsi_pollfds[ i ].lpoll_revents = 0;
01447               }
01448        }
01449        pip->cbsi_pollfds[ openslot ].lpoll_fd = sb->sb_sd;
01450        pip->cbsi_pollfds[ openslot ].lpoll_socketarg =
01451            sb->sb_ext_io_fns.lbextiofn_socket_arg;
01452        pip->cbsi_pollfds[ openslot ].lpoll_events = events;
01453        pip->cbsi_pollfds[ openslot ].lpoll_revents = 0;
01454        return( 1 );
01455 }
01456 
01457 
01458 /*
01459  * returns 1 if any "events" from "sb" were removed from pollfds
01460  * returns 0 of "sb" wasn't in pollfds or if events did not overlap.
01461  */
01462 static int
01463 nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
01464     struct nsldapi_cb_statusinfo *pip, short events )
01465 {
01466        int    i;
01467 
01468        for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
01469               if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
01470                      if (( pip->cbsi_pollfds[ i ].lpoll_events
01471                          & events ) != 0 ) {
01472                             pip->cbsi_pollfds[ i ].lpoll_events &= ~events;
01473                             if ( pip->cbsi_pollfds[ i ].lpoll_events
01474                                 == 0 ) {
01475                                    pip->cbsi_pollfds[i].lpoll_fd = -1;
01476                             }
01477                             return( 1 );  /* events overlap */
01478                      } else {
01479                             return( 0 );  /* events do not overlap */
01480                      }
01481               }
01482        }
01483 
01484        return( 0 );  /* "sb" was not found */
01485 }
01486 
01487 
01488 /*
01489  * returns 1 if any "revents" from "sb" were set in pollfds revents field.
01490  * returns 0 if not.
01491  */
01492 static int
01493 nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
01494     short revents )
01495 {
01496        int    i;
01497 
01498        for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
01499               if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
01500                      if (( pip->cbsi_pollfds[ i ].lpoll_revents
01501                          & revents ) != 0 ) {
01502                             return( 1 );  /* revents overlap */
01503                      } else {
01504                             return( 0 );  /* revents do not overlap */
01505                      }
01506               }
01507        }
01508 
01509        return( 0 );  /* "sb" was not found */
01510 }
01511 
01512 
01513 /*
01514  * Install read and write functions into lber layer / sb
01515  */
01516 int
01517 nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
01518 {
01519        struct lber_x_ext_io_fns    lberiofns;
01520 
01521        if ( NULL != sb ) {
01522               lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
01523               lberiofns.lbextiofn_read = ld->ld_extread_fn;
01524               lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
01525               lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
01526               lberiofns.lbextiofn_socket_arg = ld->ld_ext_session_arg;
01527 
01528               if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
01529                   &lberiofns ) != 0 ) {
01530                      return( LDAP_LOCAL_ERROR );
01531               }
01532        }
01533 
01534        return( LDAP_SUCCESS );
01535 }
01536 
01537 
01538 /*
01539  ******************************************************************************
01540  * One struct and several functions to bridge the gap between new extended
01541  * I/O functions that are installed using ldap_set_option( ...,
01542  * LDAP_OPT_EXTIO_FN_PTRS, ... ) and the original "classic" I/O functions
01543  * (installed using LDAP_OPT_IO_FN_PTRS) follow.
01544  *
01545  * Our basic strategy is to use the new extended arg to hold a pointer to a
01546  *    structure that contains a pointer to the LDAP * (which contains pointers
01547  *    to the old functions so we can call them) as well as a pointer to an
01548  *    LBER_SOCKET to hold the socket used by the classic functions (the new
01549  *    functions use a simple int for the socket).
01550  */
01551 typedef struct nsldapi_compat_socket_info {
01552     LBER_SOCKET             csi_socket;
01553     LDAP             *csi_ld;
01554 } NSLDAPICompatSocketInfo;
01555     
01556 static int LDAP_CALLBACK
01557 nsldapi_ext_compat_read( int s, void *buf, int len,
01558        struct lextiof_socket_private *arg )
01559 {
01560        NSLDAPICompatSocketInfo     *csip = (NSLDAPICompatSocketInfo *)arg;
01561        struct ldap_io_fns   *iofns = csip->csi_ld->ld_io_fns_ptr;
01562 
01563        return( iofns->liof_read( csip->csi_socket, buf, len ));
01564 }
01565 
01566 
01567 static int LDAP_CALLBACK
01568 nsldapi_ext_compat_write( int s, const void *buf, int len,
01569        struct lextiof_socket_private *arg  )
01570 {
01571        NSLDAPICompatSocketInfo     *csip = (NSLDAPICompatSocketInfo *)arg;
01572        struct ldap_io_fns   *iofns = csip->csi_ld->ld_io_fns_ptr;
01573 
01574        return( iofns->liof_write( csip->csi_socket, buf, len ));
01575 }
01576 
01577 
01578 static int LDAP_CALLBACK
01579 nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
01580        struct lextiof_session_private *arg )
01581 {
01582        NSLDAPICompatSocketInfo     *csip = (NSLDAPICompatSocketInfo *)arg;
01583        struct ldap_io_fns   *iofns = csip->csi_ld->ld_io_fns_ptr;
01584        fd_set               readfds, writefds;
01585        int                  i, rc, maxfd = 0;
01586        struct timeval              tv, *tvp;
01587 
01588        /*
01589         * Prepare fd_sets for select()
01590         */
01591        FD_ZERO( &readfds );
01592        FD_ZERO( &writefds );
01593        for ( i = 0; i < nfds; ++i ) {
01594               if ( fds[ i ].lpoll_fd < 0 ) {
01595                      continue;
01596               }
01597 
01598               if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
01599                      LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
01600                      return( -1 );
01601               }
01602               
01603               if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
01604                      FD_SET( fds[i].lpoll_fd, &readfds );
01605               }
01606 
01607               if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
01608                      FD_SET( fds[i].lpoll_fd, &writefds );
01609               }
01610 
01611               fds[i].lpoll_revents = 0;   /* clear revents */
01612 
01613               if ( fds[i].lpoll_fd >= maxfd ) {
01614                      maxfd = fds[i].lpoll_fd;
01615               }
01616        }
01617 
01618        /*
01619         * select() using callback.
01620         */
01621        ++maxfd;
01622        if ( timeout == -1 ) {
01623               tvp = NULL;
01624        } else {
01625               tv.tv_sec = timeout / 1000;
01626               tv.tv_usec = 1000 * ( timeout - tv.tv_sec * 1000 );
01627               tvp = &tv;
01628        }
01629        rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
01630        if ( rc <= 0 ) {     /* timeout or fatal error */
01631               return( rc );
01632        }
01633 
01634        /*
01635         * Use info. in fd_sets to populate poll() revents.
01636         */
01637        for ( i = 0; i < nfds; ++i ) {
01638               if ( fds[ i ].lpoll_fd < 0 ) {
01639                      continue;
01640               }
01641 
01642               if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )
01643                   && FD_ISSET( fds[i].lpoll_fd, &readfds )) {
01644                      fds[i].lpoll_revents |= LDAP_X_POLLIN;
01645               }
01646 
01647               if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )
01648                   && FD_ISSET( fds[i].lpoll_fd, &writefds )) {
01649                      fds[i].lpoll_revents |= LDAP_X_POLLOUT;
01650               }
01651 
01652               /* XXXmcs: any other cases to deal with?  LDAP_X_POLLERR? */
01653        }
01654 
01655        return( rc );
01656 }
01657 
01658 
01659 static LBER_SOCKET
01660 nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
01661        int protocol )
01662 {
01663        int           s;
01664 
01665        s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
01666 
01667        if ( s >= 0 ) {
01668               char                        *errmsg = NULL;
01669 
01670 #ifdef NSLDAPI_HAVE_POLL
01671               if ( ld->ld_io_fns_ptr->liof_select != NULL
01672                          && s >= FD_SETSIZE ) {
01673                      errmsg = "can't use socket >= FD_SETSIZE";
01674               }
01675 #elif !defined(_WINDOWS) /* not on Windows and do not have poll() */
01676               if ( s >= FD_SETSIZE ) {
01677                      errmsg = "can't use socket >= FD_SETSIZE";
01678               }
01679 #endif
01680 
01681               if ( NULL == errmsg && secure &&
01682                          ld->ld_io_fns_ptr->liof_ssl_enable( s ) < 0 ) {
01683                      errmsg = "failed to enable secure mode";
01684                   }
01685 
01686               if ( NULL != errmsg ) {
01687                      if ( NULL == ld->ld_io_fns_ptr->liof_close ) {
01688                             nsldapi_os_closesocket( s );
01689                      } else {
01690                             ld->ld_io_fns_ptr->liof_close( s );
01691                      }
01692                      LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
01693                                 nsldapi_strdup( errmsg ));
01694                      return( -1 );
01695               }
01696        }
01697 
01698        return( s );
01699 }
01700 
01701 
01702 /*
01703  * Note: timeout is ignored because we have no way to pass it via
01704  * the old I/O callback interface.
01705  */
01706 static int LDAP_CALLBACK
01707 nsldapi_ext_compat_connect( const char *hostlist, int defport, int timeout,
01708        unsigned long options, struct lextiof_session_private *sessionarg,
01709        struct lextiof_socket_private **socketargp )
01710 {
01711        NSLDAPICompatSocketInfo            *defcsip;
01712        struct ldap_io_fns          *iofns;
01713        int                         s, secure;
01714        NSLDAPI_SOCKET_FN           *socketfn;
01715        NSLDAPI_IOCTL_FN            *ioctlfn;
01716        NSLDAPI_CONNECT_WITH_TO_FN  *connectwithtofn;
01717        NSLDAPI_CONNECT_FN          *connectfn;
01718        NSLDAPI_CLOSE_FN            *closefn;
01719 
01720        defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
01721        iofns = defcsip->csi_ld->ld_io_fns_ptr;
01722 
01723        if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
01724               if ( NULL == iofns->liof_ssl_enable ) {
01725                      LDAP_SET_ERRNO( defcsip->csi_ld, EINVAL );
01726                      return( -1 );
01727               }
01728               secure = 1;
01729        } else {
01730               secure = 0;
01731        }
01732 
01733        socketfn = ( iofns->liof_socket == NULL ) ?
01734                   nsldapi_os_socket : nsldapi_compat_socket;
01735        ioctlfn = ( iofns->liof_ioctl == NULL ) ?
01736                   nsldapi_os_ioctl : (NSLDAPI_IOCTL_FN *)(iofns->liof_ioctl);
01737        if ( NULL == iofns->liof_connect ) {
01738               connectwithtofn = nsldapi_os_connect_with_to;
01739               connectfn = NULL;
01740        } else {
01741               connectwithtofn = NULL;
01742               connectfn = iofns->liof_connect;
01743        }
01744        closefn = ( iofns->liof_close == NULL ) ?
01745                   nsldapi_os_closesocket : iofns->liof_close;  
01746 
01747        s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
01748                      secure, socketfn, ioctlfn, connectwithtofn,
01749                      connectfn, closefn );
01750 
01751        if ( s >= 0 ) {
01752               NSLDAPICompatSocketInfo            *csip;
01753 
01754               if (( csip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
01755                   sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
01756                      (*closefn)( s );
01757                      LDAP_SET_LDERRNO( defcsip->csi_ld, LDAP_NO_MEMORY,
01758                             NULL, NULL );
01759                      return( -1 );
01760               }
01761 
01762               csip->csi_socket = s;
01763               csip->csi_ld = defcsip->csi_ld;
01764               *socketargp = (void *)csip;
01765 
01766               /*
01767                * We always return 1, which is a valid but not unique socket
01768                * (file descriptor) number.  The extended I/O functions only
01769                * require that the combination of the void *arg and the int
01770                * socket be unique.  Since we allocate the
01771                * NSLDAPICompatSocketInfo that we assign to arg, we meet
01772                * that requirement.
01773                */
01774               s = 1;
01775        }
01776 
01777        return( s );
01778 }
01779 
01780 
01781 static int LDAP_CALLBACK
01782 nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
01783 {
01784        NSLDAPICompatSocketInfo     *csip = (NSLDAPICompatSocketInfo *)arg;
01785        struct ldap_io_fns   *iofns = csip->csi_ld->ld_io_fns_ptr;
01786        int                  rc;
01787 
01788        rc = iofns->liof_close( csip->csi_socket );
01789 
01790        NSLDAPI_FREE( csip );
01791 
01792        return( rc );
01793 }
01794 
01795 /*
01796  * Install the I/O functions.
01797  * Return an LDAP error code (LDAP_SUCCESS if all goes well).
01798  */
01799 int
01800 nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
01801 {
01802        NSLDAPICompatSocketInfo            *defcsip;
01803 
01804        if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
01805            sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
01806               return( LDAP_NO_MEMORY );
01807        }
01808 
01809        defcsip->csi_socket = -1;
01810        defcsip->csi_ld = ld;
01811 
01812        if ( ld->ld_io_fns_ptr != NULL ) {
01813               (void)memset( (char *)ld->ld_io_fns_ptr, 0,
01814                   sizeof( struct ldap_io_fns ));
01815        } else if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_CALLOC(
01816            1, sizeof( struct ldap_io_fns ))) == NULL ) {
01817               NSLDAPI_FREE( defcsip );
01818               return( LDAP_NO_MEMORY );
01819        }
01820 
01821        /* struct copy */
01822        *(ld->ld_io_fns_ptr) = *iofns;
01823 
01824        ld->ld_extio_size = LBER_X_EXTIO_FNS_SIZE;
01825        ld->ld_ext_session_arg = defcsip;
01826        ld->ld_extread_fn = nsldapi_ext_compat_read;
01827        ld->ld_extwrite_fn = nsldapi_ext_compat_write;
01828        ld->ld_extpoll_fn = nsldapi_ext_compat_poll;
01829        ld->ld_extconnect_fn = nsldapi_ext_compat_connect;
01830        ld->ld_extclose_fn = nsldapi_ext_compat_close;
01831 
01832        return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
01833 }
01834 /*
01835  * end of compat I/O functions
01836  ******************************************************************************
01837  */