xref: /titanic_50/usr/src/lib/libldap5/sources/ldap/common/os-ip.c (revision dd52495f0d9ba8ff6d84921ec0500be837896554)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * The contents of this file are subject to the Netscape Public
10  * License Version 1.1 (the "License"); you may not use this file
11  * except in compliance with the License. You may obtain a copy of
12  * the License at http://www.mozilla.org/NPL/
13  *
14  * Software distributed under the License is distributed on an "AS
15  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
16  * implied. See the License for the specific language governing
17  * rights and limitations under the License.
18  *
19  * The Original Code is Mozilla Communicator client code, released
20  * March 31, 1998.
21  *
22  * The Initial Developer of the Original Code is Netscape
23  * Communications Corporation. Portions created by Netscape are
24  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
25  * Rights Reserved.
26  *
27  * Contributor(s):
28  */
29 /*
30  *  Copyright (c) 1995 Regents of the University of Michigan.
31  *  All rights reserved.
32  */
33 /*
34  *  os-ip.c -- platform-specific TCP & UDP related code
35  */
36 
37 #if 0
38 #ifndef lint
39 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
40 #endif
41 #endif
42 
43 #include "ldap-int.h"
44 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
45 #include <signal.h>
46 #endif
47 
48 #ifdef NSLDAPI_HAVE_POLL
49 #include <poll.h>
50 #endif
51 
52 
53 #ifdef _WINDOWS
54 #define NSLDAPI_INVALID_OS_SOCKET( s )	((s) == INVALID_SOCKET)
55 #else
56 #define NSLDAPI_INVALID_OS_SOCKET( s )	((s) < 0 )
57 #endif
58 
59 
60 #define NSLDAPI_POLL_ARRAY_GROWTH  5  /* grow arrays 5 elements at a time */
61 
62 
63 /*
64  * Structures and union for tracking status of network sockets
65  */
66 #ifdef NSLDAPI_HAVE_POLL
67 struct nsldapi_os_statusinfo {		/* used with native OS poll() */
68 	struct pollfd		*ossi_pollfds;
69 	int			ossi_pollfds_size;
70 };
71 #else /* NSLDAPI_HAVE_POLL */
72 struct nsldapi_os_statusinfo {		/* used with native OS select() */
73 	fd_set			ossi_readfds;
74 	fd_set			ossi_writefds;
75 	fd_set			ossi_use_readfds;
76 	fd_set			ossi_use_writefds;
77 };
78 #endif /* else NSLDAPI_HAVE_POLL */
79 
80 struct nsldapi_cb_statusinfo {		/* used with ext. I/O poll() callback */
81     LDAP_X_PollFD		*cbsi_pollfds;
82     int				cbsi_pollfds_size;
83 };
84 
85 /*
86  * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
87  * matches the LDAP_X_PollFD pollfd.
88  */
89 #ifdef _WINDOWS
90 #define NSLDAPI_CB_POLL_SD_CAST		(unsigned int)
91 #else
92 #define NSLDAPI_CB_POLL_SD_CAST
93 #endif
94 #if defined(LDAP_SASLIO_HOOKS)
95 #define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
96     ( ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd)) && \
97     (((sbp)->sb_sasl_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) || \
98     ((sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) ) )
99 #else
100 #define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
101     ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd) && \
102     (sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg)
103 #endif
104 
105 
106 struct nsldapi_iostatus_info {
107 	int				ios_type;
108 #define NSLDAPI_IOSTATUS_TYPE_OSNATIVE		1   /* poll() or select() */
109 #define NSLDAPI_IOSTATUS_TYPE_CALLBACK		2   /* poll()-like */
110 	int				ios_read_count;
111 	int				ios_write_count;
112 	union {
113 	    struct nsldapi_os_statusinfo	ios_osinfo;
114 	    struct nsldapi_cb_statusinfo	ios_cbinfo;
115 	} ios_status;
116 };
117 
118 
119 #ifdef NSLDAPI_HAVE_POLL
120 static int nsldapi_add_to_os_pollfds( int fd,
121     struct nsldapi_os_statusinfo *pip, short events );
122 static int nsldapi_clear_from_os_pollfds( int fd,
123     struct nsldapi_os_statusinfo *pip, short events );
124 static int nsldapi_find_in_os_pollfds( int fd,
125     struct nsldapi_os_statusinfo *pip, short revents );
126 #endif /* NSLDAPI_HAVE_POLL */
127 
128 static int nsldapi_iostatus_init_nolock( LDAP *ld );
129 static int nsldapi_add_to_cb_pollfds( Sockbuf *sb,
130     struct nsldapi_cb_statusinfo *pip, short events );
131 static int nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
132     struct nsldapi_cb_statusinfo *pip, short events );
133 static int nsldapi_find_in_cb_pollfds( Sockbuf *sb,
134     struct nsldapi_cb_statusinfo *pip, short revents );
135 
136 
137 #ifdef irix
138 #ifndef _PR_THREADS
139 /*
140  * XXXmcs: on IRIX NSPR's poll() and select() wrappers will crash if NSPR
141  * has not been initialized.  We work around the problem by bypassing
142  * the NSPR wrapper functions and going directly to the OS' functions.
143  */
144 #define NSLDAPI_POLL		_poll
145 #define NSLDAPI_SELECT		_select
146 extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
147 extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
148         fd_set *exceptfds, struct timeval *timeout);
149 #else /* _PR_THREADS */
150 #define NSLDAPI_POLL		poll
151 #define NSLDAPI_SELECT		select
152 #endif /* else _PR_THREADS */
153 #else /* irix */
154 #define NSLDAPI_POLL		poll
155 #define NSLDAPI_SELECT		select
156 #endif /* else irix */
157 
158 
159 static LBER_SOCKET nsldapi_os_socket( LDAP *ld, int secure, int domain,
160 	int type, int protocol );
161 static int nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp );
162 static int nsldapi_os_connect_with_to( LBER_SOCKET s, struct sockaddr *name,
163 	int namelen, LDAP *ld);
164 
165 /*
166  * Function typedefs used by nsldapi_try_each_host()
167  */
168 typedef LBER_SOCKET (NSLDAPI_SOCKET_FN)( LDAP *ld, int secure, int domain,
169 	    int type, int protocol );
170 typedef int (NSLDAPI_IOCTL_FN)( LBER_SOCKET s, int option, int *statusp );
171 typedef int (NSLDAPI_CONNECT_WITH_TO_FN )( LBER_SOCKET s, struct sockaddr *name,
172 	int namelen, LDAP *ld);
173 typedef int (NSLDAPI_CONNECT_FN )( LBER_SOCKET s, struct sockaddr *name,
174 	int namelen );
175 typedef int (NSLDAPI_CLOSE_FN )( LBER_SOCKET s );
176 
177 static int nsldapi_try_each_host( LDAP *ld, const char *hostlist, int defport,
178 	int secure, NSLDAPI_SOCKET_FN *socketfn, NSLDAPI_IOCTL_FN *ioctlfn,
179 	NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
180 	NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn );
181 
182 
183 static int
184 nsldapi_os_closesocket( LBER_SOCKET s )
185 {
186 	int	rc;
187 
188 #ifdef _WINDOWS
189 	rc = closesocket( s );
190 #else
191 	rc = close( s );
192 #endif
193 	return( rc );
194 }
195 
196 
197 static LBER_SOCKET
198 nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
199 {
200 	int		s, invalid_socket;
201 	char		*errmsg = NULL;
202 
203 	if ( secure ) {
204 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
205 			    nsldapi_strdup( dgettext(TEXT_DOMAIN,
206 				"secure mode not supported") ));
207 		return( -1 );
208 	}
209 
210 	s = socket( domain, type, protocol );
211 
212 	/*
213 	 * if the socket() call failed or it returned a socket larger
214 	 * than we can deal with, return a "local error."
215 	 */
216 	if ( NSLDAPI_INVALID_OS_SOCKET( s )) {
217 		errmsg = dgettext(TEXT_DOMAIN, "unable to create a socket");
218 		invalid_socket = 1;
219 	} else {	/* valid socket -- check for overflow */
220 		invalid_socket = 0;
221 #if !defined(NSLDAPI_HAVE_POLL) && !defined(_WINDOWS)
222 		/* not on Windows and do not have poll() */
223 		if ( s >= FD_SETSIZE ) {
224 			errmsg = "can't use socket >= FD_SETSIZE";
225 		}
226 #endif
227 	}
228 
229 	if ( errmsg != NULL ) {	/* local socket error */
230 		if ( !invalid_socket ) {
231 			nsldapi_os_closesocket( s );
232 		}
233 		errmsg = nsldapi_strdup( errmsg );
234 		LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
235 		return( -1 );
236 	}
237 
238 	return( s );
239 }
240 
241 
242 
243 /*
244  * Non-blocking connect call function
245  */
246 static int
247 nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
248 	int salen, LDAP *ld)
249 {
250 #ifndef _WINDOWS
251 	int		flags;
252 #endif /* _WINDOWS */
253 	int		n, error;
254 	int		len;
255 	fd_set		rset, wset;
256 	struct timeval	tval;
257 #ifdef _WINDOWS
258 	int		nonblock = 1;
259 	int		block = 0;
260 	fd_set		eset;
261 #endif /* _WINDOWS */
262 	int		msec = ld->ld_connect_timeout; /* milliseconds */
263 	int		continue_on_intr = 0;
264 #ifdef _SOLARIS_SDK
265 	hrtime_t	start_time = 0, tmp_time, tv_time; /* nanoseconds */
266 #else
267 	long		start_time = 0, tmp_time; /* seconds */
268 #endif
269 
270 
271 	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
272 		msec, 0, 0);
273 
274 #ifdef _WINDOWS
275 	ioctlsocket(sockfd, FIONBIO, &nonblock);
276 #else
277 	flags = fcntl(sockfd, F_GETFL, 0);
278 	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
279 #endif /* _WINDOWS */
280 
281 	error = 0;
282 	if ((n = connect(sockfd, saptr, salen)) < 0)
283 #ifdef _WINDOWS
284 		if ((n != SOCKET_ERROR) &&  (WSAGetLastError() != WSAEWOULDBLOCK)) {
285 #else
286 		if (errno != EINPROGRESS) {
287 #endif /* _WINDOWS */
288 #ifdef LDAP_DEBUG
289 			if ( ldap_debug & LDAP_DEBUG_TRACE ) {
290 				perror("connect");
291 			}
292 #endif
293 			return (-1);
294 		}
295 
296 	/* success */
297 	if (n == 0)
298 		goto done;
299 
300 	FD_ZERO(&rset);
301 	FD_SET(sockfd, &rset);
302 	wset = rset;
303 
304 #ifdef _WINDOWS
305 	eset = rset;
306 #endif /* _WINDOWS */
307 
308 	if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
309 		LDAPDebug( LDAP_DEBUG_TRACE, "Invalid timeout value detected.."
310 			"resetting connect timeout to default value "
311 			"(LDAP_X_IO_TIMEOUT_NO_TIMEOUT\n", 0, 0, 0);
312 		msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
313 	} else {
314 		if (msec != 0) {
315 			tval.tv_sec = msec / MILLISEC;
316 			tval.tv_usec = (MICROSEC / MILLISEC) *
317 					    (msec % MILLISEC);
318 #ifdef _SOLARIS_SDK
319 			start_time = gethrtime();
320 			tv_time = (hrtime_t)msec * (NANOSEC / MILLISEC);
321 #else
322 			start_time = (long)time(NULL);
323 #endif
324 		} else {
325 			tval.tv_sec = 0;
326 		        tval.tv_usec = 0;
327                 }
328 	}
329 
330 	/* if timeval structure == NULL, select will block indefinitely */
331 	/* 			!= NULL, and value == 0, select will */
332 	/* 			         not block */
333 	/* Windows is a bit quirky on how it behaves w.r.t nonblocking */
334 	/* connects.  If the connect fails, the exception fd, eset, is */
335 	/* set to show the failure.  The first argument in select is */
336 	/* ignored */
337 
338 #ifdef _WINDOWS
339 	if ((n = select(sockfd +1, &rset, &wset, &eset,
340 		(msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
341 		errno = WSAETIMEDOUT;
342 		return (-1);
343 	}
344 	/* if wset is set, the connect worked */
345 	if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
346 		len = sizeof(error);
347 		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
348 			< 0)
349 			return (-1);
350 		goto done;
351 	}
352 
353 	/* if eset is set, the connect failed */
354 	if (FD_ISSET(sockfd, &eset)) {
355 		return (-1);
356 	}
357 
358 	/* failure on select call */
359 	if (n == SOCKET_ERROR) {
360 		perror("select error: SOCKET_ERROR returned");
361 		return (-1);
362 	}
363 #else
364 	/*
365 	 * if LDAP_BITOPT_RESTART and select() is interrupted
366 	 * try again.
367 	 */
368 	do {
369 		continue_on_intr = 0;
370 		if ((n = select(sockfd +1, &rset, &wset, NULL,
371 			(msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? \
372 			    &tval : NULL)) == 0) {
373 			errno = ETIMEDOUT;
374 			return (-1);
375 		}
376 		if (n < 0) {
377 			if ((ld->ld_options & LDAP_BITOPT_RESTART) &&
378 			    (errno == EINTR)) {
379 				continue_on_intr = 1;
380 				errno = 0;
381 				FD_ZERO(&rset);
382 				FD_SET(sockfd, &rset);
383 				wset = rset;
384 				/* honour the timeout */
385 				if ((msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) &&
386 				    (msec !=  0)) {
387 #ifdef _SOLARIS_SDK
388 					tmp_time = gethrtime();
389 					if ((tv_time -=
390 					    (tmp_time - start_time)) <= 0) {
391 #else
392 					tmp_time = (long)time(NULL);
393 					if ((tval.tv_sec -=
394 					    (tmp_time - start_time)) <= 0) {
395 #endif
396 						/* timeout */
397 						errno = ETIMEDOUT;
398 						return (-1);
399 					}
400 #ifdef _SOLARIS_SDK
401 					tval.tv_sec = tv_time / NANOSEC;
402 					tval.tv_usec = (tv_time % NANOSEC) /
403 							(NANOSEC / MICROSEC);
404 #endif
405 					start_time = tmp_time;
406 				}
407 			} else {
408 #ifdef LDAP_DEBUG
409 				perror("select error: ");
410 #endif
411 				return (-1);
412 			}
413 		}
414 	} while (continue_on_intr == 1);
415 
416 	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
417 		len = sizeof(error);
418 		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
419 			< 0)
420 			return (-1);
421 #ifdef LDAP_DEBUG
422 	} else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
423 		perror("select error: sockfd not set");
424 #endif
425 	}
426 #endif /* _WINDOWS */
427 
428 done:
429 #ifdef _WINDOWS
430 	ioctlsocket(sockfd, FIONBIO, &block);
431 #else
432 	fcntl(sockfd, F_SETFL, flags);
433 #endif /* _WINDOWS */
434 
435 	if (error) {
436 		errno = error;
437 		return (-1);
438 	}
439 
440 	return (0);
441 }
442 
443 
444 static int
445 nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
446 {
447 	int		err;
448 #ifdef _WINDOWS
449 	u_long		iostatus;
450 #endif
451 
452 	if ( FIONBIO != option ) {
453 		return( -1 );
454 	}
455 
456 #ifdef _WINDOWS
457 	iostatus = *(u_long *)statusp;
458 	err = ioctlsocket( s, FIONBIO, &iostatus );
459 #else
460 	err = ioctl( s, FIONBIO, (caddr_t)statusp );
461 #endif
462 
463 	return( err );
464 }
465 
466 
467 int
468 nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
469 		int defport, int secure, char **krbinstancep )
470 /*
471  * "defport" must be in host byte order
472  * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
473  * if -1 is returned, ld_errno is set
474  */
475 {
476 	int		s;
477 
478 	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
479 	    NULL == hostlist ? "NULL" : hostlist, defport, 0 );
480 
481 	/*
482 	 * If an extended I/O connect callback has been defined, just use it.
483 	 */
484 	if ( NULL != ld->ld_extconnect_fn ) {
485 		unsigned long connect_opts = 0;
486 
487 		if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
488 			connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
489 		}
490 		if ( secure ) {
491 			connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
492 		}
493 		s = ld->ld_extconnect_fn( hostlist, defport,
494 		    ld->ld_connect_timeout, connect_opts,
495 		    ld->ld_ext_session_arg,
496 		    &sb->sb_ext_io_fns.lbextiofn_socket_arg
497 #ifdef _SOLARIS_SDK
498 		    , NULL );
499 #else
500 		    );
501 #endif	/* _SOLARIS_SDK */
502 
503 	} else {
504 		s = nsldapi_try_each_host( ld, hostlist,
505 			defport, secure, nsldapi_os_socket,
506 			nsldapi_os_ioctl, nsldapi_os_connect_with_to,
507 			NULL, nsldapi_os_closesocket );
508 	}
509 
510 	if ( s < 0 ) {
511 		LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
512 		return( -1 );
513 	}
514 
515 	sb->sb_sd = s;
516 
517 	/*
518 	 * Set krbinstancep (canonical name of host for use by Kerberos).
519 	 */
520 #ifdef KERBEROS
521 	char	*p;
522 
523 	if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
524 	    && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
525 		*p = '\0';
526 	}
527 #else /* KERBEROS */
528 	*krbinstancep = NULL;
529 #endif /* KERBEROS */
530 
531 	return( 0 );
532 }
533 
534 
535 /*
536  * Returns a socket number if successful and -1 if an error occurs.
537  */
538 static int
539 nsldapi_try_each_host( LDAP *ld, const char *hostlist,
540 	int defport, int secure, NSLDAPI_SOCKET_FN *socketfn,
541 	NSLDAPI_IOCTL_FN *ioctlfn, NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
542 	NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn )
543 {
544 	int			rc, i, s, err, connected, use_hp;
545 	int			parse_err, port;
546 	struct sockaddr_in	sin;
547 	nsldapi_in_addr_t	address;
548 	char			**addrlist, *ldhpbuf, *ldhpbuf_allocd;
549 	char			*host;
550 	LDAPHostEnt		ldhent, *ldhp;
551 	struct hostent		*hp;
552 	struct ldap_x_hostlist_status	*status;
553 #ifdef GETHOSTBYNAME_BUF_T
554 	GETHOSTBYNAME_BUF_T	hbuf;
555 	struct hostent		hent;
556 #endif /* GETHOSTBYNAME_BUF_T */
557 
558 	connected = 0;
559 	parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
560             &status );
561 	while ( !connected && LDAP_SUCCESS == parse_err && host != NULL ) {
562 		ldhpbuf_allocd = NULL;
563 		ldhp = NULL;
564 		hp = NULL;
565 		s = 0;
566 		use_hp = 0;
567 		addrlist = NULL;
568 
569 
570 		if (( address = inet_addr( host )) == -1 ) {
571 			if ( ld->ld_dns_gethostbyname_fn == NULL ) {
572 				if (( hp = GETHOSTBYNAME( host, &hent, hbuf,
573 				    sizeof(hbuf), &err )) != NULL ) {
574 					addrlist = hp->h_addr_list;
575 				}
576 			} else {
577 				/*
578 				 * DNS callback installed... use it.
579 				 */
580 #ifdef GETHOSTBYNAME_buf_t
581 				/* avoid allocation by using hbuf if large enough */
582 				if ( sizeof( hbuf ) < ld->ld_dns_bufsize ) {
583 					ldhpbuf = ldhpbuf_allocd
584 					    = NSLDAPI_MALLOC( ld->ld_dns_bufsize );
585 				} else {
586 					ldhpbuf = (char *)hbuf;
587 				}
588 #else /* GETHOSTBYNAME_buf_t */
589 				ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
590 				    ld->ld_dns_bufsize );
591 #endif /* else GETHOSTBYNAME_buf_t */
592 
593 				if ( ldhpbuf == NULL ) {
594 					LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY,
595 					    NULL, NULL );
596 					ldap_memfree( host );
597 					ldap_x_hostlist_statusfree( status );
598 					return( -1 );
599 				}
600 
601 				if (( ldhp = ld->ld_dns_gethostbyname_fn( host,
602 				    &ldhent, ldhpbuf, ld->ld_dns_bufsize, &err,
603 				    ld->ld_dns_extradata )) != NULL ) {
604 					addrlist = ldhp->ldaphe_addr_list;
605 				}
606 			}
607 
608 			if ( addrlist == NULL ) {
609 				LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
610 				LDAP_SET_ERRNO( ld, EHOSTUNREACH );  /* close enough */
611 				if ( ldhpbuf_allocd != NULL ) {
612 					NSLDAPI_FREE( ldhpbuf_allocd );
613 				}
614 				ldap_memfree( host );
615 				ldap_x_hostlist_statusfree( status );
616 				return( -1 );
617 			}
618 			use_hp = 1;
619 		}
620 
621 		rc = -1;
622 		for ( i = 0; !use_hp || ( addrlist[ i ] != 0 ); i++ ) {
623 			if ( -1 == ( s = (*socketfn)( ld, secure, AF_INET,
624 					SOCK_STREAM, 0 ))) {
625 				if ( ldhpbuf_allocd != NULL ) {
626 					NSLDAPI_FREE( ldhpbuf_allocd );
627 				}
628 				ldap_memfree( host );
629 				ldap_x_hostlist_statusfree( status );
630 				return( -1 );
631 			}
632 
633 			if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
634 				int	iostatus = 1;
635 
636 				err = (*ioctlfn)( s, FIONBIO, &iostatus );
637 				if ( err == -1 ) {
638 					LDAPDebug( LDAP_DEBUG_ANY,
639 					    "FIONBIO ioctl failed on %d\n",
640 					    s, 0, 0 );
641 				}
642 			}
643 
644 			(void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
645 			sin.sin_family = AF_INET;
646 			sin.sin_port = htons( (unsigned short)port );
647 
648 			SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
649 			    ( use_hp ? (char *) addrlist[ i ] :
650 			    (char *) &address ), sizeof( sin.sin_addr.s_addr) );
651 
652 			{
653 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
654 /*
655  * Block all of the signals that might interrupt connect() since there
656  * is an OS bug that causes connect() to fail if it is restarted.  Look in
657  * ns/netsite/ldap/include/portable.h for the definition of
658  * LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
659  */
660 				sigset_t	ints_off, oldset;
661 
662 				sigemptyset( &ints_off );
663 				sigaddset( &ints_off, SIGALRM );
664 				sigaddset( &ints_off, SIGIO );
665 				sigaddset( &ints_off, SIGCLD );
666 
667 				sigprocmask( SIG_BLOCK, &ints_off, &oldset );
668 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
669 
670 				if ( NULL != connectwithtofn  ) {
671 					err = (*connectwithtofn)(s,
672 						(struct sockaddr *)&sin,
673 						sizeof(struct sockaddr_in),
674 						ld);
675 				} else {
676 					err = (*connectfn)(s,
677 						(struct sockaddr *)&sin,
678 						sizeof(struct sockaddr_in));
679 				}
680 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
681 /*
682  * restore original signal mask
683  */
684 				sigprocmask( SIG_SETMASK, &oldset, 0 );
685 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
686 
687 			}
688 			if ( err >= 0 ) {
689 				connected = 1;
690 				rc = 0;
691 				break;
692 			} else {
693 				if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
694 #ifdef _WINDOWS
695 					if (err == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
696 						LDAP_SET_ERRNO( ld, EWOULDBLOCK );
697 #endif /* _WINDOWS */
698 					err = LDAP_GET_ERRNO( ld );
699 					if ( NSLDAPI_ERRNO_IO_INPROGRESS( err )) {
700 						LDAPDebug( LDAP_DEBUG_TRACE, "connect would block...\n",
701 							   0, 0, 0 );
702 						rc = -2;
703 						break;
704 					}
705 				}
706 
707 #ifdef LDAP_DEBUG
708 				if ( ldap_debug & LDAP_DEBUG_TRACE ) {
709 					perror( (char *)inet_ntoa( sin.sin_addr ));
710 				}
711 #endif
712 				(*closefn)( s );
713 				if ( !use_hp ) {
714 					break;
715 				}
716 			}
717 		}
718 
719 		ldap_memfree( host );
720 		parse_err = ldap_x_hostlist_next( &host, &port, status );
721 	}
722 
723 	if ( ldhpbuf_allocd != NULL ) {
724 		NSLDAPI_FREE( ldhpbuf_allocd );
725 	}
726 	ldap_memfree( host );
727 	ldap_x_hostlist_statusfree( status );
728 
729 	if ( connected ) {
730 		LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
731 		    s, inet_ntoa( sin.sin_addr ), 0 );
732 	}
733 
734 	return( rc == 0 ? s : -1 );
735 }
736 
737 
738 void
739 nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
740 {
741 	if ( ld->ld_extclose_fn == NULL ) {
742 		nsldapi_os_closesocket( sb->sb_sd );
743 	} else {
744 		ld->ld_extclose_fn( sb->sb_sd,
745 			    sb->sb_ext_io_fns.lbextiofn_socket_arg );
746 	}
747 }
748 
749 
750 #ifdef  KERBEROS
751 char *
752 nsldapi_host_connected_to( Sockbuf *sb )
753 {
754 	struct hostent		*hp;
755 	char			*p;
756 	int			len;
757 	struct sockaddr_in	sin;
758 
759 	(void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
760 	len = sizeof( sin );
761 	if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
762 	    return( NULL );
763 	}
764 
765         /*
766 	 * do a reverse lookup on the addr to get the official hostname.
767 	 * this is necessary for kerberos to work right, since the official
768 	 * hostname is used as the kerberos instance.
769 	 */
770 #error XXXmcs: need to use DNS callbacks here
771 	if (( hp = gethostbyaddr((char *) &sin.sin_addr,
772 	    sizeof( sin.sin_addr ), AF_INET)) != NULL ) {
773 	    if ( hp->h_name != NULL ) {
774 		return( nsldapi_strdup( hp->h_name ));
775 	    }
776 	}
777 
778 	return( NULL );
779 }
780 #endif /* KERBEROS */
781 
782 
783 /*
784  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
785  * Also allocates initializes ld->ld_iostatus if needed..
786  */
787 int
788 nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
789 {
790 	NSLDAPIIOStatus	*iosp;
791 
792 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
793 
794 	if ( ld->ld_iostatus == NULL
795 	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
796 		LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
797 		return( -1 );
798 	}
799 
800 	iosp = ld->ld_iostatus;
801 
802 	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
803 #ifdef NSLDAPI_HAVE_POLL
804 		if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
805 		    &iosp->ios_status.ios_osinfo, POLLOUT )) {
806 			++iosp->ios_write_count;
807 		}
808 #else /* NSLDAPI_HAVE_POLL */
809 		if ( !FD_ISSET( sb->sb_sd,
810 		    &iosp->ios_status.ios_osinfo.ossi_writefds )) {
811 			FD_SET( sb->sb_sd,
812 			    &iosp->ios_status.ios_osinfo.ossi_writefds );
813 			++iosp->ios_write_count;
814 		}
815 #endif /* else NSLDAPI_HAVE_POLL */
816 
817 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
818 		if ( nsldapi_add_to_cb_pollfds( sb,
819 		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
820 			++iosp->ios_write_count;
821 		}
822 
823 	} else {
824 		LDAPDebug( LDAP_DEBUG_ANY,
825 		    "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
826 		     iosp->ios_type, 0, 0 );
827 	}
828 
829 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
830 
831 	return( 0 );
832 }
833 
834 
835 /*
836  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
837  * Also allocates initializes ld->ld_iostatus if needed..
838  */
839 int
840 nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
841 {
842 	NSLDAPIIOStatus	*iosp;
843 
844 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
845 
846 	if ( ld->ld_iostatus == NULL
847 	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
848 		LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
849 		return( -1 );
850 	}
851 
852 	iosp = ld->ld_iostatus;
853 
854 	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
855 #ifdef NSLDAPI_HAVE_POLL
856 		if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
857 		    &iosp->ios_status.ios_osinfo, POLLIN )) {
858 			++iosp->ios_read_count;
859 		}
860 #else /* NSLDAPI_HAVE_POLL */
861 		if ( !FD_ISSET( sb->sb_sd,
862 		    &iosp->ios_status.ios_osinfo.ossi_readfds )) {
863 			FD_SET( sb->sb_sd,
864 			    &iosp->ios_status.ios_osinfo.ossi_readfds );
865 			++iosp->ios_read_count;
866 		}
867 #endif /* else NSLDAPI_HAVE_POLL */
868 
869 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
870 		if ( nsldapi_add_to_cb_pollfds( sb,
871 		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
872 			++iosp->ios_read_count;
873 		}
874 	} else {
875 		LDAPDebug( LDAP_DEBUG_ANY,
876 		    "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
877 		     iosp->ios_type, 0, 0 );
878 	}
879 
880 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
881 
882 	return( 0 );
883 }
884 
885 
886 /*
887  * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
888  * Also allocates initializes ld->ld_iostatus if needed..
889  */
890 int
891 nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
892 {
893 	NSLDAPIIOStatus	*iosp;
894 
895 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
896 
897 	if ( ld->ld_iostatus == NULL
898 	    && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
899 		LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
900 		return( -1 );
901 	}
902 
903 	iosp = ld->ld_iostatus;
904 
905 	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
906 #ifdef NSLDAPI_HAVE_POLL
907 		if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
908 		    &iosp->ios_status.ios_osinfo, POLLOUT )) {
909 			--iosp->ios_write_count;
910 		}
911 		if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
912 		    &iosp->ios_status.ios_osinfo, POLLIN )) {
913 			--iosp->ios_read_count;
914 		}
915 #else /* NSLDAPI_HAVE_POLL */
916 		if ( FD_ISSET( sb->sb_sd,
917 		    &iosp->ios_status.ios_osinfo.ossi_writefds )) {
918 			FD_CLR( sb->sb_sd,
919 			    &iosp->ios_status.ios_osinfo.ossi_writefds );
920 			--iosp->ios_write_count;
921 		}
922 		if ( FD_ISSET( sb->sb_sd,
923 		    &iosp->ios_status.ios_osinfo.ossi_readfds )) {
924 			FD_CLR( sb->sb_sd,
925 			    &iosp->ios_status.ios_osinfo.ossi_readfds );
926 			--iosp->ios_read_count;
927 		}
928 #endif /* else NSLDAPI_HAVE_POLL */
929 
930 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
931 		if ( nsldapi_clear_from_cb_pollfds( sb,
932 		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
933 			--iosp->ios_write_count;
934 		}
935 		if ( nsldapi_clear_from_cb_pollfds( sb,
936 		    &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
937 			--iosp->ios_read_count;
938 		}
939 	} else {
940 		LDAPDebug( LDAP_DEBUG_ANY,
941 		    "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
942 		     iosp->ios_type, 0, 0 );
943 	}
944 
945 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
946 
947 	return( 0 );
948 }
949 
950 
951 /*
952  * Return a non-zero value if sb is ready for write.
953  */
954 int
955 nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
956 {
957 	int		rc;
958 	NSLDAPIIOStatus	*iosp;
959 
960 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
961 	iosp = ld->ld_iostatus;
962 
963 	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
964 #ifdef NSLDAPI_HAVE_POLL
965 		/*
966 		 * if we are using poll() we do something a little tricky: if
967 		 * any bits in the socket's returned events field other than
968 		 * POLLIN (ready for read) are set, we return true.  This
969 		 * is done so we notice when a server closes a connection
970 		 * or when another error occurs.  The actual error will be
971 		 * noticed later when we call write() or send().
972 		 */
973 		rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
974 		    &iosp->ios_status.ios_osinfo, ~POLLIN );
975 
976 #else /* NSLDAPI_HAVE_POLL */
977 		rc = FD_ISSET( sb->sb_sd,
978 			&iosp->ios_status.ios_osinfo.ossi_use_writefds );
979 #endif /* else NSLDAPI_HAVE_POLL */
980 
981 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
982 		rc = nsldapi_find_in_cb_pollfds( sb,
983 		    &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLIN );
984 
985 	} else {
986 		LDAPDebug( LDAP_DEBUG_ANY,
987 		    "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
988 		     iosp->ios_type, 0, 0 );
989 		rc = 0;
990 	}
991 
992 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
993 	return( rc );
994 }
995 
996 
997 /*
998  * Return a non-zero value if sb is ready for read.
999  */
1000 int
1001 nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
1002 {
1003 	int		rc;
1004 	NSLDAPIIOStatus	*iosp;
1005 
1006 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1007 	iosp = ld->ld_iostatus;
1008 
1009 	if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1010 #ifdef NSLDAPI_HAVE_POLL
1011 		/*
1012 		 * if we are using poll() we do something a little tricky: if
1013 		 * any bits in the socket's returned events field other than
1014 		 * POLLOUT (ready for write) are set, we return true.  This
1015 		 * is done so we notice when a server closes a connection
1016 		 * or when another error occurs.  The actual error will be
1017 		 * noticed later when we call read() or recv().
1018 		 */
1019 		rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
1020 		    &iosp->ios_status.ios_osinfo, ~POLLOUT );
1021 
1022 #else /* NSLDAPI_HAVE_POLL */
1023 		rc = FD_ISSET( sb->sb_sd,
1024 		    &iosp->ios_status.ios_osinfo.ossi_use_readfds );
1025 #endif /* else NSLDAPI_HAVE_POLL */
1026 
1027 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1028 		rc = nsldapi_find_in_cb_pollfds( sb,
1029 		    &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLOUT );
1030 
1031 	} else {
1032 		LDAPDebug( LDAP_DEBUG_ANY,
1033 		    "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
1034 		     iosp->ios_type, 0, 0 );
1035 		rc = 0;
1036 	}
1037 
1038 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1039 	return( rc );
1040 }
1041 
1042 
1043 /*
1044  * Allocated and initialize ld->ld_iostatus if not already done.
1045  * Should be called with LDAP_IOSTATUS_LOCK locked.
1046  * Returns 0 if all goes well and -1 if not (sets error in ld)
1047  */
1048 static int
1049 nsldapi_iostatus_init_nolock( LDAP *ld )
1050 {
1051 	NSLDAPIIOStatus	*iosp;
1052 
1053 	if ( ld->ld_iostatus != NULL ) {
1054 		return( 0 );
1055 	}
1056 
1057 	if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
1058 	    sizeof( NSLDAPIIOStatus ))) == NULL ) {
1059 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
1060 		return( -1 );
1061 	}
1062 
1063 	if ( ld->ld_extpoll_fn == NULL ) {
1064 		iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_OSNATIVE;
1065 #ifndef NSLDAPI_HAVE_POLL
1066 		FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_readfds );
1067 		FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_writefds );
1068 #endif /* !NSLDAPI_HAVE_POLL */
1069 
1070 	} else {
1071 		iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
1072 	}
1073 
1074 	ld->ld_iostatus = iosp;
1075 	return( 0 );
1076 }
1077 
1078 
1079 void
1080 nsldapi_iostatus_free( LDAP *ld )
1081 {
1082 	if ( ld == NULL ) {
1083 		return;
1084 	}
1085 
1086 
1087 	/* clean up classic I/O compatibility glue */
1088 	if ( ld->ld_io_fns_ptr != NULL ) {
1089 		if ( ld->ld_ext_session_arg != NULL ) {
1090 			NSLDAPI_FREE( ld->ld_ext_session_arg );
1091 		}
1092 		NSLDAPI_FREE( ld->ld_io_fns_ptr );
1093 	}
1094 
1095 	/* clean up I/O status tracking info. */
1096 	if ( ld->ld_iostatus != NULL ) {
1097 		NSLDAPIIOStatus	*iosp = ld->ld_iostatus;
1098 
1099 		if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1100 #ifdef NSLDAPI_HAVE_POLL
1101 			if ( iosp->ios_status.ios_osinfo.ossi_pollfds
1102 			    != NULL ) {
1103 				NSLDAPI_FREE(
1104 				    iosp->ios_status.ios_osinfo.ossi_pollfds );
1105 			}
1106 #endif /* NSLDAPI_HAVE_POLL */
1107 
1108 		} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1109 			if ( iosp->ios_status.ios_cbinfo.cbsi_pollfds
1110 			    != NULL ) {
1111 				NSLDAPI_FREE(
1112 				    iosp->ios_status.ios_cbinfo.cbsi_pollfds );
1113 			}
1114 		} else {
1115 			LDAPDebug( LDAP_DEBUG_ANY,
1116 			    "nsldapi_iostatus_free: unknown I/O type %d\n",
1117 			     iosp->ios_type, 0, 0 );
1118 		}
1119 
1120 		NSLDAPI_FREE( iosp );
1121 	}
1122 }
1123 
1124 
1125 static int
1126 nsldapi_get_select_table_size( void )
1127 {
1128 	static int	tblsize = 0;	/* static */
1129 
1130 	if ( tblsize == 0 ) {
1131 #if defined(_WINDOWS) || defined(XP_OS2)
1132 		tblsize = FOPEN_MAX; /* ANSI spec. */
1133 #else
1134 #ifdef USE_SYSCONF
1135 		tblsize = sysconf( _SC_OPEN_MAX );
1136 #else /* USE_SYSCONF */
1137 		tblsize = getdtablesize();
1138 #endif /* else USE_SYSCONF */
1139 #endif /* else _WINDOWS */
1140 
1141 		if ( tblsize >= FD_SETSIZE ) {
1142 			/*
1143 			 * clamp value so we don't overrun the fd_set structure
1144 			 */
1145 			tblsize = FD_SETSIZE - 1;
1146 		}
1147 	}
1148 
1149 	return( tblsize );
1150 }
1151 
1152 static int
1153 nsldapi_tv2ms( struct timeval *tv )
1154 {
1155 	if ( tv == NULL ) {
1156 		return( -1 );	/* infinite timout for poll() */
1157 	}
1158 
1159 	return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
1160 }
1161 
1162 
1163 int
1164 nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
1165 {
1166 	int			rc;
1167 	NSLDAPIIOStatus		*iosp;
1168 
1169 	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
1170 
1171 	LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1172 	iosp = ld->ld_iostatus;
1173 
1174 	if ( iosp == NULL ||
1175 	    ( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
1176 		rc = 0;		/* simulate a timeout */
1177 
1178 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1179 #ifdef NSLDAPI_HAVE_POLL
1180 
1181 		rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
1182 		    iosp->ios_status.ios_osinfo.ossi_pollfds_size,
1183 		    nsldapi_tv2ms( timeout ));
1184 
1185 #else /* NSLDAPI_HAVE_POLL */
1186 
1187 		/* two (potentially large) struct copies */
1188 		iosp->ios_status.ios_osinfo.ossi_use_readfds
1189 		    = iosp->ios_status.ios_osinfo.ossi_readfds;
1190 		iosp->ios_status.ios_osinfo.ossi_use_writefds
1191 		    = iosp->ios_status.ios_osinfo.ossi_writefds;
1192 
1193 #ifdef HPUX9
1194 		rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
1195 		    (int *)&iosp->ios_status.ios_osinfo.ossi_use_readfds
1196 		    (int *)&iosp->ios_status.ios_osinfo.ossi_use_writefds,
1197 		    NULL, timeout );
1198 #else
1199 		rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
1200 		    &iosp->ios_status.ios_osinfo.ossi_use_readfds,
1201 		    &iosp->ios_status.ios_osinfo.ossi_use_writefds,
1202 		    NULL, timeout );
1203 #endif /* else HPUX9 */
1204 #endif /* else NSLDAPI_HAVE_POLL */
1205 
1206 	} else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1207 		/*
1208 		 * We always pass the session extended I/O argument to
1209 		 * the extended poll() callback.
1210 		 */
1211 		rc = ld->ld_extpoll_fn(
1212 		    iosp->ios_status.ios_cbinfo.cbsi_pollfds,
1213 		    iosp->ios_status.ios_cbinfo.cbsi_pollfds_size,
1214 		    nsldapi_tv2ms( timeout ), ld->ld_ext_session_arg );
1215 
1216 	} else {
1217 		LDAPDebug( LDAP_DEBUG_ANY,
1218 		    "nsldapi_iostatus_poll: unknown I/O type %d\n",
1219 		     iosp->ios_type, 0, 0 );
1220 		rc = 0;	/* simulate a timeout (what else to do?) */
1221 	}
1222 
1223 	LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1224 	return( rc );
1225 }
1226 
1227 
1228 #ifdef NSLDAPI_HAVE_POLL
1229 /*
1230  * returns 1 if "fd" was added to pollfds.
1231  * returns 1 if some of the bits in "events" were added to pollfds.
1232  * returns 0 if no changes were made.
1233  */
1234 static int
1235 nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1236 	short events )
1237 {
1238 	int	i, openslot;
1239 
1240 	/* first we check to see if "fd" is already in our pollfds */
1241 	openslot = -1;
1242 	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1243 		if ( pip->ossi_pollfds[ i ].fd == fd ) {
1244 			if (( pip->ossi_pollfds[ i ].events & events )
1245 			    != events ) {
1246 				pip->ossi_pollfds[ i ].events |= events;
1247 				return( 1 );
1248 			} else {
1249 				return( 0 );
1250 			}
1251 		}
1252 		if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
1253 			openslot = i;	/* remember for later */
1254 		}
1255 	}
1256 
1257 	/*
1258 	 * "fd" is not currently being poll'd on -- add to array.
1259 	 * if we need to expand the pollfds array, we do it in increments of
1260 	 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
1261 	 */
1262 	if ( openslot == -1 ) {
1263 		struct pollfd	*newpollfds;
1264 
1265 		if ( pip->ossi_pollfds_size == 0 ) {
1266 			newpollfds = (struct pollfd *)NSLDAPI_MALLOC(
1267 			    NSLDAPI_POLL_ARRAY_GROWTH
1268 			    * sizeof( struct pollfd ));
1269 		} else {
1270 			newpollfds = (struct pollfd *)NSLDAPI_REALLOC(
1271 			    pip->ossi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
1272 			    + pip->ossi_pollfds_size)
1273 			    * sizeof( struct pollfd ));
1274 		}
1275 		if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1276 			return( 0 );
1277 		}
1278 		pip->ossi_pollfds = newpollfds;
1279 		openslot = pip->ossi_pollfds_size;
1280 		pip->ossi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
1281 		for ( i = openslot + 1; i < pip->ossi_pollfds_size; ++i ) {
1282 			pip->ossi_pollfds[ i ].fd = -1;
1283 			pip->ossi_pollfds[ i ].events =
1284 			    pip->ossi_pollfds[ i ].revents = 0;
1285 		}
1286 	}
1287 	pip->ossi_pollfds[ openslot ].fd = fd;
1288 	pip->ossi_pollfds[ openslot ].events = events;
1289 	pip->ossi_pollfds[ openslot ].revents = 0;
1290 	return( 1 );
1291 }
1292 
1293 
1294 /*
1295  * returns 1 if any "events" from "fd" were removed from pollfds
1296  * returns 0 of "fd" wasn't in pollfds or if events did not overlap.
1297  */
1298 static int
1299 nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1300     short events )
1301 {
1302 	int	i;
1303 
1304 	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1305 		if ( pip->ossi_pollfds[i].fd == fd ) {
1306 			if (( pip->ossi_pollfds[ i ].events & events ) != 0 ) {
1307 				pip->ossi_pollfds[ i ].events &= ~events;
1308 				if ( pip->ossi_pollfds[ i ].events == 0 ) {
1309 					pip->ossi_pollfds[i].fd = -1;
1310 				}
1311 				return( 1 );	/* events overlap */
1312 			} else {
1313 				return( 0 );	/* events do not overlap */
1314 			}
1315 		}
1316 	}
1317 
1318 	return( 0 );	/* "fd" was not found */
1319 }
1320 
1321 
1322 /*
1323  * returns 1 if any "revents" from "fd" were set in pollfds revents field.
1324  * returns 0 if not.
1325  */
1326 static int
1327 nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1328 	short revents )
1329 {
1330 	int	i;
1331 
1332 	for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1333 		if ( pip->ossi_pollfds[i].fd == fd ) {
1334 			if (( pip->ossi_pollfds[ i ].revents & revents ) != 0 ) {
1335 				return( 1 );	/* revents overlap */
1336 			} else {
1337 				return( 0 );	/* revents do not overlap */
1338 			}
1339 		}
1340 	}
1341 
1342 	return( 0 );	/* "fd" was not found */
1343 }
1344 #endif /* NSLDAPI_HAVE_POLL */
1345 
1346 
1347 /*
1348  * returns 1 if "sb" was added to pollfds.
1349  * returns 1 if some of the bits in "events" were added to pollfds.
1350  * returns 0 if no changes were made.
1351  */
1352 static int
1353 nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1354     short events )
1355 {
1356 	int	i, openslot;
1357 
1358 	/* first we check to see if "sb" is already in our pollfds */
1359 	openslot = -1;
1360 	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1361 		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1362 			if (( pip->cbsi_pollfds[ i ].lpoll_events & events )
1363 			    != events ) {
1364 				pip->cbsi_pollfds[ i ].lpoll_events |= events;
1365 				return( 1 );
1366 			} else {
1367 				return( 0 );
1368 			}
1369 		}
1370 		if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
1371 			openslot = i;	/* remember for later */
1372 		}
1373 	}
1374 
1375 	/*
1376 	 * "sb" is not currently being poll'd on -- add to array.
1377 	 * if we need to expand the pollfds array, we do it in increments of
1378 	 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
1379 	 */
1380 	if ( openslot == -1 ) {
1381 		LDAP_X_PollFD	*newpollfds;
1382 
1383 		if ( pip->cbsi_pollfds_size == 0 ) {
1384 			newpollfds = (LDAP_X_PollFD *)NSLDAPI_MALLOC(
1385 			    NSLDAPI_POLL_ARRAY_GROWTH
1386 			    * sizeof( LDAP_X_PollFD ));
1387 		} else {
1388 			newpollfds = (LDAP_X_PollFD *)NSLDAPI_REALLOC(
1389 			    pip->cbsi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
1390 			    + pip->cbsi_pollfds_size)
1391 			    * sizeof( LDAP_X_PollFD ));
1392 		}
1393 		if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1394 			return( 0 );
1395 		}
1396 		pip->cbsi_pollfds = newpollfds;
1397 		openslot = pip->cbsi_pollfds_size;
1398 		pip->cbsi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
1399 		for ( i = openslot + 1; i < pip->cbsi_pollfds_size; ++i ) {
1400 			pip->cbsi_pollfds[ i ].lpoll_fd = -1;
1401 			pip->cbsi_pollfds[ i ].lpoll_socketarg = NULL;
1402 			pip->cbsi_pollfds[ i ].lpoll_events =
1403 			    pip->cbsi_pollfds[ i ].lpoll_revents = 0;
1404 		}
1405 	}
1406 	pip->cbsi_pollfds[ openslot ].lpoll_fd = sb->sb_sd;
1407 	pip->cbsi_pollfds[ openslot ].lpoll_socketarg =
1408 	    sb->sb_ext_io_fns.lbextiofn_socket_arg;
1409 	pip->cbsi_pollfds[ openslot ].lpoll_events = events;
1410 	pip->cbsi_pollfds[ openslot ].lpoll_revents = 0;
1411 	return( 1 );
1412 }
1413 
1414 
1415 /*
1416  * returns 1 if any "events" from "sb" were removed from pollfds
1417  * returns 0 of "sb" wasn't in pollfds or if events did not overlap.
1418  */
1419 static int
1420 nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
1421     struct nsldapi_cb_statusinfo *pip, short events )
1422 {
1423 	int	i;
1424 
1425 	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1426 		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1427 			if (( pip->cbsi_pollfds[ i ].lpoll_events
1428 			    & events ) != 0 ) {
1429 				pip->cbsi_pollfds[ i ].lpoll_events &= ~events;
1430 				if ( pip->cbsi_pollfds[ i ].lpoll_events
1431 				    == 0 ) {
1432 					pip->cbsi_pollfds[i].lpoll_fd = -1;
1433 				}
1434 				return( 1 );	/* events overlap */
1435 			} else {
1436 				return( 0 );	/* events do not overlap */
1437 			}
1438 		}
1439 	}
1440 
1441 	return( 0 );	/* "sb" was not found */
1442 }
1443 
1444 
1445 /*
1446  * returns 1 if any "revents" from "sb" were set in pollfds revents field.
1447  * returns 0 if not.
1448  */
1449 static int
1450 nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1451     short revents )
1452 {
1453 	int	i;
1454 
1455 	for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1456 		if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1457 			if (( pip->cbsi_pollfds[ i ].lpoll_revents
1458 			    & revents ) != 0 ) {
1459 				return( 1 );	/* revents overlap */
1460 			} else {
1461 				return( 0 );	/* revents do not overlap */
1462 			}
1463 		}
1464 	}
1465 
1466 	return( 0 );	/* "sb" was not found */
1467 }
1468 
1469 
1470 /*
1471  * Install read and write functions into lber layer / sb
1472  */
1473 int
1474 nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
1475 {
1476 	struct lber_x_ext_io_fns	lberiofns;
1477 
1478         memset( &lberiofns, 0, sizeof(struct lber_x_ext_io_fns) );
1479 	if ( NULL != sb ) {
1480 		lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
1481 		lberiofns.lbextiofn_read = ld->ld_extread_fn;
1482 		lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
1483 		lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
1484 		lberiofns.lbextiofn_socket_arg = ld->ld_ext_session_arg;
1485 
1486 		if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
1487 		    &lberiofns ) != 0 ) {
1488 			return( LDAP_LOCAL_ERROR );
1489 		}
1490 	}
1491 
1492 	return( LDAP_SUCCESS );
1493 }
1494 
1495 
1496 /*
1497  ******************************************************************************
1498  * One struct and several functions to bridge the gap between new extended
1499  * I/O functions that are installed using ldap_set_option( ...,
1500  * LDAP_OPT_EXTIO_FN_PTRS, ... ) and the original "classic" I/O functions
1501  * (installed using LDAP_OPT_IO_FN_PTRS) follow.
1502  *
1503  * Our basic strategy is to use the new extended arg to hold a pointer to a
1504  *    structure that contains a pointer to the LDAP * (which contains pointers
1505  *    to the old functions so we can call them) as well as a pointer to an
1506  *    LBER_SOCKET to hold the socket used by the classic functions (the new
1507  *    functions use a simple int for the socket).
1508  */
1509 typedef struct nsldapi_compat_socket_info {
1510     LBER_SOCKET		csi_socket;
1511     LDAP		*csi_ld;
1512 } NSLDAPICompatSocketInfo;
1513 
1514 static int LDAP_CALLBACK
1515 nsldapi_ext_compat_read( int s, void *buf, int len,
1516 	struct lextiof_socket_private *arg )
1517 {
1518 	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
1519 	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
1520 
1521 	return( iofns->liof_read( csip->csi_socket, buf, len ));
1522 }
1523 
1524 
1525 static int LDAP_CALLBACK
1526 nsldapi_ext_compat_write( int s, const void *buf, int len,
1527 	struct lextiof_socket_private *arg  )
1528 {
1529 	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
1530 	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
1531 
1532 	return( iofns->liof_write( csip->csi_socket, buf, len ));
1533 }
1534 
1535 
1536 static int LDAP_CALLBACK
1537 nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
1538 	struct lextiof_session_private *arg )
1539 {
1540 	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
1541 	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
1542 	fd_set			readfds, writefds;
1543 	int			i, rc, maxfd = 0;
1544 	struct timeval		tv, *tvp;
1545 
1546 	/*
1547 	 * Prepare fd_sets for select()
1548 	 */
1549 	FD_ZERO( &readfds );
1550 	FD_ZERO( &writefds );
1551 	for ( i = 0; i < nfds; ++i ) {
1552 		if ( fds[ i ].lpoll_fd < 0 ) {
1553 			continue;
1554 		}
1555 
1556 		if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
1557 			LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
1558 			return( -1 );
1559 		}
1560 
1561 		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
1562 			FD_SET( fds[i].lpoll_fd, &readfds );
1563 		}
1564 
1565 		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
1566 			FD_SET( fds[i].lpoll_fd, &writefds );
1567 		}
1568 
1569 		fds[i].lpoll_revents = 0;	/* clear revents */
1570 
1571 		if ( fds[i].lpoll_fd >= maxfd ) {
1572 			maxfd = fds[i].lpoll_fd;
1573 		}
1574 	}
1575 
1576 	/*
1577 	 * select() using callback.
1578 	 */
1579 	++maxfd;
1580 	if ( timeout == -1 ) {
1581 		tvp = NULL;
1582 	} else {
1583 		tv.tv_sec = timeout / 1000;
1584 		tv.tv_usec = 1000 * ( timeout - tv.tv_sec * 1000 );
1585 		tvp = &tv;
1586 	}
1587 	rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
1588 	if ( rc <= 0 ) {	/* timeout or fatal error */
1589 		return( rc );
1590 	}
1591 
1592 	/*
1593 	 * Use info. in fd_sets to populate poll() revents.
1594 	 */
1595 	for ( i = 0; i < nfds; ++i ) {
1596 		if ( fds[ i ].lpoll_fd < 0 ) {
1597 			continue;
1598 		}
1599 
1600 		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )
1601 		    && FD_ISSET( fds[i].lpoll_fd, &readfds )) {
1602 			fds[i].lpoll_revents |= LDAP_X_POLLIN;
1603 		}
1604 
1605 		if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )
1606 		    && FD_ISSET( fds[i].lpoll_fd, &writefds )) {
1607 			fds[i].lpoll_revents |= LDAP_X_POLLOUT;
1608 		}
1609 
1610 		/* XXXmcs: any other cases to deal with?  LDAP_X_POLLERR? */
1611 	}
1612 
1613 	return( rc );
1614 }
1615 
1616 
1617 static LBER_SOCKET
1618 nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
1619 	int protocol )
1620 {
1621 	int		s;
1622 
1623 	s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
1624 
1625 	if ( s >= 0 ) {
1626 		char				*errmsg = NULL;
1627 
1628 #ifdef NSLDAPI_HAVE_POLL
1629 		if ( ld->ld_io_fns_ptr->liof_select != NULL
1630 			    && s >= FD_SETSIZE ) {
1631 			errmsg = dgettext(TEXT_DOMAIN,
1632 				"can't use socket >= FD_SETSIZE");
1633 		}
1634 #elif !defined(_WINDOWS) /* not on Windows and do not have poll() */
1635 		if ( s >= FD_SETSIZE ) {
1636 			errmsg = "can't use socket >= FD_SETSIZE";
1637 		}
1638 #endif
1639 
1640 		if ( NULL == errmsg && secure &&
1641 			    ld->ld_io_fns_ptr->liof_ssl_enable( s ) < 0 ) {
1642 			errmsg = dgettext(TEXT_DOMAIN,
1643 				"failed to enable secure mode");
1644 		    }
1645 
1646 		if ( NULL != errmsg ) {
1647 			if ( NULL == ld->ld_io_fns_ptr->liof_close ) {
1648 				nsldapi_os_closesocket( s );
1649 			} else {
1650 				ld->ld_io_fns_ptr->liof_close( s );
1651 			}
1652 			LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
1653 				    nsldapi_strdup( errmsg ));
1654 			return( -1 );
1655 		}
1656 	}
1657 
1658 	return( s );
1659 }
1660 
1661 
1662 /*
1663  * Note: timeout is ignored because we have no way to pass it via
1664  * the old I/O callback interface.
1665  */
1666 static int LDAP_CALLBACK
1667 nsldapi_ext_compat_connect( const char *hostlist, int defport, int timeout,
1668 	unsigned long options, struct lextiof_session_private *sessionarg,
1669 	struct lextiof_socket_private **socketargp
1670 #ifdef _SOLARIS_SDK
1671 	, void **not_used )
1672 #else
1673 	)
1674 #endif	/* _SOLARIS_SDK */
1675 {
1676 	NSLDAPICompatSocketInfo		*defcsip;
1677 	struct ldap_io_fns		*iofns;
1678 	int				s, secure;
1679 	NSLDAPI_SOCKET_FN		*socketfn;
1680 	NSLDAPI_IOCTL_FN		*ioctlfn;
1681 	NSLDAPI_CONNECT_WITH_TO_FN	*connectwithtofn;
1682 	NSLDAPI_CONNECT_FN		*connectfn;
1683 	NSLDAPI_CLOSE_FN		*closefn;
1684 
1685 	defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
1686 	iofns = defcsip->csi_ld->ld_io_fns_ptr;
1687 
1688 	if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
1689 		if ( NULL == iofns->liof_ssl_enable ) {
1690 			LDAP_SET_ERRNO( defcsip->csi_ld, EINVAL );
1691 			return( -1 );
1692 		}
1693 		secure = 1;
1694 	} else {
1695 		secure = 0;
1696 	}
1697 
1698 	socketfn = ( iofns->liof_socket == NULL ) ?
1699 		    nsldapi_os_socket : nsldapi_compat_socket;
1700 	ioctlfn = ( iofns->liof_ioctl == NULL ) ?
1701 		    nsldapi_os_ioctl : (NSLDAPI_IOCTL_FN *)(iofns->liof_ioctl);
1702 	if ( NULL == iofns->liof_connect ) {
1703 		connectwithtofn = nsldapi_os_connect_with_to;
1704 		connectfn = NULL;
1705 	} else {
1706 		connectwithtofn = NULL;
1707 		connectfn = iofns->liof_connect;
1708 	}
1709 	closefn = ( iofns->liof_close == NULL ) ?
1710 		    nsldapi_os_closesocket : iofns->liof_close;
1711 
1712 	s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
1713 			secure, socketfn, ioctlfn, connectwithtofn,
1714 			connectfn, closefn );
1715 
1716 	if ( s >= 0 ) {
1717 		NSLDAPICompatSocketInfo		*csip;
1718 
1719 		if (( csip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
1720 		    sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
1721 			(*closefn)( s );
1722 			LDAP_SET_LDERRNO( defcsip->csi_ld, LDAP_NO_MEMORY,
1723 				NULL, NULL );
1724 			return( -1 );
1725 		}
1726 
1727 		csip->csi_socket = s;
1728 		csip->csi_ld = defcsip->csi_ld;
1729 		*socketargp = (void *)csip;
1730 
1731 		/*
1732 		 * We always return 1, which is a valid but not unique socket
1733 		 * (file descriptor) number.  The extended I/O functions only
1734 		 * require that the combination of the void *arg and the int
1735 		 * socket be unique.  Since we allocate the
1736 		 * NSLDAPICompatSocketInfo that we assign to arg, we meet
1737 		 * that requirement.
1738 		 */
1739 		s = 1;
1740 	}
1741 
1742 	return( s );
1743 }
1744 
1745 
1746 static int LDAP_CALLBACK
1747 nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
1748 {
1749 	NSLDAPICompatSocketInfo	*csip = (NSLDAPICompatSocketInfo *)arg;
1750 	struct ldap_io_fns	*iofns = csip->csi_ld->ld_io_fns_ptr;
1751 	int			rc;
1752 
1753 	rc = iofns->liof_close( csip->csi_socket );
1754 
1755 	NSLDAPI_FREE( csip );
1756 
1757 	return( rc );
1758 }
1759 
1760 /*
1761  * Install the I/O functions.
1762  * Return an LDAP error code (LDAP_SUCCESS if all goes well).
1763  */
1764 int
1765 nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
1766 {
1767 	NSLDAPICompatSocketInfo		*defcsip;
1768 
1769 	if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
1770 	    sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
1771 		return( LDAP_NO_MEMORY );
1772 	}
1773 
1774 	defcsip->csi_socket = -1;
1775 	defcsip->csi_ld = ld;
1776 
1777 	if ( ld->ld_io_fns_ptr != NULL ) {
1778 		(void)memset( (char *)ld->ld_io_fns_ptr, 0,
1779 		    sizeof( struct ldap_io_fns ));
1780 	} else if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_CALLOC(
1781 	    1, sizeof( struct ldap_io_fns ))) == NULL ) {
1782 		NSLDAPI_FREE( defcsip );
1783 		return( LDAP_NO_MEMORY );
1784 	}
1785 
1786 	/* struct copy */
1787 	*(ld->ld_io_fns_ptr) = *iofns;
1788 
1789 	ld->ld_extio_size = LBER_X_EXTIO_FNS_SIZE;
1790 	ld->ld_ext_session_arg = defcsip;
1791 	ld->ld_extread_fn = nsldapi_ext_compat_read;
1792 	ld->ld_extwrite_fn = nsldapi_ext_compat_write;
1793 	ld->ld_extpoll_fn = nsldapi_ext_compat_poll;
1794 	ld->ld_extconnect_fn = nsldapi_ext_compat_connect;
1795 	ld->ld_extclose_fn = nsldapi_ext_compat_close;
1796 
1797 	return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
1798 }
1799 /*
1800  * end of compat I/O functions
1801  ******************************************************************************
1802  */
1803 #ifdef _SOLARIS_SDK
1804 /*
1805  * _ns_gethostbyaddr is a helper function for the ssl layer so that
1806  * it can use the ldap layer's gethostbyaddr resolver.
1807  */
1808 
1809 LDAPHostEnt *
1810 _ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type,
1811 	LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
1812 	void *extradata)
1813 {
1814 	if (ld == NULL || ld->ld_dns_gethostbyaddr_fn == NULL)
1815 		return (NULL);
1816 	return (ld->ld_dns_gethostbyaddr_fn(addr, length, type,
1817 		result, buffer, buflen, statusp, extradata));
1818 }
1819 
1820 #endif	/* _SOLARIS_SDK */
1821 
1822 
1823