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