8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / os-ip.c
blob4dd1f8d6724c0a0c43cbb709fa8d4b2f470278e7
1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
25 * Contributor(s):
28 * Copyright (c) 1995 Regents of the University of Michigan.
29 * All rights reserved.
32 * os-ip.c -- platform-specific TCP & UDP related code
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
41 #include "ldap-int.h"
42 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
43 #include <signal.h>
44 #endif
46 #ifdef NSLDAPI_HAVE_POLL
47 #include <poll.h>
48 #endif
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
58 #define NSLDAPI_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
62 * Structures and union for tracking status of network sockets
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;
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;
76 #endif /* else NSLDAPI_HAVE_POLL */
78 struct nsldapi_cb_statusinfo { /* used with ext. I/O poll() callback */
79 LDAP_X_PollFD *cbsi_pollfds;
80 int cbsi_pollfds_size;
84 * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
85 * matches the LDAP_X_PollFD pollfd.
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
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;
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 */
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 );
135 #ifdef irix
136 #ifndef _PR_THREADS
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.
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 */
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);
164 * Function typedefs used by nsldapi_try_each_host()
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 );
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 );
181 static int
182 nsldapi_os_closesocket( LBER_SOCKET s )
184 int rc;
186 #ifdef _WINDOWS
187 rc = closesocket( s );
188 #else
189 rc = close( s );
190 #endif
191 return( rc );
195 static LBER_SOCKET
196 nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
198 int s, invalid_socket;
199 char *errmsg = NULL;
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 );
208 s = socket( domain, type, protocol );
211 * if the socket() call failed or it returned a socket larger
212 * than we can deal with, return a "local error."
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";
224 #endif
227 if ( errmsg != NULL ) { /* local socket error */
228 if ( !invalid_socket ) {
229 nsldapi_os_closesocket( s );
231 errmsg = nsldapi_strdup( errmsg );
232 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
233 return( -1 );
236 return( s );
242 * Non-blocking connect call function
244 static int
245 nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
246 int salen, LDAP *ld)
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
269 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
270 msec, 0, 0);
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 */
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");
290 #endif
291 return (-1);
294 /* success */
295 if (n == 0)
296 goto done;
298 FD_ZERO(&rset);
299 FD_SET(sockfd, &rset);
300 wset = rset;
302 #ifdef _WINDOWS
303 eset = rset;
304 #endif /* _WINDOWS */
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;
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 */
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);
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;
351 /* if eset is set, the connect failed */
352 if (FD_ISSET(sockfd, &eset)) {
353 return (-1);
356 /* failure on select call */
357 if (n == SOCKET_ERROR) {
358 perror("select error: SOCKET_ERROR returned");
359 return (-1);
361 #else
363 * if LDAP_BITOPT_RESTART and select() is interrupted
364 * try again.
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);
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);
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;
405 } else {
406 #ifdef LDAP_DEBUG
407 perror("select error: ");
408 #endif
409 return (-1);
412 } while (continue_on_intr == 1);
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
424 #endif /* _WINDOWS */
426 done:
427 #ifdef _WINDOWS
428 ioctlsocket(sockfd, FIONBIO, &block);
429 #else
430 fcntl(sockfd, F_SETFL, flags);
431 #endif /* _WINDOWS */
433 if (error) {
434 errno = error;
435 return (-1);
438 return (0);
442 static int
443 nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
445 int err;
446 #ifdef _WINDOWS
447 u_long iostatus;
448 #endif
450 if ( FIONBIO != option ) {
451 return( -1 );
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
461 return( err );
466 nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
467 int defport, int secure, char **krbinstancep )
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
474 int s;
476 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
477 NULL == hostlist ? "NULL" : hostlist, defport, 0 );
480 * If an extended I/O connect callback has been defined, just use it.
482 if ( NULL != ld->ld_extconnect_fn ) {
483 unsigned long connect_opts = 0;
485 if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
486 connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
488 if ( secure ) {
489 connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
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
499 #endif /* _SOLARIS_SDK */
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 );
508 if ( s < 0 ) {
509 LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
510 return( -1 );
513 sb->sb_sd = s;
516 * Set krbinstancep (canonical name of host for use by Kerberos).
518 #ifdef KERBEROS
519 char *p;
521 if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
522 && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
523 *p = '\0';
525 #else /* KERBEROS */
526 *krbinstancep = NULL;
527 #endif /* KERBEROS */
529 return( 0 );
534 * Returns a socket number if successful and -1 if an error occurs.
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 )
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 */
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;
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;
574 } else {
576 * DNS callback installed... use it.
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;
586 #else /* GETHOSTBYNAME_buf_t */
587 ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
588 ld->ld_dns_bufsize );
589 #endif /* else GETHOSTBYNAME_buf_t */
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 );
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;
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 );
612 ldap_memfree( host );
613 ldap_x_hostlist_statusfree( status );
614 return( -1 );
616 use_hp = 1;
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 );
626 ldap_memfree( host );
627 ldap_x_hostlist_statusfree( status );
628 return( -1 );
631 if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
632 int iostatus = 1;
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 );
642 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
643 sin.sin_family = AF_INET;
644 sin.sin_port = htons( (unsigned short)port );
646 SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
647 ( use_hp ? (char *) addrlist[ i ] :
648 (char *) &address ), sizeof( sin.sin_addr.s_addr) );
651 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
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
658 sigset_t ints_off, oldset;
660 sigemptyset( &ints_off );
661 sigaddset( &ints_off, SIGALRM );
662 sigaddset( &ints_off, SIGIO );
663 sigaddset( &ints_off, SIGCLD );
665 sigprocmask( SIG_BLOCK, &ints_off, &oldset );
666 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
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));
678 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
680 * restore original signal mask
682 sigprocmask( SIG_SETMASK, &oldset, 0 );
683 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
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;
705 #ifdef LDAP_DEBUG
706 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
707 perror( (char *)inet_ntoa( sin.sin_addr ));
709 #endif
710 (*closefn)( s );
711 if ( !use_hp ) {
712 break;
717 ldap_memfree( host );
718 parse_err = ldap_x_hostlist_next( &host, &port, status );
721 if ( ldhpbuf_allocd != NULL ) {
722 NSLDAPI_FREE( ldhpbuf_allocd );
724 ldap_memfree( host );
725 ldap_x_hostlist_statusfree( status );
727 if ( connected ) {
728 LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
729 s, inet_ntoa( sin.sin_addr ), 0 );
732 return( rc == 0 ? s : -1 );
736 void
737 nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
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 );
748 #ifdef KERBEROS
749 char *
750 nsldapi_host_connected_to( Sockbuf *sb )
752 struct hostent *hp;
753 char *p;
754 int len;
755 struct sockaddr_in sin;
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 );
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.
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 ));
776 return( NULL );
778 #endif /* KERBEROS */
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..
786 nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
788 NSLDAPIIOStatus *iosp;
790 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
792 if ( ld->ld_iostatus == NULL
793 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
794 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
795 return( -1 );
798 iosp = ld->ld_iostatus;
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;
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;
813 #endif /* else NSLDAPI_HAVE_POLL */
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;
821 } else {
822 LDAPDebug( LDAP_DEBUG_ANY,
823 "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
824 iosp->ios_type, 0, 0 );
827 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
829 return( 0 );
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..
838 nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
840 NSLDAPIIOStatus *iosp;
842 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
844 if ( ld->ld_iostatus == NULL
845 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
846 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
847 return( -1 );
850 iosp = ld->ld_iostatus;
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;
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;
865 #endif /* else NSLDAPI_HAVE_POLL */
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;
872 } else {
873 LDAPDebug( LDAP_DEBUG_ANY,
874 "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
875 iosp->ios_type, 0, 0 );
878 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
880 return( 0 );
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..
889 nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
891 NSLDAPIIOStatus *iosp;
893 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
895 if ( ld->ld_iostatus == NULL
896 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
897 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
898 return( -1 );
901 iosp = ld->ld_iostatus;
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;
909 if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
910 &iosp->ios_status.ios_osinfo, POLLIN )) {
911 --iosp->ios_read_count;
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;
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;
926 #endif /* else NSLDAPI_HAVE_POLL */
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;
933 if ( nsldapi_clear_from_cb_pollfds( sb,
934 &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
935 --iosp->ios_read_count;
937 } else {
938 LDAPDebug( LDAP_DEBUG_ANY,
939 "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
940 iosp->ios_type, 0, 0 );
943 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
945 return( 0 );
950 * Return a non-zero value if sb is ready for write.
953 nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
955 int rc;
956 NSLDAPIIOStatus *iosp;
958 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
959 iosp = ld->ld_iostatus;
961 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
962 #ifdef NSLDAPI_HAVE_POLL
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().
971 rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
972 &iosp->ios_status.ios_osinfo, ~POLLIN );
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 */
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 );
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;
990 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
991 return( rc );
996 * Return a non-zero value if sb is ready for read.
999 nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
1001 int rc;
1002 NSLDAPIIOStatus *iosp;
1004 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1005 iosp = ld->ld_iostatus;
1007 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1008 #ifdef NSLDAPI_HAVE_POLL
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().
1017 rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
1018 &iosp->ios_status.ios_osinfo, ~POLLOUT );
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 */
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 );
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;
1036 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1037 return( rc );
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)
1046 static int
1047 nsldapi_iostatus_init_nolock( LDAP *ld )
1049 NSLDAPIIOStatus *iosp;
1051 if ( ld->ld_iostatus != NULL ) {
1052 return( 0 );
1055 if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
1056 sizeof( NSLDAPIIOStatus ))) == NULL ) {
1057 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
1058 return( -1 );
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 */
1068 } else {
1069 iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
1072 ld->ld_iostatus = iosp;
1073 return( 0 );
1077 void
1078 nsldapi_iostatus_free( LDAP *ld )
1080 if ( ld == NULL ) {
1081 return;
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 );
1090 NSLDAPI_FREE( ld->ld_io_fns_ptr );
1093 /* clean up I/O status tracking info. */
1094 if ( ld->ld_iostatus != NULL ) {
1095 NSLDAPIIOStatus *iosp = ld->ld_iostatus;
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 );
1104 #endif /* NSLDAPI_HAVE_POLL */
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 );
1112 } else {
1113 LDAPDebug( LDAP_DEBUG_ANY,
1114 "nsldapi_iostatus_free: unknown I/O type %d\n",
1115 iosp->ios_type, 0, 0 );
1118 NSLDAPI_FREE( iosp );
1123 static int
1124 nsldapi_get_select_table_size( void )
1126 static int tblsize = 0; /* static */
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 */
1139 if ( tblsize >= FD_SETSIZE ) {
1141 * clamp value so we don't overrun the fd_set structure
1143 tblsize = FD_SETSIZE - 1;
1147 return( tblsize );
1150 static int
1151 nsldapi_tv2ms( struct timeval *tv )
1153 if ( tv == NULL ) {
1154 return( -1 ); /* infinite timout for poll() */
1157 return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
1162 nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
1164 int rc;
1165 NSLDAPIIOStatus *iosp;
1167 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
1169 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1170 iosp = ld->ld_iostatus;
1172 if ( iosp == NULL ||
1173 ( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
1174 rc = 0; /* simulate a timeout */
1176 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1177 #ifdef NSLDAPI_HAVE_POLL
1179 rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
1180 iosp->ios_status.ios_osinfo.ossi_pollfds_size,
1181 nsldapi_tv2ms( timeout ));
1183 #else /* NSLDAPI_HAVE_POLL */
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;
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 */
1204 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1206 * We always pass the session extended I/O argument to
1207 * the extended poll() callback.
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 );
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?) */
1221 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1222 return( rc );
1226 #ifdef NSLDAPI_HAVE_POLL
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.
1232 static int
1233 nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1234 short events )
1236 int i, openslot;
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 );
1250 if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
1251 openslot = i; /* remember for later */
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).
1260 if ( openslot == -1 ) {
1261 struct pollfd *newpollfds;
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 ));
1273 if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1274 return( 0 );
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;
1285 pip->ossi_pollfds[ openslot ].fd = fd;
1286 pip->ossi_pollfds[ openslot ].events = events;
1287 pip->ossi_pollfds[ openslot ].revents = 0;
1288 return( 1 );
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.
1296 static int
1297 nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1298 short events )
1300 int i;
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;
1309 return( 1 ); /* events overlap */
1310 } else {
1311 return( 0 ); /* events do not overlap */
1316 return( 0 ); /* "fd" was not found */
1321 * returns 1 if any "revents" from "fd" were set in pollfds revents field.
1322 * returns 0 if not.
1324 static int
1325 nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1326 short revents )
1328 int i;
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 */
1340 return( 0 ); /* "fd" was not found */
1342 #endif /* NSLDAPI_HAVE_POLL */
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.
1350 static int
1351 nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1352 short events )
1354 int i, openslot;
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 );
1368 if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
1369 openslot = i; /* remember for later */
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).
1378 if ( openslot == -1 ) {
1379 LDAP_X_PollFD *newpollfds;
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 ));
1391 if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1392 return( 0 );
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;
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 );
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.
1417 static int
1418 nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
1419 struct nsldapi_cb_statusinfo *pip, short events )
1421 int i;
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;
1432 return( 1 ); /* events overlap */
1433 } else {
1434 return( 0 ); /* events do not overlap */
1439 return( 0 ); /* "sb" was not found */
1444 * returns 1 if any "revents" from "sb" were set in pollfds revents field.
1445 * returns 0 if not.
1447 static int
1448 nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1449 short revents )
1451 int i;
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 */
1464 return( 0 ); /* "sb" was not found */
1469 * Install read and write functions into lber layer / sb
1472 nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
1474 struct lber_x_ext_io_fns lberiofns;
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;
1484 if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
1485 &lberiofns ) != 0 ) {
1486 return( LDAP_LOCAL_ERROR );
1490 return( LDAP_SUCCESS );
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.
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).
1507 typedef struct nsldapi_compat_socket_info {
1508 LBER_SOCKET csi_socket;
1509 LDAP *csi_ld;
1510 } NSLDAPICompatSocketInfo;
1512 static int LDAP_CALLBACK
1513 nsldapi_ext_compat_read( int s, void *buf, int len,
1514 struct lextiof_socket_private *arg )
1516 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1517 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1519 return( iofns->liof_read( csip->csi_socket, buf, len ));
1523 static int LDAP_CALLBACK
1524 nsldapi_ext_compat_write( int s, const void *buf, int len,
1525 struct lextiof_socket_private *arg )
1527 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1528 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1530 return( iofns->liof_write( csip->csi_socket, buf, len ));
1534 static int LDAP_CALLBACK
1535 nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
1536 struct lextiof_session_private *arg )
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;
1545 * Prepare fd_sets for select()
1547 FD_ZERO( &readfds );
1548 FD_ZERO( &writefds );
1549 for ( i = 0; i < nfds; ++i ) {
1550 if ( fds[ i ].lpoll_fd < 0 ) {
1551 continue;
1554 if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
1555 LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
1556 return( -1 );
1559 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
1560 FD_SET( fds[i].lpoll_fd, &readfds );
1563 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
1564 FD_SET( fds[i].lpoll_fd, &writefds );
1567 fds[i].lpoll_revents = 0; /* clear revents */
1569 if ( fds[i].lpoll_fd >= maxfd ) {
1570 maxfd = fds[i].lpoll_fd;
1575 * select() using callback.
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;
1585 rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
1586 if ( rc <= 0 ) { /* timeout or fatal error */
1587 return( rc );
1591 * Use info. in fd_sets to populate poll() revents.
1593 for ( i = 0; i < nfds; ++i ) {
1594 if ( fds[ i ].lpoll_fd < 0 ) {
1595 continue;
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;
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;
1608 /* XXXmcs: any other cases to deal with? LDAP_X_POLLERR? */
1611 return( rc );
1615 static LBER_SOCKET
1616 nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
1617 int protocol )
1619 int s;
1621 s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
1623 if ( s >= 0 ) {
1624 char *errmsg = NULL;
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");
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";
1636 #endif
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");
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 );
1650 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
1651 nsldapi_strdup( errmsg ));
1652 return( -1 );
1656 return( s );
1661 * Note: timeout is ignored because we have no way to pass it via
1662 * the old I/O callback interface.
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
1672 #endif /* _SOLARIS_SDK */
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;
1683 defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
1684 iofns = defcsip->csi_ld->ld_io_fns_ptr;
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 );
1691 secure = 1;
1692 } else {
1693 secure = 0;
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;
1707 closefn = ( iofns->liof_close == NULL ) ?
1708 nsldapi_os_closesocket : iofns->liof_close;
1710 s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
1711 secure, socketfn, ioctlfn, connectwithtofn,
1712 connectfn, closefn );
1714 if ( s >= 0 ) {
1715 NSLDAPICompatSocketInfo *csip;
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 );
1725 csip->csi_socket = s;
1726 csip->csi_ld = defcsip->csi_ld;
1727 *socketargp = (void *)csip;
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.
1737 s = 1;
1740 return( s );
1744 static int LDAP_CALLBACK
1745 nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
1747 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1748 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1749 int rc;
1751 rc = iofns->liof_close( csip->csi_socket );
1753 NSLDAPI_FREE( csip );
1755 return( rc );
1759 * Install the I/O functions.
1760 * Return an LDAP error code (LDAP_SUCCESS if all goes well).
1763 nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
1765 NSLDAPICompatSocketInfo *defcsip;
1767 if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
1768 sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
1769 return( LDAP_NO_MEMORY );
1772 defcsip->csi_socket = -1;
1773 defcsip->csi_ld = ld;
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 );
1784 /* struct copy */
1785 *(ld->ld_io_fns_ptr) = *iofns;
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;
1795 return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
1798 * end of compat I/O functions
1799 ******************************************************************************
1801 #ifdef _SOLARIS_SDK
1803 * _ns_gethostbyaddr is a helper function for the ssl layer so that
1804 * it can use the ldap layer's gethostbyaddr resolver.
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)
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));
1818 #endif /* _SOLARIS_SDK */