Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: os-ip.c,v 1.12 2025/09/05 21:16:21 christos Exp $	*/
      2 
      3 /* os-ip.c -- platform-specific TCP & UDP related code */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * Portions Copyright 1999 Lars Uffmann.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted only as authorized by the OpenLDAP
     13  * Public License.
     14  *
     15  * A copy of this license is available in the file LICENSE in the
     16  * top-level directory of the distribution or, alternatively, at
     17  * <http://www.OpenLDAP.org/license.html>.
     18  */
     19 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     20  * All rights reserved.
     21  */
     22 /* Significant additional contributors include:
     23  *    Lars Uffman
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __RCSID("$NetBSD: os-ip.c,v 1.12 2025/09/05 21:16:21 christos Exp $");
     28 
     29 #include "portable.h"
     30 
     31 #include <stdio.h>
     32 
     33 #include <ac/stdlib.h>
     34 
     35 #include <ac/errno.h>
     36 #include <ac/socket.h>
     37 #include <ac/string.h>
     38 #include <ac/time.h>
     39 #include <ac/unistd.h>
     40 
     41 #ifdef HAVE_IO_H
     42 #include <io.h>
     43 #endif /* HAVE_IO_H */
     44 #ifdef HAVE_FCNTL_H
     45 #include <fcntl.h>
     46 #endif
     47 
     48 #include "ldap-int.h"
     49 
     50 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
     51 #  ifdef LDAP_PF_INET6
     52 int ldap_int_inet4or6 = AF_UNSPEC;
     53 #  else
     54 int ldap_int_inet4or6 = AF_INET;
     55 #  endif
     56 #endif
     57 
     58 static void
     59 ldap_pvt_set_errno(int err)
     60 {
     61 	sock_errset(err);
     62 }
     63 
     64 int
     65 ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src )
     66 {
     67 	struct timeval *new;
     68 
     69 	assert( dest != NULL );
     70 
     71 	if (src == NULL) {
     72 		*dest = NULL;
     73 		return 0;
     74 	}
     75 
     76 	new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval));
     77 
     78 	if( new == NULL ) {
     79 		*dest = NULL;
     80 		return 1;
     81 	}
     82 
     83 	AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval));
     84 
     85 	*dest = new;
     86 	return 0;
     87 }
     88 
     89 static int
     90 ldap_pvt_ndelay_on(LDAP *ld, int fd)
     91 {
     92 	Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_on: %d\n",fd );
     93 	return ber_pvt_socket_set_nonblock( fd, 1 );
     94 }
     95 
     96 static int
     97 ldap_pvt_ndelay_off(LDAP *ld, int fd)
     98 {
     99 	Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_off: %d\n",fd );
    100 	return ber_pvt_socket_set_nonblock( fd, 0 );
    101 }
    102 
    103 static ber_socket_t
    104 ldap_int_socket(LDAP *ld, int family, int type )
    105 {
    106 	ber_socket_t s = socket(family, type, 0);
    107 	Debug1(LDAP_DEBUG_TRACE, "ldap_new_socket: %d\n",s );
    108 #ifdef FD_CLOEXEC
    109 	fcntl(s, F_SETFD, FD_CLOEXEC);
    110 #endif
    111 	return ( s );
    112 }
    113 
    114 static int
    115 ldap_pvt_close_socket(LDAP *ld, int s)
    116 {
    117 	Debug1(LDAP_DEBUG_TRACE, "ldap_close_socket: %d\n",s );
    118 	return tcp_close(s);
    119 }
    120 
    121 static int
    122 ldap_int_prepare_socket(LDAP *ld, int s, int proto )
    123 {
    124 	Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: %d\n", s );
    125 
    126 #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY ) || defined( TCP_USER_TIMEOUT )
    127 	if ( proto == LDAP_PROTO_TCP ) {
    128 		int dummy = 1;
    129 #ifdef SO_KEEPALIVE
    130 		if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE,
    131 			(char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
    132 		{
    133 			Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    134 				"setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
    135 				s );
    136 		}
    137 		if ( ld->ld_options.ldo_keepalive_idle > 0 )
    138 		{
    139 #ifdef TCP_KEEPIDLE
    140 			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE,
    141 					(void*) &ld->ld_options.ldo_keepalive_idle,
    142 					sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR )
    143 			{
    144 				Debug1(LDAP_DEBUG_TRACE,
    145 					"ldap_prepare_socket: "
    146 					"setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n",
    147 					s );
    148 			}
    149 #else
    150 			Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    151 					"sockopt TCP_KEEPIDLE not supported on this system.\n" );
    152 #endif /* TCP_KEEPIDLE */
    153 		}
    154 		if ( ld->ld_options.ldo_keepalive_probes > 0 )
    155 		{
    156 #ifdef TCP_KEEPCNT
    157 			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT,
    158 					(void*) &ld->ld_options.ldo_keepalive_probes,
    159 					sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR )
    160 			{
    161 				Debug1(LDAP_DEBUG_TRACE,
    162 					"ldap_prepare_socket: "
    163 					"setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n",
    164 					s );
    165 			}
    166 #else
    167 			Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    168 					"sockopt TCP_KEEPCNT not supported on this system.\n" );
    169 #endif /* TCP_KEEPCNT */
    170 		}
    171 		if ( ld->ld_options.ldo_keepalive_interval > 0 )
    172 		{
    173 #ifdef TCP_KEEPINTVL
    174 			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL,
    175 					(void*) &ld->ld_options.ldo_keepalive_interval,
    176 					sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR )
    177 			{
    178 				Debug1(LDAP_DEBUG_TRACE,
    179 					"ldap_prepare_socket: "
    180 					"setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n",
    181 					s );
    182 			}
    183 #else
    184 			Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    185 					"sockopt TCP_KEEPINTVL not supported on this system.\n" );
    186 #endif /* TCP_KEEPINTVL */
    187 		}
    188 #endif /* SO_KEEPALIVE */
    189 #ifdef TCP_NODELAY
    190 		if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
    191 			(char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
    192 		{
    193 			Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    194 				"setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
    195 				s );
    196 		}
    197 #endif /* TCP_NODELAY */
    198 		if ( ld->ld_options.ldo_tcp_user_timeout > 0 )
    199 		{
    200 #ifdef TCP_USER_TIMEOUT
    201 			if ( setsockopt( s, IPPROTO_TCP, TCP_USER_TIMEOUT,
    202 					(void*) &ld->ld_options.ldo_tcp_user_timeout,
    203 					sizeof(ld->ld_options.ldo_tcp_user_timeout) ) == AC_SOCKET_ERROR )
    204 			{
    205 				Debug1(LDAP_DEBUG_TRACE,
    206 					"ldap_prepare_socket: "
    207 					"setsockopt(%d, TCP_USER_TIMEOUT) failed (ignored).\n",
    208 					s );
    209 			}
    210 #else
    211 			Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: "
    212 			       "sockopt TCP_USER_TIMEOUT not supported on this system.\n" );
    213 #endif /* TCP_USER_TIMEOUT */
    214 		}
    215 	}
    216 #endif /* SO_KEEPALIVE || TCP_NODELAY || TCP_USER_TIMEOUT */
    217 
    218 	return 0;
    219 }
    220 
    221 #ifndef HAVE_WINSOCK
    222 
    223 #undef TRACE
    224 #define TRACE do { \
    225 	char ebuf[128]; \
    226 	int saved_errno = errno; \
    227 	Debug3(LDAP_DEBUG_TRACE, "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \
    228 		s, \
    229 		saved_errno, \
    230 		sock_errstr(saved_errno, ebuf, sizeof(ebuf)) ); \
    231 } while( 0 )
    232 
    233 /*
    234  * check the socket for errors after select returned.
    235  */
    236 static int
    237 ldap_pvt_is_socket_ready(LDAP *ld, int s)
    238 {
    239 	Debug1(LDAP_DEBUG_TRACE, "ldap_is_sock_ready: %d\n",s );
    240 
    241 #if defined( notyet ) /* && defined( SO_ERROR ) */
    242 {
    243 	int so_errno;
    244 	ber_socklen_t dummy = sizeof(so_errno);
    245 	if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
    246 		== AC_SOCKET_ERROR )
    247 	{
    248 		return -1;
    249 	}
    250 	if ( so_errno ) {
    251 		ldap_pvt_set_errno(so_errno);
    252 		TRACE;
    253 		return -1;
    254 	}
    255 	return 0;
    256 }
    257 #else
    258 {
    259 	/* error slippery */
    260 #ifdef LDAP_PF_INET6
    261 	struct sockaddr_storage sin;
    262 #else
    263 	struct sockaddr_in sin;
    264 #endif
    265 	char ch;
    266 	ber_socklen_t dummy = sizeof(sin);
    267 	if ( getpeername( s, (struct sockaddr *) &sin, &dummy )
    268 		== AC_SOCKET_ERROR )
    269 	{
    270 		/* XXX: needs to be replace with ber_stream_read() */
    271 		(void)!read(s, &ch, 1);
    272 		TRACE;
    273 		return -1;
    274 	}
    275 	return 0;
    276 }
    277 #endif
    278 	return -1;
    279 }
    280 #undef TRACE
    281 
    282 #endif /* HAVE_WINSOCK */
    283 
    284 /* NOTE: this is identical to analogous code in os-local.c */
    285 int
    286 ldap_int_poll(
    287 	LDAP *ld,
    288 	ber_socket_t s,
    289 	struct timeval *tvp,
    290 	int wr )
    291 {
    292 	int		rc;
    293 
    294 
    295 	Debug2(LDAP_DEBUG_TRACE, "ldap_int_poll: fd: %d tm: %jd\n",
    296 		s, (intmax_t)(tvp ? tvp->tv_sec : -1));
    297 
    298 #ifdef HAVE_POLL
    299 	{
    300 		struct pollfd fd;
    301 		int timeout = INFTIM;
    302 		short event = wr ? POLL_WRITE : POLL_READ;
    303 
    304 		fd.fd = s;
    305 		fd.events = event;
    306 
    307 		if ( tvp != NULL ) {
    308 			timeout = TV2MILLISEC( tvp );
    309 		}
    310 		do {
    311 			fd.revents = 0;
    312 			rc = poll( &fd, 1, timeout );
    313 
    314 		} while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
    315 			LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
    316 
    317 		if ( rc == AC_SOCKET_ERROR ) {
    318 			return rc;
    319 		}
    320 
    321 		if ( timeout == 0 && rc == 0 ) {
    322 			return -2;
    323 		}
    324 
    325 		if ( fd.revents & event ) {
    326 			if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
    327 				return -1;
    328 			}
    329 
    330 			if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) {
    331 				return -1;
    332 			}
    333 			return 0;
    334 		}
    335 	}
    336 #else
    337 	{
    338 		fd_set		wfds, *z = NULL;
    339 #ifdef HAVE_WINSOCK
    340 		fd_set		efds;
    341 #endif
    342 		struct timeval	tv = { 0 };
    343 
    344 #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK )
    345 		if ( s >= FD_SETSIZE ) {
    346 			rc = AC_SOCKET_ERROR;
    347 			tcp_close( s );
    348 			ldap_pvt_set_errno( EMFILE );
    349 			return rc;
    350 		}
    351 #endif
    352 
    353 		if ( tvp != NULL ) {
    354 			tv = *tvp;
    355 		}
    356 
    357 		do {
    358 			FD_ZERO(&wfds);
    359 			FD_SET(s, &wfds );
    360 
    361 #ifdef HAVE_WINSOCK
    362 			FD_ZERO(&efds);
    363 			FD_SET(s, &efds );
    364 #endif
    365 
    366 			rc = select( ldap_int_tblsize, z, &wfds,
    367 #ifdef HAVE_WINSOCK
    368 				&efds,
    369 #else
    370 				z,
    371 #endif
    372 				tvp ? &tv : NULL );
    373 		} while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
    374 			LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
    375 
    376 		if ( rc == AC_SOCKET_ERROR ) {
    377 			return rc;
    378 		}
    379 
    380 		if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) {
    381 			return -2;
    382 		}
    383 
    384 #ifdef HAVE_WINSOCK
    385 		/* This means the connection failed */
    386 		if ( FD_ISSET(s, &efds) ) {
    387 			int so_errno;
    388 			ber_socklen_t dummy = sizeof(so_errno);
    389 			if ( getsockopt( s, SOL_SOCKET, SO_ERROR,
    390 				(char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno )
    391 			{
    392 				/* impossible */
    393 				so_errno = WSAGetLastError();
    394 			}
    395 			ldap_pvt_set_errno( so_errno );
    396 			Debug3(LDAP_DEBUG_TRACE,
    397 			       "ldap_int_poll: error on socket %d: "
    398 			       "errno: %d (%s)\n", s, so_errno, sock_errstr( so_errno, dummy, dummy ));
    399 			return -1;
    400 		}
    401 #endif
    402 		if ( FD_ISSET(s, &wfds) ) {
    403 #ifndef HAVE_WINSOCK
    404 			if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
    405 				return -1;
    406 			}
    407 #endif
    408 			if ( ldap_pvt_ndelay_off(ld, s) == -1 ) {
    409 				return -1;
    410 			}
    411 			return 0;
    412 		}
    413 	}
    414 #endif
    415 
    416 	Debug0(LDAP_DEBUG_TRACE, "ldap_int_poll: timed out\n" );
    417 	ldap_pvt_set_errno( ETIMEDOUT );
    418 	return -1;
    419 }
    420 
    421 static int
    422 ldap_pvt_connect(LDAP *ld, ber_socket_t s,
    423 	struct sockaddr *sin, ber_socklen_t addrlen,
    424 	int async)
    425 {
    426 	int rc, err;
    427 	struct timeval	tv, *opt_tv = NULL;
    428 
    429 #ifdef LDAP_CONNECTIONLESS
    430 	/* We could do a connect() but that would interfere with
    431 	 * attempts to poll a broadcast address
    432 	 */
    433 	if (LDAP_IS_UDP(ld)) {
    434 		if (ld->ld_options.ldo_peer)
    435 			ldap_memfree(ld->ld_options.ldo_peer);
    436 		ld->ld_options.ldo_peer=ldap_memcalloc(1, sizeof(struct sockaddr_storage));
    437 		AC_MEMCPY(ld->ld_options.ldo_peer,sin,addrlen);
    438 		return ( 0 );
    439 	}
    440 #endif
    441 	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
    442 		tv = ld->ld_options.ldo_tm_net;
    443 		opt_tv = &tv;
    444 	}
    445 
    446 	Debug3(LDAP_DEBUG_TRACE,
    447 			"ldap_pvt_connect: fd: %d tm: %jd async: %d\n",
    448 			s, (intmax_t)(opt_tv ? tv.tv_sec : -1), async);
    449 
    450 	if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 )
    451 		return ( -1 );
    452 
    453 	do{
    454 		Debug0(LDAP_DEBUG_TRACE, "attempting to connect: \n" );
    455 		if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) {
    456 			Debug0(LDAP_DEBUG_TRACE, "connect success\n" );
    457 
    458 			if ( !async && opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 )
    459 				return ( -1 );
    460 			return ( 0 );
    461 		}
    462 		err = sock_errno();
    463 		Debug1(LDAP_DEBUG_TRACE, "connect errno: %d\n", err );
    464 
    465 	} while(err == EINTR &&
    466 		LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ));
    467 
    468 	if ( err != EINPROGRESS && err != EWOULDBLOCK ) {
    469 		return ( -1 );
    470 	}
    471 
    472 	if ( async ) {
    473 		/* caller will call ldap_int_poll() as appropriate? */
    474 		return ( -2 );
    475 	}
    476 
    477 	rc = ldap_int_poll( ld, s, opt_tv, 1 );
    478 
    479 	Debug1(LDAP_DEBUG_TRACE, "ldap_pvt_connect: %d\n", rc );
    480 
    481 	return rc;
    482 }
    483 
    484 #ifndef HAVE_INET_ATON
    485 int
    486 ldap_pvt_inet_aton( const char *host, struct in_addr *in)
    487 {
    488 	unsigned long u = inet_addr( host );
    489 
    490 #ifdef INADDR_NONE
    491 	if ( u == INADDR_NONE ) return 0;
    492 #endif
    493 	if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0;
    494 
    495 	in->s_addr = u;
    496 	return 1;
    497 }
    498 #endif
    499 
    500 int
    501 ldap_validate_and_fill_sourceip  (char** source_ip_lst, ldapsourceip* temp_source_ip )
    502 {
    503 	int i = 0;
    504 	int rc = LDAP_PARAM_ERROR;
    505 
    506 	for ( i = 0; source_ip_lst[i] != NULL; i++ ) {
    507 		Debug1( LDAP_DEBUG_TRACE,
    508 				"ldap_validate_and_fill_sourceip(%s)\n",
    509 				source_ip_lst[i] );
    510 
    511 		if ( !temp_source_ip->has_ipv4 ) {
    512 			if ( inet_aton( source_ip_lst[i], &temp_source_ip->ip4_addr ) ) {
    513 				temp_source_ip->has_ipv4 = 1;
    514 				rc = LDAP_OPT_SUCCESS;
    515 				continue;
    516 			}
    517 		}
    518 #ifdef LDAP_PF_INET6
    519 		if ( !temp_source_ip->has_ipv6 ) {
    520 			if ( inet_pton( AF_INET6, source_ip_lst[i],
    521 				& temp_source_ip->ip6_addr ) ) {
    522 				temp_source_ip->has_ipv6 = 1;
    523 				rc = LDAP_OPT_SUCCESS;
    524 				continue;
    525 			}
    526 		}
    527 #endif
    528 		memset( temp_source_ip, 0, sizeof( * (temp_source_ip ) ) );
    529 		Debug1( LDAP_DEBUG_TRACE,
    530 				"ldap_validate_and_fill_sourceip: validation failed for (%s)\n",
    531 				source_ip_lst[i] );
    532 		break;
    533 	}
    534 	return rc;
    535 }
    536 
    537 int
    538 ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr)
    539 {
    540 	struct ldapoptions *lo;
    541 	ldaplist *ll;
    542 	ldap_conncb *cb;
    543 	int rc;
    544 
    545 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, s );
    546 
    547 	/* Invoke all handle-specific callbacks first */
    548 	lo = &ld->ld_options;
    549 	for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
    550 		cb = ll->ll_data;
    551 		rc = cb->lc_add( ld, sb, srv, addr, cb );
    552 		/* on any failure, call the teardown functions for anything
    553 		 * that previously succeeded
    554 		 */
    555 		if ( rc ) {
    556 			ldaplist *l2;
    557 			for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
    558 				cb = l2->ll_data;
    559 				cb->lc_del( ld, sb, cb );
    560 			}
    561 			/* a failure might have implicitly closed the fd */
    562 			ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
    563 			return rc;
    564 		}
    565 	}
    566 	lo = LDAP_INT_GLOBAL_OPT();
    567 	for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
    568 		cb = ll->ll_data;
    569 		rc = cb->lc_add( ld, sb, srv, addr, cb );
    570 		if ( rc ) {
    571 			ldaplist *l2;
    572 			for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
    573 				cb = l2->ll_data;
    574 				cb->lc_del( ld, sb, cb );
    575 			}
    576 			lo = &ld->ld_options;
    577 			for (l2 = lo->ldo_conn_cbs; l2; l2 = l2->ll_next) {
    578 				cb = l2->ll_data;
    579 				cb->lc_del( ld, sb, cb );
    580 			}
    581 			ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
    582 			return rc;
    583 		}
    584 	}
    585 	return 0;
    586 }
    587 
    588 int
    589 ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
    590 	int proto, LDAPURLDesc *srv,
    591 	int async )
    592 {
    593 	int	rc;
    594 	int	socktype, port;
    595 	ber_socket_t		s = AC_SOCKET_INVALID;
    596 	char *host;
    597 
    598 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
    599 	char serv[7];
    600 	int err;
    601 	struct addrinfo hints, *res, *sai;
    602 #else
    603 	int i;
    604 	int use_hp = 0;
    605 	struct hostent *hp = NULL;
    606 	struct hostent he_buf;
    607 	struct in_addr in;
    608 	char *ha_buf=NULL;
    609 #endif
    610 
    611 	if ( srv->lud_host == NULL || *srv->lud_host == 0 ) {
    612 		host = "localhost";
    613 	} else {
    614 		host = srv->lud_host;
    615 	}
    616 
    617 	port = srv->lud_port;
    618 
    619 	if( !port ) {
    620 		if( strcmp(srv->lud_scheme, "ldaps") == 0 ) {
    621 			port = LDAPS_PORT;
    622 		} else {
    623 			port = LDAP_PORT;
    624 		}
    625 	}
    626 
    627 	switch(proto) {
    628 	case LDAP_PROTO_TCP: socktype = SOCK_STREAM;
    629 		Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: TCP %s:%d\n",
    630 			host, port );
    631 		break;
    632 	case LDAP_PROTO_UDP: socktype = SOCK_DGRAM;
    633 		Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: UDP %s:%d\n",
    634 			host, port );
    635 		break;
    636 	default:
    637 		Debug1(LDAP_DEBUG_TRACE,
    638 			"ldap_connect_to_host: unknown proto: %d\n",
    639 			proto );
    640 		return -1;
    641 	}
    642 
    643 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
    644 	memset( &hints, '\0', sizeof(hints) );
    645 #ifdef USE_AI_ADDRCONFIG /* FIXME: configure test needed */
    646 	/* Use AI_ADDRCONFIG only on systems where its known to be needed. */
    647 	hints.ai_flags = AI_ADDRCONFIG;
    648 #endif
    649 	hints.ai_family = ldap_int_inet4or6;
    650 	hints.ai_socktype = socktype;
    651 	snprintf(serv, sizeof serv, "%d", port );
    652 
    653 	/* most getaddrinfo(3) use non-threadsafe resolver libraries */
    654 	LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex);
    655 
    656 	err = getaddrinfo( host, serv, &hints, &res );
    657 
    658 	LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex);
    659 
    660 	if ( err != 0 ) {
    661 		Debug1(LDAP_DEBUG_TRACE,
    662 			"ldap_connect_to_host: getaddrinfo failed: %s\n",
    663 			AC_GAI_STRERROR(err) );
    664 		return -1;
    665 	}
    666 	rc = -1;
    667 
    668 	for( sai=res; sai != NULL; sai=sai->ai_next) {
    669 		unsigned short bind_success = 1;
    670 		if( sai->ai_addr == NULL ) {
    671 			Debug0(LDAP_DEBUG_TRACE,
    672 				"ldap_connect_to_host: getaddrinfo "
    673 				"ai_addr is NULL?\n" );
    674 			continue;
    675 		}
    676 
    677 #ifndef LDAP_PF_INET6
    678 		if ( sai->ai_family == AF_INET6 ) continue;
    679 #endif
    680 		/* we assume AF_x and PF_x are equal for all x */
    681 		s = ldap_int_socket( ld, sai->ai_family, socktype );
    682 		if ( s == AC_SOCKET_INVALID ) {
    683 			continue;
    684 		}
    685 
    686 		if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) {
    687 			ldap_pvt_close_socket(ld, s);
    688 			break;
    689 		}
    690 
    691 		switch (sai->ai_family) {
    692 #ifdef LDAP_PF_INET6
    693 			case AF_INET6: {
    694 				char addr[INET6_ADDRSTRLEN];
    695 				inet_ntop( AF_INET6,
    696 					&((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
    697 					addr, sizeof addr);
    698 				Debug2(LDAP_DEBUG_TRACE,
    699 				      "ldap_connect_to_host: Trying %s %s\n",
    700 					addr, serv );
    701 				if( ld->ld_options.ldo_local_ip_addrs.has_ipv6 ) {
    702 					struct sockaddr_in6 ip6addr;
    703 					char bind_addr[INET6_ADDRSTRLEN];
    704 					ip6addr.sin6_family = AF_INET6;
    705 					ip6addr.sin6_port = 0;
    706 					ip6addr.sin6_addr = ld->ld_options.ldo_local_ip_addrs.ip6_addr;
    707 					inet_ntop( AF_INET6,
    708 						&(ip6addr.sin6_addr),
    709 						bind_addr, sizeof bind_addr );
    710 					Debug1( LDAP_DEBUG_TRACE,
    711 						"ldap_connect_to_host: From source address %s\n",
    712 						bind_addr );
    713 					if ( bind( s, ( struct sockaddr* ) &ip6addr, sizeof ip6addr ) != 0 ) {
    714 						Debug1( LDAP_DEBUG_TRACE,
    715 								"ldap_connect_to_host: Failed to bind source address %s\n",
    716 								bind_addr );
    717 						bind_success = 0;
    718 					}
    719 				}
    720 			} break;
    721 #endif
    722 			case AF_INET: {
    723 				char addr[INET_ADDRSTRLEN];
    724 				inet_ntop( AF_INET,
    725 					&((struct sockaddr_in *)sai->ai_addr)->sin_addr,
    726 					addr, sizeof addr);
    727 				Debug2(LDAP_DEBUG_TRACE,
    728 				      "ldap_connect_to_host: Trying %s:%s\n",
    729 					addr, serv );
    730 				if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
    731 					struct sockaddr_in ip4addr;
    732 					char bind_addr[INET_ADDRSTRLEN];
    733 					ip4addr.sin_family = AF_INET;
    734 					ip4addr.sin_port = 0;
    735 					ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
    736 					inet_ntop( AF_INET,
    737 						&(ip4addr.sin_addr),
    738 						bind_addr, sizeof bind_addr );
    739 					Debug1( LDAP_DEBUG_TRACE,
    740 						"ldap_connect_to_host: From source address %s\n",
    741 						bind_addr );
    742 					if ( bind(s, ( struct sockaddr* )&ip4addr, sizeof ip4addr ) != 0 ) {
    743 						Debug1( LDAP_DEBUG_TRACE,
    744 								"ldap_connect_to_host: Failed to bind source address %s\n",
    745 								bind_addr );
    746 						bind_success = 0;
    747 					}
    748 				}
    749 			} break;
    750 		}
    751 		if ( bind_success ) {
    752 			rc = ldap_pvt_connect( ld, s,
    753 				sai->ai_addr, sai->ai_addrlen, async );
    754 			if ( rc == 0 || rc == -2 ) {
    755 				err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr );
    756 				if ( err )
    757 					rc = err;
    758 				else
    759 					break;
    760 			}
    761 		}
    762 		ldap_pvt_close_socket(ld, s);
    763 	}
    764 	freeaddrinfo(res);
    765 
    766 #else
    767 	if (! inet_aton( host, &in ) ) {
    768 		int local_h_errno;
    769 		rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
    770 			&hp, &local_h_errno );
    771 
    772 		if ( (rc < 0) || (hp == NULL) ) {
    773 #ifdef HAVE_WINSOCK
    774 			ldap_pvt_set_errno( WSAGetLastError() );
    775 #else
    776 			/* not exactly right, but... */
    777 			ldap_pvt_set_errno( EHOSTUNREACH );
    778 #endif
    779 			if (ha_buf) LDAP_FREE(ha_buf);
    780 			return -1;
    781 		}
    782 
    783 		use_hp = 1;
    784 	}
    785 
    786 	rc = s = -1;
    787 	for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
    788 		struct sockaddr_in	sin;
    789 		unsigned short bind_success = 1;
    790 #ifdef HAVE_INET_NTOA_B
    791 		char address[INET_ADDR_LEN];
    792 		char bind_addr[INET_ADDR_LEN];
    793 #else
    794 		char *address;
    795 		char *bind_addr;
    796 #endif
    797 		s = ldap_int_socket( ld, PF_INET, socktype );
    798 		if ( s == AC_SOCKET_INVALID ) {
    799 			/* use_hp ? continue : break; */
    800 			break;
    801 		}
    802 
    803 		if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
    804 			ldap_pvt_close_socket(ld, s);
    805 			break;
    806 		}
    807 
    808 		(void)memset((char *)&sin, '\0', sizeof sin);
    809 		sin.sin_family = AF_INET;
    810 		sin.sin_port = htons((unsigned short) port);
    811 
    812 		if( use_hp ) {
    813 			AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i],
    814 				sizeof(sin.sin_addr) );
    815 		} else {
    816 			AC_MEMCPY( &sin.sin_addr, &in.s_addr,
    817 				sizeof(sin.sin_addr) );
    818 		}
    819 
    820 #ifdef HAVE_INET_NTOA_B
    821 		/* for VxWorks */
    822 		inet_ntoa_b( sin.sin_address, address );
    823 #else
    824 		address = inet_ntoa( sin.sin_addr );
    825 #endif
    826 		Debug2( LDAP_DEBUG_TRACE,
    827 			"ldap_connect_to_host: Trying %s:%d\n",
    828 			address, port );
    829 		if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
    830 			struct sockaddr_in ip4addr;
    831 			ip4addr.sin_family = AF_INET;
    832 			ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
    833 #ifdef HAVE_INET_NTOA_B
    834 			inet_ntoa_b( ip4addr.sin_address, bind_addr );
    835 #else
    836 			bind_addr = inet_ntoa( ip4addr.sin_addr );
    837 #endif
    838 			Debug1( LDAP_DEBUG_TRACE,
    839 				"ldap_connect_to_host: From source address %s\n",
    840 				bind_addr );
    841 			if ( bind( s, (struct sockaddr*)&ip4addr, sizeof ip4addr ) != 0 ) {
    842 				Debug1( LDAP_DEBUG_TRACE,
    843 						"ldap_connect_to_host: Failed to bind source address %s\n",
    844 						bind_addr );
    845 				bind_success = 0;
    846 			}
    847 		}
    848 		if ( bind_success ) {
    849 			rc = ldap_pvt_connect(ld, s,
    850 					(struct sockaddr *)&sin, sizeof(sin),
    851 					async);
    852 
    853 			if ( (rc == 0) || (rc == -2) ) {
    854 				int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin );
    855 				if ( err )
    856 					rc = err;
    857 				else
    858 					break;
    859 			}
    860 		}
    861 
    862 		ldap_pvt_close_socket(ld, s);
    863 
    864 		if (!use_hp) break;
    865 	}
    866 	if (ha_buf) LDAP_FREE(ha_buf);
    867 #endif
    868 
    869 	return rc;
    870 }
    871 
    872 #if defined( HAVE_CYRUS_SASL )
    873 char *
    874 ldap_host_connected_to( Sockbuf *sb, const char *host )
    875 {
    876 	ber_socklen_t	len;
    877 #ifdef LDAP_PF_INET6
    878 	struct sockaddr_storage sabuf;
    879 #else
    880 	struct sockaddr sabuf;
    881 #endif
    882 	struct sockaddr	*sa = (struct sockaddr *) &sabuf;
    883 	ber_socket_t	sd;
    884 
    885 	(void)memset( (char *)sa, '\0', sizeof sabuf );
    886 	len = sizeof sabuf;
    887 
    888 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
    889 	if ( getpeername( sd, sa, &len ) == -1 ) {
    890 		return( NULL );
    891 	}
    892 
    893 	/*
    894 	 * do a reverse lookup on the addr to get the official hostname.
    895 	 * this is necessary for kerberos to work right, since the official
    896 	 * hostname is used as the kerberos instance.
    897 	 */
    898 
    899 	switch (sa->sa_family) {
    900 #ifdef LDAP_PF_LOCAL
    901 	case AF_LOCAL:
    902 		return LDAP_STRDUP( ldap_int_hostname );
    903 #endif
    904 #ifdef LDAP_PF_INET6
    905 	case AF_INET6:
    906 		{
    907 			struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT;
    908 			if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr,
    909 				&localhost, sizeof(localhost)) == 0 )
    910 			{
    911 				return LDAP_STRDUP( ldap_int_hostname );
    912 			}
    913 		}
    914 		break;
    915 #endif
    916 	case AF_INET:
    917 		{
    918 			struct in_addr localhost;
    919 			localhost.s_addr = htonl( INADDR_ANY );
    920 
    921 			if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
    922 				&localhost, sizeof(localhost) ) == 0 )
    923 			{
    924 				return LDAP_STRDUP( ldap_int_hostname );
    925 			}
    926 
    927 #ifdef INADDR_LOOPBACK
    928 			localhost.s_addr = htonl( INADDR_LOOPBACK );
    929 
    930 			if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
    931 				&localhost, sizeof(localhost) ) == 0 )
    932 			{
    933 				return LDAP_STRDUP( ldap_int_hostname );
    934 			}
    935 #endif
    936 		}
    937 		break;
    938 
    939 	default:
    940 		return( NULL );
    941 		break;
    942 	}
    943 
    944 	{
    945 		char *herr;
    946 #ifdef NI_MAXHOST
    947 		char hbuf[NI_MAXHOST];
    948 #elif defined( MAXHOSTNAMELEN )
    949 		char hbuf[MAXHOSTNAMELEN];
    950 #else
    951 		char hbuf[256];
    952 #endif
    953 		hbuf[0] = 0;
    954 
    955 		if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0
    956 			&& hbuf[0] )
    957 		{
    958 			return LDAP_STRDUP( hbuf );
    959 		}
    960 	}
    961 
    962 	return host ? LDAP_STRDUP( host ) : NULL;
    963 }
    964 #endif
    965 
    966 
    967 struct selectinfo {
    968 #ifdef HAVE_POLL
    969 	/* for UNIX poll(2) */
    970 	int si_maxfd;
    971 	struct pollfd si_fds[FD_SETSIZE];
    972 #else
    973 	/* for UNIX select(2) */
    974 	fd_set	si_readfds;
    975 	fd_set	si_writefds;
    976 	fd_set	si_use_readfds;
    977 	fd_set	si_use_writefds;
    978 #endif
    979 };
    980 
    981 void
    982 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
    983 {
    984 	struct selectinfo	*sip;
    985 	ber_socket_t		sd;
    986 
    987 	sip = (struct selectinfo *)ld->ld_selectinfo;
    988 
    989 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
    990 
    991 #ifdef HAVE_POLL
    992 	/* for UNIX poll(2) */
    993 	{
    994 		int empty=-1;
    995 		int i;
    996 		for(i=0; i < sip->si_maxfd; i++) {
    997 			if( sip->si_fds[i].fd == sd ) {
    998 				sip->si_fds[i].events |= POLL_WRITE;
    999 				return;
   1000 			}
   1001 			if( empty==-1 && sip->si_fds[i].fd == -1 ) {
   1002 				empty=i;
   1003 			}
   1004 		}
   1005 
   1006 		if( empty == -1 ) {
   1007 			if( sip->si_maxfd >= FD_SETSIZE ) {
   1008 				/* FIXME */
   1009 				return;
   1010 			}
   1011 			empty = sip->si_maxfd++;
   1012 		}
   1013 
   1014 		sip->si_fds[empty].fd = sd;
   1015 		sip->si_fds[empty].events = POLL_WRITE;
   1016 	}
   1017 #else
   1018 	/* for UNIX select(2) */
   1019 	if ( !FD_ISSET( sd, &sip->si_writefds )) {
   1020 		FD_SET( sd, &sip->si_writefds );
   1021 	}
   1022 #endif
   1023 }
   1024 
   1025 
   1026 void
   1027 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
   1028 {
   1029 	struct selectinfo	*sip;
   1030 	ber_socket_t		sd;
   1031 
   1032 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1033 
   1034 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
   1035 
   1036 #ifdef HAVE_POLL
   1037 	/* for UNIX poll(2) */
   1038 	{
   1039 		int empty=-1;
   1040 		int i;
   1041 		for(i=0; i < sip->si_maxfd; i++) {
   1042 			if( sip->si_fds[i].fd == sd ) {
   1043 				sip->si_fds[i].events |= POLL_READ;
   1044 				return;
   1045 			}
   1046 			if( empty==-1 && sip->si_fds[i].fd == -1 ) {
   1047 				empty=i;
   1048 			}
   1049 		}
   1050 
   1051 		if( empty == -1 ) {
   1052 			if( sip->si_maxfd >= FD_SETSIZE ) {
   1053 				/* FIXME */
   1054 				return;
   1055 			}
   1056 			empty = sip->si_maxfd++;
   1057 		}
   1058 
   1059 		sip->si_fds[empty].fd = sd;
   1060 		sip->si_fds[empty].events = POLL_READ;
   1061 	}
   1062 #else
   1063 	/* for UNIX select(2) */
   1064 	if ( !FD_ISSET( sd, &sip->si_readfds )) {
   1065 		FD_SET( sd, &sip->si_readfds );
   1066 	}
   1067 #endif
   1068 }
   1069 
   1070 
   1071 void
   1072 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
   1073 {
   1074 	struct selectinfo	*sip;
   1075 	ber_socket_t		sd;
   1076 
   1077 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1078 
   1079 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
   1080 
   1081 #ifdef HAVE_POLL
   1082 	/* for UNIX poll(2) */
   1083 	{
   1084 		int i;
   1085 		for(i=0; i < sip->si_maxfd; i++) {
   1086 			if( sip->si_fds[i].fd == sd ) {
   1087 				sip->si_fds[i].fd = -1;
   1088 			}
   1089 		}
   1090 	}
   1091 #else
   1092 	/* for UNIX select(2) */
   1093 	FD_CLR( sd, &sip->si_writefds );
   1094 	FD_CLR( sd, &sip->si_readfds );
   1095 #endif
   1096 }
   1097 
   1098 void
   1099 ldap_clear_select_write( LDAP *ld, Sockbuf *sb )
   1100 {
   1101 	struct selectinfo	*sip;
   1102 	ber_socket_t		sd;
   1103 
   1104 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1105 
   1106 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
   1107 
   1108 #ifdef HAVE_POLL
   1109 	/* for UNIX poll(2) */
   1110 	{
   1111 		int i;
   1112 		for(i=0; i < sip->si_maxfd; i++) {
   1113 			if( sip->si_fds[i].fd == sd ) {
   1114 				sip->si_fds[i].events &= ~POLL_WRITE;
   1115 			}
   1116 		}
   1117 	}
   1118 #else
   1119 	/* for UNIX select(2) */
   1120 	FD_CLR( sd, &sip->si_writefds );
   1121 #endif
   1122 }
   1123 
   1124 
   1125 int
   1126 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
   1127 {
   1128 	struct selectinfo	*sip;
   1129 	ber_socket_t		sd;
   1130 
   1131 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1132 
   1133 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
   1134 
   1135 #ifdef HAVE_POLL
   1136 	/* for UNIX poll(2) */
   1137 	{
   1138 		int i;
   1139 		for(i=0; i < sip->si_maxfd; i++) {
   1140 			if( sip->si_fds[i].fd == sd ) {
   1141 				return sip->si_fds[i].revents & POLL_WRITE;
   1142 			}
   1143 		}
   1144 
   1145 		return 0;
   1146 	}
   1147 #else
   1148 	/* for UNIX select(2) */
   1149 	return( FD_ISSET( sd, &sip->si_use_writefds ));
   1150 #endif
   1151 }
   1152 
   1153 
   1154 int
   1155 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
   1156 {
   1157 	struct selectinfo	*sip;
   1158 	ber_socket_t		sd;
   1159 
   1160 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1161 
   1162 	if (ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ))
   1163 		return 1;
   1164 
   1165 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
   1166 
   1167 #ifdef HAVE_POLL
   1168 	/* for UNIX poll(2) */
   1169 	{
   1170 		int i;
   1171 		for(i=0; i < sip->si_maxfd; i++) {
   1172 			if( sip->si_fds[i].fd == sd ) {
   1173 				return sip->si_fds[i].revents & POLL_READ;
   1174 			}
   1175 		}
   1176 
   1177 		return 0;
   1178 	}
   1179 #else
   1180 	/* for UNIX select(2) */
   1181 	return( FD_ISSET( sd, &sip->si_use_readfds ));
   1182 #endif
   1183 }
   1184 
   1185 
   1186 void *
   1187 ldap_new_select_info( void )
   1188 {
   1189 	struct selectinfo	*sip;
   1190 
   1191 	sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo ));
   1192 
   1193 	if ( sip == NULL ) return NULL;
   1194 
   1195 #ifdef HAVE_POLL
   1196 	/* for UNIX poll(2) */
   1197 	/* sip->si_maxfd=0 */
   1198 #else
   1199 	/* for UNIX select(2) */
   1200 	FD_ZERO( &sip->si_readfds );
   1201 	FD_ZERO( &sip->si_writefds );
   1202 #endif
   1203 
   1204 	return( (void *)sip );
   1205 }
   1206 
   1207 
   1208 void
   1209 ldap_free_select_info( void *sip )
   1210 {
   1211 	LDAP_FREE( sip );
   1212 }
   1213 
   1214 
   1215 #ifndef HAVE_POLL
   1216 int ldap_int_tblsize = 0;
   1217 
   1218 void
   1219 ldap_int_ip_init( void )
   1220 {
   1221 #if defined( HAVE_SYSCONF )
   1222 	long tblsize = sysconf( _SC_OPEN_MAX );
   1223 	if( tblsize > INT_MAX ) tblsize = INT_MAX;
   1224 
   1225 #elif defined( HAVE_GETDTABLESIZE )
   1226 	int tblsize = getdtablesize();
   1227 #else
   1228 	int tblsize = FD_SETSIZE;
   1229 #endif /* !USE_SYSCONF */
   1230 
   1231 #ifdef FD_SETSIZE
   1232 	if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE;
   1233 #endif	/* FD_SETSIZE */
   1234 
   1235 	ldap_int_tblsize = tblsize;
   1236 }
   1237 #endif
   1238 
   1239 
   1240 int
   1241 ldap_int_select( LDAP *ld, struct timeval *timeout )
   1242 {
   1243 	int rc;
   1244 	struct selectinfo	*sip;
   1245 
   1246 	Debug0( LDAP_DEBUG_TRACE, "ldap_int_select\n" );
   1247 
   1248 #ifndef HAVE_POLL
   1249 	if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
   1250 #endif
   1251 
   1252 	sip = (struct selectinfo *)ld->ld_selectinfo;
   1253 	assert( sip != NULL );
   1254 
   1255 #ifdef HAVE_POLL
   1256 	{
   1257 		int to = timeout ? TV2MILLISEC( timeout ) : INFTIM;
   1258 		rc = poll( sip->si_fds, sip->si_maxfd, to );
   1259 	}
   1260 #else
   1261 	sip->si_use_readfds = sip->si_readfds;
   1262 	sip->si_use_writefds = sip->si_writefds;
   1263 
   1264 	rc = select( ldap_int_tblsize,
   1265 		&sip->si_use_readfds, &sip->si_use_writefds,
   1266 		NULL, timeout );
   1267 #endif
   1268 
   1269 	return rc;
   1270 }
   1271