xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/os-ip.c (revision 4b71a66d0f279143147d63ebfcfd8a59499a3684)
1 /* os-ip.c -- platform-specific TCP & UDP related code */
2 /* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.118.2.7 2008/04/15 00:00:36 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 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 
40 #include "ldap-int.h"
41 
42 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
43 #  ifdef LDAP_PF_INET6
44 int ldap_int_inet4or6 = AF_UNSPEC;
45 #  else
46 int ldap_int_inet4or6 = AF_INET;
47 #  endif
48 #endif
49 
50 #ifdef LDAP_DEBUG
51 
52 #define osip_debug(ld,fmt,arg1,arg2,arg3) \
53 do { \
54 	ldap_log_printf(NULL, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
55 } while(0)
56 
57 #else
58 
59 #define osip_debug(ld,fmt,arg1,arg2,arg3) ((void)0)
60 
61 #endif /* LDAP_DEBUG */
62 
63 static void
64 ldap_pvt_set_errno(int err)
65 {
66 	sock_errset(err);
67 }
68 
69 int
70 ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src )
71 {
72 	struct timeval *new;
73 
74 	assert( dest != NULL );
75 
76 	if (src == NULL) {
77 		*dest = NULL;
78 		return 0;
79 	}
80 
81 	new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval));
82 
83 	if( new == NULL ) {
84 		*dest = NULL;
85 		return 1;
86 	}
87 
88 	AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval));
89 
90 	*dest = new;
91 	return 0;
92 }
93 
94 static int
95 ldap_pvt_ndelay_on(LDAP *ld, int fd)
96 {
97 	osip_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
98 	return ber_pvt_socket_set_nonblock( fd, 1 );
99 }
100 
101 static int
102 ldap_pvt_ndelay_off(LDAP *ld, int fd)
103 {
104 	osip_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
105 	return ber_pvt_socket_set_nonblock( fd, 0 );
106 }
107 
108 static ber_socket_t
109 ldap_int_socket(LDAP *ld, int family, int type )
110 {
111 	ber_socket_t s = socket(family, type, 0);
112 	osip_debug(ld, "ldap_new_socket: %d\n",s,0,0);
113 	return ( s );
114 }
115 
116 static int
117 ldap_pvt_close_socket(LDAP *ld, int s)
118 {
119 	osip_debug(ld, "ldap_close_socket: %d\n",s,0,0);
120 	return tcp_close(s);
121 }
122 
123 static int
124 ldap_int_prepare_socket(LDAP *ld, int s, int proto )
125 {
126 	osip_debug( ld, "ldap_prepare_socket: %d\n", s, 0, 0 );
127 
128 #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY )
129 	if ( proto == LDAP_PROTO_TCP ) {
130 		int dummy = 1;
131 #ifdef SO_KEEPALIVE
132 		if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE,
133 			(char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
134 		{
135 			osip_debug( ld, "ldap_prepare_socket: "
136 				"setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
137 				s, 0, 0 );
138 		}
139 #endif /* SO_KEEPALIVE */
140 #ifdef TCP_NODELAY
141 		if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
142 			(char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
143 		{
144 			osip_debug( ld, "ldap_prepare_socket: "
145 				"setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
146 				s, 0, 0 );
147 		}
148 #endif /* TCP_NODELAY */
149 	}
150 #endif /* SO_KEEPALIVE || TCP_NODELAY */
151 
152 	return 0;
153 }
154 
155 #ifndef HAVE_WINSOCK
156 
157 #undef TRACE
158 #define TRACE do { \
159 	osip_debug(ld, \
160 		"ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \
161 		s, \
162 		errno, \
163 		sock_errstr(errno) ); \
164 } while( 0 )
165 
166 /*
167  * check the socket for errors after select returned.
168  */
169 static int
170 ldap_pvt_is_socket_ready(LDAP *ld, int s)
171 {
172 	osip_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
173 
174 #if defined( notyet ) /* && defined( SO_ERROR ) */
175 {
176 	int so_errno;
177 	ber_socklen_t dummy = sizeof(so_errno);
178 	if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
179 		== AC_SOCKET_ERROR )
180 	{
181 		return -1;
182 	}
183 	if ( so_errno ) {
184 		ldap_pvt_set_errno(so_errno);
185 		TRACE;
186 		return -1;
187 	}
188 	return 0;
189 }
190 #else
191 {
192 	/* error slippery */
193 #ifdef LDAP_PF_INET6
194 	struct sockaddr_storage sin;
195 #else
196 	struct sockaddr_in sin;
197 #endif
198 	char ch;
199 	ber_socklen_t dummy = sizeof(sin);
200 	if ( getpeername( s, (struct sockaddr *) &sin, &dummy )
201 		== AC_SOCKET_ERROR )
202 	{
203 		/* XXX: needs to be replace with ber_stream_read() */
204 		read(s, &ch, 1);
205 		TRACE;
206 		return -1;
207 	}
208 	return 0;
209 }
210 #endif
211 	return -1;
212 }
213 #undef TRACE
214 
215 #endif /* HAVE_WINSOCK */
216 
217 /* NOTE: this is identical to analogous code in os-local.c */
218 int
219 ldap_int_poll(
220 	LDAP *ld,
221 	ber_socket_t s,
222 	struct timeval *tvp )
223 {
224 	int		rc;
225 
226 
227 	osip_debug(ld, "ldap_int_poll: fd: %d tm: %ld\n",
228 		s, tvp ? tvp->tv_sec : -1L, 0);
229 
230 #ifdef HAVE_POLL
231 	{
232 		struct pollfd fd;
233 		int timeout = INFTIM;
234 
235 		fd.fd = s;
236 		fd.events = POLL_WRITE;
237 
238 		if ( tvp != NULL ) {
239 			timeout = TV2MILLISEC( tvp );
240 		}
241 		do {
242 			fd.revents = 0;
243 			rc = poll( &fd, 1, timeout );
244 
245 		} while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
246 			LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
247 
248 		if ( rc == AC_SOCKET_ERROR ) {
249 			return rc;
250 		}
251 
252 		if ( timeout == 0 && rc == 0 ) {
253 			return -2;
254 		}
255 
256 		if ( fd.revents & POLL_WRITE ) {
257 			if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
258 				return -1;
259 			}
260 
261 			if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) {
262 				return -1;
263 			}
264 			return 0;
265 		}
266 	}
267 #else
268 	{
269 		fd_set		wfds, *z = NULL;
270 #ifdef HAVE_WINSOCK
271 		fd_set		efds;
272 #endif
273 		struct timeval	tv = { 0 };
274 
275 #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK )
276 		if ( s >= FD_SETSIZE ) {
277 			rc = AC_SOCKET_ERROR;
278 			tcp_close( s );
279 			ldap_pvt_set_errno( EMFILE );
280 			return rc;
281 		}
282 #endif
283 
284 		if ( tvp != NULL ) {
285 			tv = *tvp;
286 		}
287 
288 		do {
289 			FD_ZERO(&wfds);
290 			FD_SET(s, &wfds );
291 
292 #ifdef HAVE_WINSOCK
293 			FD_ZERO(&efds);
294 			FD_SET(s, &efds );
295 #endif
296 
297 			rc = select( ldap_int_tblsize, z, &wfds,
298 #ifdef HAVE_WINSOCK
299 				&efds,
300 #else
301 				z,
302 #endif
303 				tvp ? &tv : NULL );
304 		} while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
305 			LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
306 
307 		if ( rc == AC_SOCKET_ERROR ) {
308 			return rc;
309 		}
310 
311 		if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) {
312 			return -2;
313 		}
314 
315 #ifdef HAVE_WINSOCK
316 		/* This means the connection failed */
317 		if ( FD_ISSET(s, &efds) ) {
318 			int so_errno;
319 			ber_socklen_t dummy = sizeof(so_errno);
320 			if ( getsockopt( s, SOL_SOCKET, SO_ERROR,
321 				(char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno )
322 			{
323 				/* impossible */
324 				so_errno = WSAGetLastError();
325 			}
326 			ldap_pvt_set_errno( so_errno );
327 			osip_debug(ld, "ldap_int_poll: error on socket %d: "
328 			       "errno: %d (%s)\n", s, errno, sock_errstr( errno ));
329 			return -1;
330 		}
331 #endif
332 		if ( FD_ISSET(s, &wfds) ) {
333 #ifndef HAVE_WINSOCK
334 			if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
335 				return -1;
336 			}
337 #endif
338 			if ( ldap_pvt_ndelay_off(ld, s) == -1 ) {
339 				return -1;
340 			}
341 			return 0;
342 		}
343 	}
344 #endif
345 
346 	osip_debug(ld, "ldap_int_poll: timed out\n",0,0,0);
347 	ldap_pvt_set_errno( ETIMEDOUT );
348 	return -1;
349 }
350 
351 static int
352 ldap_pvt_connect(LDAP *ld, ber_socket_t s,
353 	struct sockaddr *sin, ber_socklen_t addrlen,
354 	int async)
355 {
356 	int rc, err;
357 	struct timeval	tv, *opt_tv = NULL;
358 
359 #ifdef LDAP_CONNECTIONLESS
360 	/* We could do a connect() but that would interfere with
361 	 * attempts to poll a broadcast address
362 	 */
363 	if (LDAP_IS_UDP(ld)) {
364 		if (ld->ld_options.ldo_peer)
365 			ldap_memfree(ld->ld_options.ldo_peer);
366 		ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr));
367 		AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr));
368 		return ( 0 );
369 	}
370 #endif
371 	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
372 		tv = ld->ld_options.ldo_tm_net;
373 		opt_tv = &tv;
374 	}
375 
376 	osip_debug(ld, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n",
377 			s, opt_tv ? tv.tv_sec : -1L, async);
378 
379 	if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 )
380 		return ( -1 );
381 
382 	if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) {
383 		if ( opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 )
384 			return ( -1 );
385 		return ( 0 );
386 	}
387 
388 	err = sock_errno();
389 	if ( err != EINPROGRESS && err != EWOULDBLOCK ) {
390 		return ( -1 );
391 	}
392 
393 	if ( async ) {
394 		/* caller will call ldap_int_poll() as appropriate? */
395 		return ( -2 );
396 	}
397 
398 	rc = ldap_int_poll( ld, s, opt_tv );
399 
400 	osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0);
401 
402 	return rc;
403 }
404 
405 #ifndef HAVE_INET_ATON
406 int
407 ldap_pvt_inet_aton( const char *host, struct in_addr *in)
408 {
409 	unsigned long u = inet_addr( host );
410 
411 #ifdef INADDR_NONE
412 	if ( u == INADDR_NONE ) return 0;
413 #endif
414 	if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0;
415 
416 	in->s_addr = u;
417 	return 1;
418 }
419 #endif
420 
421 
422 int
423 ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
424 	int proto,
425 	const char *host, int port,
426 	int async )
427 {
428 	int	rc;
429 	int	socktype;
430 	ber_socket_t		s = AC_SOCKET_INVALID;
431 
432 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
433 	char serv[7];
434 	int err;
435 	struct addrinfo hints, *res, *sai;
436 #else
437 	int i;
438 	int use_hp = 0;
439 	struct hostent *hp = NULL;
440 	struct hostent he_buf;
441 	struct in_addr in;
442 	char *ha_buf=NULL;
443 #endif
444 
445 	if( host == NULL ) host = "localhost";
446 
447 	switch(proto) {
448 	case LDAP_PROTO_TCP: socktype = SOCK_STREAM;
449 		osip_debug( ld,
450 			"ldap_connect_to_host: TCP %s:%d\n",
451 			host, port, 0);
452 		break;
453 	case LDAP_PROTO_UDP: socktype = SOCK_DGRAM;
454 		osip_debug( ld,
455 			"ldap_connect_to_host: UDP %s:%d\n",
456 			host, port, 0);
457 		break;
458 	default:
459 		osip_debug( ld, "ldap_connect_to_host: unknown proto: %d\n",
460 			proto, 0, 0 );
461 		return -1;
462 	}
463 
464 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
465 	memset( &hints, '\0', sizeof(hints) );
466 #ifdef USE_AI_ATTRCONFIG /* FIXME: configure test needed */
467 	/* Use AI_ATTRCONFIG only on systems where its known to be needed. */
468 	hints.ai_flags = AI_ATTRCONFIG;
469 #endif
470 	hints.ai_family = ldap_int_inet4or6;
471 	hints.ai_socktype = socktype;
472 	snprintf(serv, sizeof serv, "%d", port );
473 
474 #ifdef LDAP_R_COMPILE
475 	/* most getaddrinfo(3) use non-threadsafe resolver libraries */
476 	ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
477 #endif
478 
479 	err = getaddrinfo( host, serv, &hints, &res );
480 
481 #ifdef LDAP_R_COMPILE
482 	ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
483 #endif
484 
485 	if ( err != 0 ) {
486 		osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n",
487 			AC_GAI_STRERROR(err), 0, 0);
488 		return -1;
489 	}
490 	rc = -1;
491 
492 	for( sai=res; sai != NULL; sai=sai->ai_next) {
493 		if( sai->ai_addr == NULL ) {
494 			osip_debug(ld, "ldap_connect_to_host: getaddrinfo "
495 				"ai_addr is NULL?\n", 0, 0, 0);
496 			continue;
497 		}
498 
499 		/* we assume AF_x and PF_x are equal for all x */
500 		s = ldap_int_socket( ld, sai->ai_family, socktype );
501 		if ( s == AC_SOCKET_INVALID ) {
502 			continue;
503 		}
504 
505 		if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) {
506 			ldap_pvt_close_socket(ld, s);
507 			break;
508 		}
509 
510 		switch (sai->ai_family) {
511 #ifdef LDAP_PF_INET6
512 			case AF_INET6: {
513 				char addr[INET6_ADDRSTRLEN];
514 				inet_ntop( AF_INET6,
515 					&((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
516 					addr, sizeof addr);
517 				osip_debug(ld, "ldap_connect_to_host: Trying %s %s\n",
518 					addr, serv, 0);
519 			} break;
520 #endif
521 			case AF_INET: {
522 				char addr[INET_ADDRSTRLEN];
523 				inet_ntop( AF_INET,
524 					&((struct sockaddr_in *)sai->ai_addr)->sin_addr,
525 					addr, sizeof addr);
526 				osip_debug(ld, "ldap_connect_to_host: Trying %s:%s\n",
527 					addr, serv, 0);
528 			} break;
529 		}
530 
531 		rc = ldap_pvt_connect( ld, s,
532 			sai->ai_addr, sai->ai_addrlen, async );
533 		if ( rc == 0 || rc == -2 ) {
534 			ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
535 			break;
536 		}
537 		ldap_pvt_close_socket(ld, s);
538 	}
539 	freeaddrinfo(res);
540 
541 #else
542 	if (! inet_aton( host, &in ) ) {
543 		int local_h_errno;
544 		rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
545 			&hp, &local_h_errno );
546 
547 		if ( (rc < 0) || (hp == NULL) ) {
548 #ifdef HAVE_WINSOCK
549 			ldap_pvt_set_errno( WSAGetLastError() );
550 #else
551 			/* not exactly right, but... */
552 			ldap_pvt_set_errno( EHOSTUNREACH );
553 #endif
554 			if (ha_buf) LDAP_FREE(ha_buf);
555 			return -1;
556 		}
557 
558 		use_hp = 1;
559 	}
560 
561 	rc = s = -1;
562 	for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
563 		struct sockaddr_in	sin;
564 
565 		s = ldap_int_socket( ld, PF_INET, socktype );
566 		if ( s == AC_SOCKET_INVALID ) {
567 			/* use_hp ? continue : break; */
568 			break;
569 		}
570 
571 		if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
572 			ldap_pvt_close_socket(ld, s);
573 			break;
574 		}
575 
576 		(void)memset((char *)&sin, '\0', sizeof sin);
577 		sin.sin_family = AF_INET;
578 		sin.sin_port = htons((unsigned short) port);
579 
580 		if( use_hp ) {
581 			AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i],
582 				sizeof(sin.sin_addr) );
583 		} else {
584 			AC_MEMCPY( &sin.sin_addr, &in.s_addr,
585 				sizeof(sin.sin_addr) );
586 		}
587 
588 #ifdef HAVE_INET_NTOA_B
589 		{
590 			/* for VxWorks */
591 			char address[INET_ADDR_LEN];
592 			inet_ntoa_b(sin.sin_address, address);
593 			osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n",
594 				address, port, 0);
595 		}
596 #else
597 		osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n",
598 			inet_ntoa(sin.sin_addr), port, 0);
599 #endif
600 
601 		rc = ldap_pvt_connect(ld, s,
602 			(struct sockaddr *)&sin, sizeof(sin),
603 			async);
604 
605 		if ( (rc == 0) || (rc == -2) ) {
606 			ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
607 			break;
608 		}
609 
610 		ldap_pvt_close_socket(ld, s);
611 
612 		if (!use_hp) break;
613 	}
614 	if (ha_buf) LDAP_FREE(ha_buf);
615 #endif
616 
617 	return rc;
618 }
619 
620 #if defined( HAVE_CYRUS_SASL )
621 char *
622 ldap_host_connected_to( Sockbuf *sb, const char *host )
623 {
624 	ber_socklen_t	len;
625 #ifdef LDAP_PF_INET6
626 	struct sockaddr_storage sabuf;
627 #else
628 	struct sockaddr sabuf;
629 #endif
630 	struct sockaddr	*sa = (struct sockaddr *) &sabuf;
631 	ber_socket_t	sd;
632 
633 	(void)memset( (char *)sa, '\0', sizeof sabuf );
634 	len = sizeof sabuf;
635 
636 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
637 	if ( getpeername( sd, sa, &len ) == -1 ) {
638 		return( NULL );
639 	}
640 
641 	/*
642 	 * do a reverse lookup on the addr to get the official hostname.
643 	 * this is necessary for kerberos to work right, since the official
644 	 * hostname is used as the kerberos instance.
645 	 */
646 
647 	switch (sa->sa_family) {
648 #ifdef LDAP_PF_LOCAL
649 	case AF_LOCAL:
650 		return LDAP_STRDUP( ldap_int_hostname );
651 #endif
652 #ifdef LDAP_PF_INET6
653 	case AF_INET6:
654 		{
655 			struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT;
656 			if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr,
657 				&localhost, sizeof(localhost)) == 0 )
658 			{
659 				return LDAP_STRDUP( ldap_int_hostname );
660 			}
661 		}
662 		break;
663 #endif
664 	case AF_INET:
665 		{
666 			struct in_addr localhost;
667 			localhost.s_addr = htonl( INADDR_ANY );
668 
669 			if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
670 				&localhost, sizeof(localhost) ) == 0 )
671 			{
672 				return LDAP_STRDUP( ldap_int_hostname );
673 			}
674 
675 #ifdef INADDR_LOOPBACK
676 			localhost.s_addr = htonl( INADDR_LOOPBACK );
677 
678 			if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
679 				&localhost, sizeof(localhost) ) == 0 )
680 			{
681 				return LDAP_STRDUP( ldap_int_hostname );
682 			}
683 #endif
684 		}
685 		break;
686 
687 	default:
688 		return( NULL );
689 		break;
690 	}
691 
692 	{
693 		char *herr;
694 #ifdef NI_MAXHOST
695 		char hbuf[NI_MAXHOST];
696 #elif defined( MAXHOSTNAMELEN
697 		char hbuf[MAXHOSTNAMELEN];
698 #else
699 		char hbuf[256];
700 #endif
701 		hbuf[0] = 0;
702 
703 		if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0
704 			&& hbuf[0] )
705 		{
706 			return LDAP_STRDUP( hbuf );
707 		}
708 	}
709 
710 	return host ? LDAP_STRDUP( host ) : NULL;
711 }
712 #endif
713 
714 
715 struct selectinfo {
716 #ifdef HAVE_POLL
717 	/* for UNIX poll(2) */
718 	int si_maxfd;
719 	struct pollfd si_fds[FD_SETSIZE];
720 #else
721 	/* for UNIX select(2) */
722 	fd_set	si_readfds;
723 	fd_set	si_writefds;
724 	fd_set	si_use_readfds;
725 	fd_set	si_use_writefds;
726 #endif
727 };
728 
729 void
730 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
731 {
732 	struct selectinfo	*sip;
733 	ber_socket_t		sd;
734 
735 	sip = (struct selectinfo *)ld->ld_selectinfo;
736 
737 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
738 
739 #ifdef HAVE_POLL
740 	/* for UNIX poll(2) */
741 	{
742 		int empty=-1;
743 		int i;
744 		for(i=0; i < sip->si_maxfd; i++) {
745 			if( sip->si_fds[i].fd == sd ) {
746 				sip->si_fds[i].events |= POLL_WRITE;
747 				return;
748 			}
749 			if( empty==-1 && sip->si_fds[i].fd == -1 ) {
750 				empty=i;
751 			}
752 		}
753 
754 		if( empty == -1 ) {
755 			if( sip->si_maxfd >= FD_SETSIZE ) {
756 				/* FIXME */
757 				return;
758 			}
759 			empty = sip->si_maxfd++;
760 		}
761 
762 		sip->si_fds[empty].fd = sd;
763 		sip->si_fds[empty].events = POLL_WRITE;
764 	}
765 #else
766 	/* for UNIX select(2) */
767 	if ( !FD_ISSET( sd, &sip->si_writefds )) {
768 		FD_SET( sd, &sip->si_writefds );
769 	}
770 #endif
771 }
772 
773 
774 void
775 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
776 {
777 	struct selectinfo	*sip;
778 	ber_socket_t		sd;
779 
780 	sip = (struct selectinfo *)ld->ld_selectinfo;
781 
782 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
783 
784 #ifdef HAVE_POLL
785 	/* for UNIX poll(2) */
786 	{
787 		int empty=-1;
788 		int i;
789 		for(i=0; i < sip->si_maxfd; i++) {
790 			if( sip->si_fds[i].fd == sd ) {
791 				sip->si_fds[i].events |= POLL_READ;
792 				return;
793 			}
794 			if( empty==-1 && sip->si_fds[i].fd == -1 ) {
795 				empty=i;
796 			}
797 		}
798 
799 		if( empty == -1 ) {
800 			if( sip->si_maxfd >= FD_SETSIZE ) {
801 				/* FIXME */
802 				return;
803 			}
804 			empty = sip->si_maxfd++;
805 		}
806 
807 		sip->si_fds[empty].fd = sd;
808 		sip->si_fds[empty].events = POLL_READ;
809 	}
810 #else
811 	/* for UNIX select(2) */
812 	if ( !FD_ISSET( sd, &sip->si_readfds )) {
813 		FD_SET( sd, &sip->si_readfds );
814 	}
815 #endif
816 }
817 
818 
819 void
820 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
821 {
822 	struct selectinfo	*sip;
823 	ber_socket_t		sd;
824 
825 	sip = (struct selectinfo *)ld->ld_selectinfo;
826 
827 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
828 
829 #ifdef HAVE_POLL
830 	/* for UNIX poll(2) */
831 	{
832 		int i;
833 		for(i=0; i < sip->si_maxfd; i++) {
834 			if( sip->si_fds[i].fd == sd ) {
835 				sip->si_fds[i].fd = -1;
836 			}
837 		}
838 	}
839 #else
840 	/* for UNIX select(2) */
841 	FD_CLR( sd, &sip->si_writefds );
842 	FD_CLR( sd, &sip->si_readfds );
843 #endif
844 }
845 
846 
847 int
848 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
849 {
850 	struct selectinfo	*sip;
851 	ber_socket_t		sd;
852 
853 	sip = (struct selectinfo *)ld->ld_selectinfo;
854 
855 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
856 
857 #ifdef HAVE_POLL
858 	/* for UNIX poll(2) */
859 	{
860 		int i;
861 		for(i=0; i < sip->si_maxfd; i++) {
862 			if( sip->si_fds[i].fd == sd ) {
863 				return sip->si_fds[i].revents & POLL_WRITE;
864 			}
865 		}
866 
867 		return 0;
868 	}
869 #else
870 	/* for UNIX select(2) */
871 	return( FD_ISSET( sd, &sip->si_use_writefds ));
872 #endif
873 }
874 
875 
876 int
877 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
878 {
879 	struct selectinfo	*sip;
880 	ber_socket_t		sd;
881 
882 	sip = (struct selectinfo *)ld->ld_selectinfo;
883 
884 	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
885 
886 #ifdef HAVE_POLL
887 	/* for UNIX poll(2) */
888 	{
889 		int i;
890 		for(i=0; i < sip->si_maxfd; i++) {
891 			if( sip->si_fds[i].fd == sd ) {
892 				return sip->si_fds[i].revents & POLL_READ;
893 			}
894 		}
895 
896 		return 0;
897 	}
898 #else
899 	/* for UNIX select(2) */
900 	return( FD_ISSET( sd, &sip->si_use_readfds ));
901 #endif
902 }
903 
904 
905 void *
906 ldap_new_select_info( void )
907 {
908 	struct selectinfo	*sip;
909 
910 	sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo ));
911 
912 	if ( sip == NULL ) return NULL;
913 
914 #ifdef HAVE_POLL
915 	/* for UNIX poll(2) */
916 	/* sip->si_maxfd=0 */
917 #else
918 	/* for UNIX select(2) */
919 	FD_ZERO( &sip->si_readfds );
920 	FD_ZERO( &sip->si_writefds );
921 #endif
922 
923 	return( (void *)sip );
924 }
925 
926 
927 void
928 ldap_free_select_info( void *sip )
929 {
930 	LDAP_FREE( sip );
931 }
932 
933 
934 #ifndef HAVE_POLL
935 int ldap_int_tblsize = 0;
936 
937 void
938 ldap_int_ip_init( void )
939 {
940 #if defined( HAVE_SYSCONF )
941 	long tblsize = sysconf( _SC_OPEN_MAX );
942 	if( tblsize > INT_MAX ) tblsize = INT_MAX;
943 
944 #elif defined( HAVE_GETDTABLESIZE )
945 	int tblsize = getdtablesize();
946 #else
947 	int tblsize = FD_SETSIZE;
948 #endif /* !USE_SYSCONF */
949 
950 #ifdef FD_SETSIZE
951 	if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE;
952 #endif	/* FD_SETSIZE */
953 
954 	ldap_int_tblsize = tblsize;
955 }
956 #endif
957 
958 
959 int
960 ldap_int_select( LDAP *ld, struct timeval *timeout )
961 {
962 	int rc;
963 	struct selectinfo	*sip;
964 
965 	Debug( LDAP_DEBUG_TRACE, "ldap_int_select\n", 0, 0, 0 );
966 
967 #ifndef HAVE_POLL
968 	if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
969 #endif
970 
971 	sip = (struct selectinfo *)ld->ld_selectinfo;
972 	assert( sip != NULL );
973 
974 #ifdef HAVE_POLL
975 	{
976 		int to = timeout ? TV2MILLISEC( timeout ) : INFTIM;
977 		rc = poll( sip->si_fds, sip->si_maxfd, to );
978 	}
979 #else
980 	sip->si_use_readfds = sip->si_readfds;
981 	sip->si_use_writefds = sip->si_writefds;
982 
983 	rc = select( ldap_int_tblsize,
984 		&sip->si_use_readfds, &sip->si_use_writefds,
985 		NULL, timeout );
986 #endif
987 
988 	return rc;
989 }
990