Back to index

openldap  2.4.31
os-ip.c
Go to the documentation of this file.
00001 /* os-ip.c -- platform-specific TCP & UDP related code */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 1999 Lars Uffmann.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00018  * All rights reserved.
00019  */
00020 /* Significant additional contributors include:
00021  *    Lars Uffman
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 
00028 #include <ac/stdlib.h>
00029 
00030 #include <ac/errno.h>
00031 #include <ac/socket.h>
00032 #include <ac/string.h>
00033 #include <ac/time.h>
00034 #include <ac/unistd.h>
00035 
00036 #ifdef HAVE_IO_H
00037 #include <io.h>
00038 #endif /* HAVE_IO_H */
00039 #ifdef HAVE_FCNTL_H
00040 #include <fcntl.h>
00041 #endif
00042 
00043 #include "ldap-int.h"
00044 
00045 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
00046 #  ifdef LDAP_PF_INET6
00047 int ldap_int_inet4or6 = AF_UNSPEC;
00048 #  else
00049 int ldap_int_inet4or6 = AF_INET;
00050 #  endif
00051 #endif
00052 
00053 #ifdef LDAP_DEBUG
00054 
00055 #define osip_debug(ld,fmt,arg1,arg2,arg3) \
00056 do { \
00057        ldap_log_printf(NULL, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
00058 } while(0)
00059 
00060 #else
00061 
00062 #define osip_debug(ld,fmt,arg1,arg2,arg3) ((void)0)
00063 
00064 #endif /* LDAP_DEBUG */
00065 
00066 static void
00067 ldap_pvt_set_errno(int err)
00068 {
00069        sock_errset(err);
00070 }
00071 
00072 int
00073 ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src )
00074 {
00075        struct timeval *new;
00076 
00077        assert( dest != NULL );
00078 
00079        if (src == NULL) {
00080               *dest = NULL;
00081               return 0;
00082        }
00083 
00084        new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval));
00085 
00086        if( new == NULL ) {
00087               *dest = NULL;
00088               return 1;
00089        }
00090 
00091        AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval));
00092 
00093        *dest = new;
00094        return 0;
00095 }
00096 
00097 static int
00098 ldap_pvt_ndelay_on(LDAP *ld, int fd)
00099 {
00100        osip_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
00101        return ber_pvt_socket_set_nonblock( fd, 1 );
00102 }
00103    
00104 static int
00105 ldap_pvt_ndelay_off(LDAP *ld, int fd)
00106 {
00107        osip_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
00108        return ber_pvt_socket_set_nonblock( fd, 0 );
00109 }
00110 
00111 static ber_socket_t
00112 ldap_int_socket(LDAP *ld, int family, int type )
00113 {
00114        ber_socket_t s = socket(family, type, 0);
00115        osip_debug(ld, "ldap_new_socket: %d\n",s,0,0);
00116 #ifdef FD_CLOEXEC
00117        fcntl(s, F_SETFD, FD_CLOEXEC);
00118 #endif
00119        return ( s );
00120 }
00121 
00122 static int
00123 ldap_pvt_close_socket(LDAP *ld, int s)
00124 {
00125        osip_debug(ld, "ldap_close_socket: %d\n",s,0,0);
00126        return tcp_close(s);
00127 }
00128 
00129 static int
00130 ldap_int_prepare_socket(LDAP *ld, int s, int proto )
00131 {
00132        osip_debug( ld, "ldap_prepare_socket: %d\n", s, 0, 0 );
00133 
00134 #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY )
00135        if ( proto == LDAP_PROTO_TCP ) {
00136               int dummy = 1;
00137 #ifdef SO_KEEPALIVE
00138               if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE,
00139                      (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
00140               {
00141                      osip_debug( ld, "ldap_prepare_socket: "
00142                             "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
00143                             s, 0, 0 );
00144               }
00145               if ( ld->ld_options.ldo_keepalive_idle > 0 )
00146               {
00147 #ifdef TCP_KEEPIDLE
00148                      if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE,
00149                                    (void*) &ld->ld_options.ldo_keepalive_idle,
00150                                    sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR )
00151                      {
00152                             osip_debug( ld, "ldap_prepare_socket: "
00153                                    "setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n",
00154                                    s, 0, 0 );
00155                      }
00156 #else
00157                      osip_debug( ld, "ldap_prepare_socket: "
00158                                    "sockopt TCP_KEEPIDLE not supported on this system.\n", 
00159                                    0, 0, 0 );
00160 #endif /* TCP_KEEPIDLE */
00161               }
00162               if ( ld->ld_options.ldo_keepalive_probes > 0 )
00163               {
00164 #ifdef TCP_KEEPCNT
00165                      if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT,
00166                                    (void*) &ld->ld_options.ldo_keepalive_probes,
00167                                    sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR )
00168                      {
00169                             osip_debug( ld, "ldap_prepare_socket: "
00170                                    "setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n",
00171                                    s, 0, 0 );
00172                      }
00173 #else
00174                      osip_debug( ld, "ldap_prepare_socket: "
00175                                    "sockopt TCP_KEEPCNT not supported on this system.\n", 
00176                                    0, 0, 0 );
00177 #endif /* TCP_KEEPCNT */
00178               }
00179               if ( ld->ld_options.ldo_keepalive_interval > 0 )
00180               {
00181 #ifdef TCP_KEEPINTVL
00182                      if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL,
00183                                    (void*) &ld->ld_options.ldo_keepalive_interval,
00184                                    sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR )
00185                      {
00186                             osip_debug( ld, "ldap_prepare_socket: "
00187                                    "setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n",
00188                                    s, 0, 0 );
00189                      } 
00190 #else
00191                      osip_debug( ld, "ldap_prepare_socket: "
00192                                    "sockopt TCP_KEEPINTVL not supported on this system.\n", 
00193                                    0, 0, 0 );
00194 #endif /* TCP_KEEPINTVL */
00195               }
00196 #endif /* SO_KEEPALIVE */
00197 #ifdef TCP_NODELAY
00198               if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
00199                      (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
00200               {
00201                      osip_debug( ld, "ldap_prepare_socket: "
00202                             "setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
00203                             s, 0, 0 );
00204               }
00205 #endif /* TCP_NODELAY */
00206        }
00207 #endif /* SO_KEEPALIVE || TCP_NODELAY */
00208 
00209        return 0;
00210 }
00211 
00212 #ifndef HAVE_WINSOCK
00213 
00214 #undef TRACE
00215 #define TRACE do { \
00216        osip_debug(ld, \
00217               "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \
00218               s, \
00219               errno, \
00220               sock_errstr(errno) ); \
00221 } while( 0 )
00222 
00223 /*
00224  * check the socket for errors after select returned.
00225  */
00226 static int
00227 ldap_pvt_is_socket_ready(LDAP *ld, int s)
00228 {
00229        osip_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
00230 
00231 #if defined( notyet ) /* && defined( SO_ERROR ) */
00232 {
00233        int so_errno;
00234        ber_socklen_t dummy = sizeof(so_errno);
00235        if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
00236               == AC_SOCKET_ERROR )
00237        {
00238               return -1;
00239        }
00240        if ( so_errno ) {
00241               ldap_pvt_set_errno(so_errno);
00242               TRACE;
00243               return -1;
00244        }
00245        return 0;
00246 }
00247 #else
00248 {
00249        /* error slippery */
00250 #ifdef LDAP_PF_INET6
00251        struct sockaddr_storage sin;
00252 #else
00253        struct sockaddr_in sin;
00254 #endif
00255        char ch;
00256        ber_socklen_t dummy = sizeof(sin);
00257        if ( getpeername( s, (struct sockaddr *) &sin, &dummy )
00258               == AC_SOCKET_ERROR )
00259        {
00260               /* XXX: needs to be replace with ber_stream_read() */
00261               (void)read(s, &ch, 1);
00262               TRACE;
00263               return -1;
00264        }
00265        return 0;
00266 }
00267 #endif
00268        return -1;
00269 }
00270 #undef TRACE
00271 
00272 #endif /* HAVE_WINSOCK */
00273 
00274 /* NOTE: this is identical to analogous code in os-local.c */
00275 int
00276 ldap_int_poll(
00277        LDAP *ld,
00278        ber_socket_t s,
00279        struct timeval *tvp )
00280 {
00281        int           rc;
00282               
00283 
00284        osip_debug(ld, "ldap_int_poll: fd: %d tm: %ld\n",
00285               s, tvp ? tvp->tv_sec : -1L, 0);
00286 
00287 #ifdef HAVE_POLL
00288        {
00289               struct pollfd fd;
00290               int timeout = INFTIM;
00291 
00292               fd.fd = s;
00293               fd.events = POLL_WRITE;
00294 
00295               if ( tvp != NULL ) {
00296                      timeout = TV2MILLISEC( tvp );
00297               }
00298               do {
00299                      fd.revents = 0;
00300                      rc = poll( &fd, 1, timeout );
00301               
00302               } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
00303                      LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
00304 
00305               if ( rc == AC_SOCKET_ERROR ) {
00306                      return rc;
00307               }
00308 
00309               if ( timeout == 0 && rc == 0 ) {
00310                      return -2;
00311               }
00312 
00313               if ( fd.revents & POLL_WRITE ) {
00314                      if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
00315                             return -1;
00316                      }
00317 
00318                      if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) {
00319                             return -1;
00320                      }
00321                      return 0;
00322               }
00323        }
00324 #else
00325        {
00326               fd_set        wfds, *z = NULL;
00327 #ifdef HAVE_WINSOCK
00328               fd_set        efds;
00329 #endif
00330               struct timeval       tv = { 0 };
00331 
00332 #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK )
00333               if ( s >= FD_SETSIZE ) {
00334                      rc = AC_SOCKET_ERROR;
00335                      tcp_close( s );
00336                      ldap_pvt_set_errno( EMFILE );
00337                      return rc;
00338               }
00339 #endif
00340 
00341               if ( tvp != NULL ) {
00342                      tv = *tvp;
00343               }
00344 
00345               do {
00346                      FD_ZERO(&wfds);
00347                      FD_SET(s, &wfds );
00348 
00349 #ifdef HAVE_WINSOCK
00350                      FD_ZERO(&efds);
00351                      FD_SET(s, &efds );
00352 #endif
00353 
00354                      rc = select( ldap_int_tblsize, z, &wfds,
00355 #ifdef HAVE_WINSOCK
00356                             &efds,
00357 #else
00358                             z,
00359 #endif
00360                             tvp ? &tv : NULL );
00361               } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
00362                      LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
00363 
00364               if ( rc == AC_SOCKET_ERROR ) {
00365                      return rc;
00366               }
00367 
00368               if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) {
00369                      return -2;
00370               }
00371 
00372 #ifdef HAVE_WINSOCK
00373               /* This means the connection failed */
00374               if ( FD_ISSET(s, &efds) ) {
00375                      int so_errno;
00376                      ber_socklen_t dummy = sizeof(so_errno);
00377                      if ( getsockopt( s, SOL_SOCKET, SO_ERROR,
00378                             (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno )
00379                      {
00380                             /* impossible */
00381                             so_errno = WSAGetLastError();
00382                      }
00383                      ldap_pvt_set_errno( so_errno );
00384                      osip_debug(ld, "ldap_int_poll: error on socket %d: "
00385                             "errno: %d (%s)\n", s, errno, sock_errstr( errno ));
00386                      return -1;
00387               }
00388 #endif
00389               if ( FD_ISSET(s, &wfds) ) {
00390 #ifndef HAVE_WINSOCK
00391                      if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
00392                             return -1;
00393                      }
00394 #endif
00395                      if ( ldap_pvt_ndelay_off(ld, s) == -1 ) {
00396                             return -1;
00397                      }
00398                      return 0;
00399               }
00400        }
00401 #endif
00402 
00403        osip_debug(ld, "ldap_int_poll: timed out\n",0,0,0);
00404        ldap_pvt_set_errno( ETIMEDOUT );
00405        return -1;
00406 }
00407 
00408 static int
00409 ldap_pvt_connect(LDAP *ld, ber_socket_t s,
00410        struct sockaddr *sin, ber_socklen_t addrlen,
00411        int async)
00412 {
00413        int rc, err;
00414        struct timeval       tv, *opt_tv = NULL;
00415 
00416 #ifdef LDAP_CONNECTIONLESS
00417        /* We could do a connect() but that would interfere with
00418         * attempts to poll a broadcast address
00419         */
00420        if (LDAP_IS_UDP(ld)) {
00421               if (ld->ld_options.ldo_peer)
00422                      ldap_memfree(ld->ld_options.ldo_peer);
00423               ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr));
00424               AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr));
00425               return ( 0 );
00426        }
00427 #endif
00428        if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
00429               tv = ld->ld_options.ldo_tm_net;
00430               opt_tv = &tv;
00431        }
00432 
00433        osip_debug(ld, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n",
00434                      s, opt_tv ? tv.tv_sec : -1L, async);
00435 
00436        if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 )
00437               return ( -1 );
00438 
00439        if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) {
00440               if ( opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 )
00441                      return ( -1 );
00442               return ( 0 );
00443        }
00444 
00445        err = sock_errno();
00446        if ( err != EINPROGRESS && err != EWOULDBLOCK ) {
00447               return ( -1 );
00448        }
00449        
00450        if ( async ) {
00451               /* caller will call ldap_int_poll() as appropriate? */
00452               return ( -2 );
00453        }
00454 
00455        rc = ldap_int_poll( ld, s, opt_tv );
00456 
00457        osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0);
00458 
00459        return rc;
00460 }
00461 
00462 #ifndef HAVE_INET_ATON
00463 int
00464 ldap_pvt_inet_aton( const char *host, struct in_addr *in)
00465 {
00466        unsigned long u = inet_addr( host );
00467 
00468 #ifdef INADDR_NONE
00469        if ( u == INADDR_NONE ) return 0;
00470 #endif
00471        if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0;
00472 
00473        in->s_addr = u;
00474        return 1;
00475 }
00476 #endif
00477 
00478 int
00479 ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr)
00480 {
00481        struct ldapoptions *lo;
00482        ldaplist *ll;
00483        ldap_conncb *cb;
00484        int rc;
00485 
00486        ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, s );
00487 
00488        /* Invoke all handle-specific callbacks first */
00489        lo = &ld->ld_options;
00490        for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
00491               cb = ll->ll_data;
00492               rc = cb->lc_add( ld, sb, srv, addr, cb );
00493               /* on any failure, call the teardown functions for anything
00494                * that previously succeeded
00495                */
00496               if ( rc ) {
00497                      ldaplist *l2;
00498                      for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
00499                             cb = l2->ll_data;
00500                             cb->lc_del( ld, sb, cb );
00501                      }
00502                      /* a failure might have implicitly closed the fd */
00503                      ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
00504                      return rc;
00505               }
00506        }
00507        lo = LDAP_INT_GLOBAL_OPT();
00508        for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
00509               cb = ll->ll_data;
00510               rc = cb->lc_add( ld, sb, srv, addr, cb );
00511               if ( rc ) {
00512                      ldaplist *l2;
00513                      for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
00514                             cb = l2->ll_data;
00515                             cb->lc_del( ld, sb, cb );
00516                      }
00517                      lo = &ld->ld_options;
00518                      for (l2 = lo->ldo_conn_cbs; l2; l2 = l2->ll_next) {
00519                             cb = l2->ll_data;
00520                             cb->lc_del( ld, sb, cb );
00521                      }
00522                      ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
00523                      return rc;
00524               }
00525        }
00526        return 0;
00527 }
00528 
00529 int
00530 ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
00531        int proto, LDAPURLDesc *srv,
00532        int async )
00533 {
00534        int    rc;
00535        int    socktype, port;
00536        ber_socket_t         s = AC_SOCKET_INVALID;
00537        char *host;
00538 
00539 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
00540        char serv[7];
00541        int err;
00542        struct addrinfo hints, *res, *sai;
00543 #else
00544        int i;
00545        int use_hp = 0;
00546        struct hostent *hp = NULL;
00547        struct hostent he_buf;
00548        struct in_addr in;
00549        char *ha_buf=NULL;
00550 #endif
00551 
00552        if ( srv->lud_host == NULL || *srv->lud_host == 0 ) {
00553               host = "localhost";
00554        } else {
00555               host = srv->lud_host;
00556        }
00557 
00558        port = srv->lud_port;
00559 
00560        if( !port ) {
00561               if( strcmp(srv->lud_scheme, "ldaps") == 0 ) {
00562                      port = LDAPS_PORT;
00563               } else {
00564                      port = LDAP_PORT;
00565               }
00566        }
00567 
00568        switch(proto) {
00569        case LDAP_PROTO_TCP: socktype = SOCK_STREAM;
00570               osip_debug( ld,
00571                      "ldap_connect_to_host: TCP %s:%d\n",
00572                      host, port, 0);
00573               break;
00574        case LDAP_PROTO_UDP: socktype = SOCK_DGRAM;
00575               osip_debug( ld,
00576                      "ldap_connect_to_host: UDP %s:%d\n",
00577                      host, port, 0);
00578               break;
00579        default:
00580               osip_debug( ld, "ldap_connect_to_host: unknown proto: %d\n",
00581                      proto, 0, 0 );
00582               return -1;
00583        }
00584 
00585 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
00586        memset( &hints, '\0', sizeof(hints) );
00587 #ifdef USE_AI_ADDRCONFIG /* FIXME: configure test needed */
00588        /* Use AI_ADDRCONFIG only on systems where its known to be needed. */
00589        hints.ai_flags = AI_ADDRCONFIG;
00590 #endif
00591        hints.ai_family = ldap_int_inet4or6;
00592        hints.ai_socktype = socktype;
00593        snprintf(serv, sizeof serv, "%d", port );
00594 
00595        /* most getaddrinfo(3) use non-threadsafe resolver libraries */
00596        LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex);
00597 
00598        err = getaddrinfo( host, serv, &hints, &res );
00599 
00600        LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex);
00601 
00602        if ( err != 0 ) {
00603               osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n",
00604                      AC_GAI_STRERROR(err), 0, 0);
00605               return -1;
00606        }
00607        rc = -1;
00608 
00609        for( sai=res; sai != NULL; sai=sai->ai_next) {
00610               if( sai->ai_addr == NULL ) {
00611                      osip_debug(ld, "ldap_connect_to_host: getaddrinfo "
00612                             "ai_addr is NULL?\n", 0, 0, 0);
00613                      continue;
00614               }
00615 
00616               /* we assume AF_x and PF_x are equal for all x */
00617               s = ldap_int_socket( ld, sai->ai_family, socktype );
00618               if ( s == AC_SOCKET_INVALID ) {
00619                      continue;
00620               }
00621 
00622               if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) {
00623                      ldap_pvt_close_socket(ld, s);
00624                      break;
00625               }
00626 
00627               switch (sai->ai_family) {
00628 #ifdef LDAP_PF_INET6
00629                      case AF_INET6: {
00630                             char addr[INET6_ADDRSTRLEN];
00631                             inet_ntop( AF_INET6,
00632                                    &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
00633                                    addr, sizeof addr);
00634                             osip_debug(ld, "ldap_connect_to_host: Trying %s %s\n", 
00635                                    addr, serv, 0);
00636                      } break;
00637 #endif
00638                      case AF_INET: {
00639                             char addr[INET_ADDRSTRLEN];
00640                             inet_ntop( AF_INET,
00641                                    &((struct sockaddr_in *)sai->ai_addr)->sin_addr,
00642                                    addr, sizeof addr);
00643                             osip_debug(ld, "ldap_connect_to_host: Trying %s:%s\n", 
00644                                    addr, serv, 0);
00645                      } break;
00646               }
00647 
00648               rc = ldap_pvt_connect( ld, s,
00649                      sai->ai_addr, sai->ai_addrlen, async );
00650               if ( rc == 0 || rc == -2 ) {
00651                      err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr );
00652                      if ( err )
00653                             rc = err;
00654                      else
00655                             break;
00656               }
00657               ldap_pvt_close_socket(ld, s);
00658        }
00659        freeaddrinfo(res);
00660 
00661 #else
00662        if (! inet_aton( host, &in ) ) {
00663               int local_h_errno;
00664               rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
00665                      &hp, &local_h_errno );
00666 
00667               if ( (rc < 0) || (hp == NULL) ) {
00668 #ifdef HAVE_WINSOCK
00669                      ldap_pvt_set_errno( WSAGetLastError() );
00670 #else
00671                      /* not exactly right, but... */
00672                      ldap_pvt_set_errno( EHOSTUNREACH );
00673 #endif
00674                      if (ha_buf) LDAP_FREE(ha_buf);
00675                      return -1;
00676               }
00677 
00678               use_hp = 1;
00679        }
00680 
00681        rc = s = -1;
00682        for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
00683               struct sockaddr_in   sin;
00684 
00685               s = ldap_int_socket( ld, PF_INET, socktype );
00686               if ( s == AC_SOCKET_INVALID ) {
00687                      /* use_hp ? continue : break; */
00688                      break;
00689               }
00690           
00691               if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
00692                      ldap_pvt_close_socket(ld, s);
00693                      break;
00694               }
00695 
00696               (void)memset((char *)&sin, '\0', sizeof sin);
00697               sin.sin_family = AF_INET;
00698               sin.sin_port = htons((unsigned short) port);
00699 
00700               if( use_hp ) {
00701                      AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i],
00702                             sizeof(sin.sin_addr) );
00703               } else {
00704                      AC_MEMCPY( &sin.sin_addr, &in.s_addr,
00705                             sizeof(sin.sin_addr) );
00706               }
00707 
00708 #ifdef HAVE_INET_NTOA_B
00709               {
00710                      /* for VxWorks */
00711                      char address[INET_ADDR_LEN];
00712                      inet_ntoa_b(sin.sin_address, address);
00713                      osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 
00714                             address, port, 0);
00715               }
00716 #else
00717               osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 
00718                      inet_ntoa(sin.sin_addr), port, 0);
00719 #endif
00720 
00721               rc = ldap_pvt_connect(ld, s,
00722                      (struct sockaddr *)&sin, sizeof(sin),
00723                      async);
00724    
00725               if ( (rc == 0) || (rc == -2) ) {
00726                      int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin );
00727                      if ( err )
00728                             rc = err;
00729                      else
00730                             break;
00731               }
00732 
00733               ldap_pvt_close_socket(ld, s);
00734 
00735               if (!use_hp) break;
00736        }
00737        if (ha_buf) LDAP_FREE(ha_buf);
00738 #endif
00739 
00740        return rc;
00741 }
00742 
00743 #if defined( HAVE_CYRUS_SASL )
00744 char *
00745 ldap_host_connected_to( Sockbuf *sb, const char *host )
00746 {
00747        ber_socklen_t len;
00748 #ifdef LDAP_PF_INET6
00749        struct sockaddr_storage sabuf;
00750 #else
00751        struct sockaddr sabuf;
00752 #endif
00753        struct sockaddr      *sa = (struct sockaddr *) &sabuf;
00754        ber_socket_t  sd;
00755 
00756        (void)memset( (char *)sa, '\0', sizeof sabuf );
00757        len = sizeof sabuf;
00758 
00759        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
00760        if ( getpeername( sd, sa, &len ) == -1 ) {
00761               return( NULL );
00762        }
00763 
00764        /*
00765         * do a reverse lookup on the addr to get the official hostname.
00766         * this is necessary for kerberos to work right, since the official
00767         * hostname is used as the kerberos instance.
00768         */
00769 
00770        switch (sa->sa_family) {
00771 #ifdef LDAP_PF_LOCAL
00772        case AF_LOCAL:
00773               return LDAP_STRDUP( ldap_int_hostname );
00774 #endif
00775 #ifdef LDAP_PF_INET6
00776        case AF_INET6:
00777               {
00778                      struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT;
00779                      if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr,
00780                             &localhost, sizeof(localhost)) == 0 )
00781                      {
00782                             return LDAP_STRDUP( ldap_int_hostname );
00783                      }
00784               }
00785               break;
00786 #endif
00787        case AF_INET:
00788               {
00789                      struct in_addr localhost;
00790                      localhost.s_addr = htonl( INADDR_ANY );
00791 
00792                      if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
00793                             &localhost, sizeof(localhost) ) == 0 )
00794                      {
00795                             return LDAP_STRDUP( ldap_int_hostname );
00796                      }
00797 
00798 #ifdef INADDR_LOOPBACK
00799                      localhost.s_addr = htonl( INADDR_LOOPBACK );
00800 
00801                      if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
00802                             &localhost, sizeof(localhost) ) == 0 )
00803                      {
00804                             return LDAP_STRDUP( ldap_int_hostname );
00805                      }
00806 #endif
00807               }
00808               break;
00809 
00810        default:
00811               return( NULL );
00812               break;
00813        }
00814 
00815        {
00816               char *herr;
00817 #ifdef NI_MAXHOST
00818               char hbuf[NI_MAXHOST];
00819 #elif defined( MAXHOSTNAMELEN )
00820               char hbuf[MAXHOSTNAMELEN];
00821 #else
00822               char hbuf[256];
00823 #endif
00824               hbuf[0] = 0;
00825 
00826               if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0
00827                      && hbuf[0] ) 
00828               {
00829                      return LDAP_STRDUP( hbuf );   
00830               }
00831        }
00832 
00833        return host ? LDAP_STRDUP( host ) : NULL;
00834 }
00835 #endif
00836 
00837 
00838 struct selectinfo {
00839 #ifdef HAVE_POLL
00840        /* for UNIX poll(2) */
00841        int si_maxfd;
00842        struct pollfd si_fds[FD_SETSIZE];
00843 #else
00844        /* for UNIX select(2) */
00845        fd_set si_readfds;
00846        fd_set si_writefds;
00847        fd_set si_use_readfds;
00848        fd_set si_use_writefds;
00849 #endif
00850 };
00851 
00852 void
00853 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
00854 {
00855        struct selectinfo    *sip;
00856        ber_socket_t         sd;
00857 
00858        sip = (struct selectinfo *)ld->ld_selectinfo;
00859        
00860        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
00861 
00862 #ifdef HAVE_POLL
00863        /* for UNIX poll(2) */
00864        {
00865               int empty=-1;
00866               int i;
00867               for(i=0; i < sip->si_maxfd; i++) {
00868                      if( sip->si_fds[i].fd == sd ) {
00869                             sip->si_fds[i].events |= POLL_WRITE;
00870                             return;
00871                      }
00872                      if( empty==-1 && sip->si_fds[i].fd == -1 ) {
00873                             empty=i;
00874                      }
00875               }
00876 
00877               if( empty == -1 ) {
00878                      if( sip->si_maxfd >= FD_SETSIZE ) {
00879                             /* FIXME */
00880                             return;
00881                      }
00882                      empty = sip->si_maxfd++;
00883               }
00884 
00885               sip->si_fds[empty].fd = sd;
00886               sip->si_fds[empty].events = POLL_WRITE;
00887        }
00888 #else
00889        /* for UNIX select(2) */
00890        if ( !FD_ISSET( sd, &sip->si_writefds )) {
00891               FD_SET( sd, &sip->si_writefds );
00892        }
00893 #endif
00894 }
00895 
00896 
00897 void
00898 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
00899 {
00900        struct selectinfo    *sip;
00901        ber_socket_t         sd;
00902 
00903        sip = (struct selectinfo *)ld->ld_selectinfo;
00904 
00905        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
00906 
00907 #ifdef HAVE_POLL
00908        /* for UNIX poll(2) */
00909        {
00910               int empty=-1;
00911               int i;
00912               for(i=0; i < sip->si_maxfd; i++) {
00913                      if( sip->si_fds[i].fd == sd ) {
00914                             sip->si_fds[i].events |= POLL_READ;
00915                             return;
00916                      }
00917                      if( empty==-1 && sip->si_fds[i].fd == -1 ) {
00918                             empty=i;
00919                      }
00920               }
00921 
00922               if( empty == -1 ) {
00923                      if( sip->si_maxfd >= FD_SETSIZE ) {
00924                             /* FIXME */
00925                             return;
00926                      }
00927                      empty = sip->si_maxfd++;
00928               }
00929 
00930               sip->si_fds[empty].fd = sd;
00931               sip->si_fds[empty].events = POLL_READ;
00932        }
00933 #else
00934        /* for UNIX select(2) */
00935        if ( !FD_ISSET( sd, &sip->si_readfds )) {
00936               FD_SET( sd, &sip->si_readfds );
00937        }
00938 #endif
00939 }
00940 
00941 
00942 void
00943 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
00944 {
00945        struct selectinfo    *sip;
00946        ber_socket_t         sd;
00947 
00948        sip = (struct selectinfo *)ld->ld_selectinfo;
00949 
00950        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
00951 
00952 #ifdef HAVE_POLL
00953        /* for UNIX poll(2) */
00954        {
00955               int i;
00956               for(i=0; i < sip->si_maxfd; i++) {
00957                      if( sip->si_fds[i].fd == sd ) {
00958                             sip->si_fds[i].fd = -1;
00959                      }
00960               }
00961        }
00962 #else
00963        /* for UNIX select(2) */
00964        FD_CLR( sd, &sip->si_writefds );
00965        FD_CLR( sd, &sip->si_readfds );
00966 #endif
00967 }
00968 
00969 void
00970 ldap_clear_select_write( LDAP *ld, Sockbuf *sb )
00971 {
00972        struct selectinfo    *sip;
00973        ber_socket_t         sd;
00974 
00975        sip = (struct selectinfo *)ld->ld_selectinfo;
00976 
00977        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
00978 
00979 #ifdef HAVE_POLL
00980        /* for UNIX poll(2) */
00981        {
00982               int i;
00983               for(i=0; i < sip->si_maxfd; i++) {
00984                      if( sip->si_fds[i].fd == sd ) {
00985                             sip->si_fds[i].events &= ~POLL_WRITE;
00986                      }
00987               }
00988        }
00989 #else
00990        /* for UNIX select(2) */
00991        FD_CLR( sd, &sip->si_writefds );
00992 #endif
00993 }
00994 
00995 
00996 int
00997 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
00998 {
00999        struct selectinfo    *sip;
01000        ber_socket_t         sd;
01001 
01002        sip = (struct selectinfo *)ld->ld_selectinfo;
01003 
01004        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
01005 
01006 #ifdef HAVE_POLL
01007        /* for UNIX poll(2) */
01008        {
01009               int i;
01010               for(i=0; i < sip->si_maxfd; i++) {
01011                      if( sip->si_fds[i].fd == sd ) {
01012                             return sip->si_fds[i].revents & POLL_WRITE;
01013                      }
01014               }
01015 
01016               return 0;
01017        }
01018 #else
01019        /* for UNIX select(2) */
01020        return( FD_ISSET( sd, &sip->si_use_writefds ));
01021 #endif
01022 }
01023 
01024 
01025 int
01026 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
01027 {
01028        struct selectinfo    *sip;
01029        ber_socket_t         sd;
01030 
01031        sip = (struct selectinfo *)ld->ld_selectinfo;
01032 
01033        if (ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ))
01034               return 1;
01035 
01036        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
01037 
01038 #ifdef HAVE_POLL
01039        /* for UNIX poll(2) */
01040        {
01041               int i;
01042               for(i=0; i < sip->si_maxfd; i++) {
01043                      if( sip->si_fds[i].fd == sd ) {
01044                             return sip->si_fds[i].revents & POLL_READ;
01045                      }
01046               }
01047 
01048               return 0;
01049        }
01050 #else
01051        /* for UNIX select(2) */
01052        return( FD_ISSET( sd, &sip->si_use_readfds ));
01053 #endif
01054 }
01055 
01056 
01057 void *
01058 ldap_new_select_info( void )
01059 {
01060        struct selectinfo    *sip;
01061 
01062        sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo ));
01063 
01064        if ( sip == NULL ) return NULL;
01065 
01066 #ifdef HAVE_POLL
01067        /* for UNIX poll(2) */
01068        /* sip->si_maxfd=0 */
01069 #else
01070        /* for UNIX select(2) */
01071        FD_ZERO( &sip->si_readfds );
01072        FD_ZERO( &sip->si_writefds );
01073 #endif
01074 
01075        return( (void *)sip );
01076 }
01077 
01078 
01079 void
01080 ldap_free_select_info( void *sip )
01081 {
01082        LDAP_FREE( sip );
01083 }
01084 
01085 
01086 #ifndef HAVE_POLL
01087 int ldap_int_tblsize = 0;
01088 
01089 void
01090 ldap_int_ip_init( void )
01091 {
01092 #if defined( HAVE_SYSCONF )
01093        long tblsize = sysconf( _SC_OPEN_MAX );
01094        if( tblsize > INT_MAX ) tblsize = INT_MAX;
01095 
01096 #elif defined( HAVE_GETDTABLESIZE )
01097        int tblsize = getdtablesize();
01098 #else
01099        int tblsize = FD_SETSIZE;
01100 #endif /* !USE_SYSCONF */
01101 
01102 #ifdef FD_SETSIZE
01103        if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE;
01104 #endif /* FD_SETSIZE */
01105 
01106        ldap_int_tblsize = tblsize;
01107 }
01108 #endif
01109 
01110 
01111 int
01112 ldap_int_select( LDAP *ld, struct timeval *timeout )
01113 {
01114        int rc;
01115        struct selectinfo    *sip;
01116 
01117        Debug( LDAP_DEBUG_TRACE, "ldap_int_select\n", 0, 0, 0 );
01118 
01119 #ifndef HAVE_POLL
01120        if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
01121 #endif
01122 
01123        sip = (struct selectinfo *)ld->ld_selectinfo;
01124        assert( sip != NULL );
01125 
01126 #ifdef HAVE_POLL
01127        {
01128               int to = timeout ? TV2MILLISEC( timeout ) : INFTIM;
01129               rc = poll( sip->si_fds, sip->si_maxfd, to );
01130        }
01131 #else
01132        sip->si_use_readfds = sip->si_readfds;
01133        sip->si_use_writefds = sip->si_writefds;
01134        
01135        rc = select( ldap_int_tblsize,
01136               &sip->si_use_readfds, &sip->si_use_writefds,
01137               NULL, timeout );
01138 #endif
01139 
01140        return rc;
01141 }