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