dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / os-ip.c
blob61ab25caf595699461bd440c17a37e21c41fa80c
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 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
37 #endif
39 #include "ldap-int.h"
40 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
41 #include <signal.h>
42 #endif
44 #ifdef NSLDAPI_HAVE_POLL
45 #include <poll.h>
46 #endif
49 #ifdef _WINDOWS
50 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) == INVALID_SOCKET)
51 #else
52 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) < 0 )
53 #endif
56 #define NSLDAPI_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
60 * Structures and union for tracking status of network sockets
62 #ifdef NSLDAPI_HAVE_POLL
63 struct nsldapi_os_statusinfo { /* used with native OS poll() */
64 struct pollfd *ossi_pollfds;
65 int ossi_pollfds_size;
67 #else /* NSLDAPI_HAVE_POLL */
68 struct nsldapi_os_statusinfo { /* used with native OS select() */
69 fd_set ossi_readfds;
70 fd_set ossi_writefds;
71 fd_set ossi_use_readfds;
72 fd_set ossi_use_writefds;
74 #endif /* else NSLDAPI_HAVE_POLL */
76 struct nsldapi_cb_statusinfo { /* used with ext. I/O poll() callback */
77 LDAP_X_PollFD *cbsi_pollfds;
78 int cbsi_pollfds_size;
82 * NSLDAPI_CB_POLL_MATCH() evaluates to non-zero (true) if the Sockbuf *sdp
83 * matches the LDAP_X_PollFD pollfd.
85 #ifdef _WINDOWS
86 #define NSLDAPI_CB_POLL_SD_CAST (unsigned int)
87 #else
88 #define NSLDAPI_CB_POLL_SD_CAST
89 #endif
90 #if defined(LDAP_SASLIO_HOOKS)
91 #define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
92 ( ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd)) && \
93 (((sbp)->sb_sasl_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) || \
94 ((sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg) ) )
95 #else
96 #define NSLDAPI_CB_POLL_MATCH( sbp, pollfd ) \
97 ((sbp)->sb_sd == NSLDAPI_CB_POLL_SD_CAST ((pollfd).lpoll_fd) && \
98 (sbp)->sb_ext_io_fns.lbextiofn_socket_arg == (pollfd).lpoll_socketarg)
99 #endif
102 struct nsldapi_iostatus_info {
103 int ios_type;
104 #define NSLDAPI_IOSTATUS_TYPE_OSNATIVE 1 /* poll() or select() */
105 #define NSLDAPI_IOSTATUS_TYPE_CALLBACK 2 /* poll()-like */
106 int ios_read_count;
107 int ios_write_count;
108 union {
109 struct nsldapi_os_statusinfo ios_osinfo;
110 struct nsldapi_cb_statusinfo ios_cbinfo;
111 } ios_status;
115 #ifdef NSLDAPI_HAVE_POLL
116 static int nsldapi_add_to_os_pollfds( int fd,
117 struct nsldapi_os_statusinfo *pip, short events );
118 static int nsldapi_clear_from_os_pollfds( int fd,
119 struct nsldapi_os_statusinfo *pip, short events );
120 static int nsldapi_find_in_os_pollfds( int fd,
121 struct nsldapi_os_statusinfo *pip, short revents );
122 #endif /* NSLDAPI_HAVE_POLL */
124 static int nsldapi_iostatus_init_nolock( LDAP *ld );
125 static int nsldapi_add_to_cb_pollfds( Sockbuf *sb,
126 struct nsldapi_cb_statusinfo *pip, short events );
127 static int nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
128 struct nsldapi_cb_statusinfo *pip, short events );
129 static int nsldapi_find_in_cb_pollfds( Sockbuf *sb,
130 struct nsldapi_cb_statusinfo *pip, short revents );
133 #ifdef irix
134 #ifndef _PR_THREADS
136 * XXXmcs: on IRIX NSPR's poll() and select() wrappers will crash if NSPR
137 * has not been initialized. We work around the problem by bypassing
138 * the NSPR wrapper functions and going directly to the OS' functions.
140 #define NSLDAPI_POLL _poll
141 #define NSLDAPI_SELECT _select
142 extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
143 extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
144 fd_set *exceptfds, struct timeval *timeout);
145 #else /* _PR_THREADS */
146 #define NSLDAPI_POLL poll
147 #define NSLDAPI_SELECT select
148 #endif /* else _PR_THREADS */
149 #else /* irix */
150 #define NSLDAPI_POLL poll
151 #define NSLDAPI_SELECT select
152 #endif /* else irix */
155 static LBER_SOCKET nsldapi_os_socket( LDAP *ld, int secure, int domain,
156 int type, int protocol );
157 static int nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp );
158 static int nsldapi_os_connect_with_to( LBER_SOCKET s, struct sockaddr *name,
159 int namelen, LDAP *ld);
162 * Function typedefs used by nsldapi_try_each_host()
164 typedef LBER_SOCKET (NSLDAPI_SOCKET_FN)( LDAP *ld, int secure, int domain,
165 int type, int protocol );
166 typedef int (NSLDAPI_IOCTL_FN)( LBER_SOCKET s, int option, int *statusp );
167 typedef int (NSLDAPI_CONNECT_WITH_TO_FN )( LBER_SOCKET s, struct sockaddr *name,
168 int namelen, LDAP *ld);
169 typedef int (NSLDAPI_CONNECT_FN )( LBER_SOCKET s, struct sockaddr *name,
170 int namelen );
171 typedef int (NSLDAPI_CLOSE_FN )( LBER_SOCKET s );
173 static int nsldapi_try_each_host( LDAP *ld, const char *hostlist, int defport,
174 int secure, NSLDAPI_SOCKET_FN *socketfn, NSLDAPI_IOCTL_FN *ioctlfn,
175 NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
176 NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn );
179 static int
180 nsldapi_os_closesocket( LBER_SOCKET s )
182 int rc;
184 #ifdef _WINDOWS
185 rc = closesocket( s );
186 #else
187 rc = close( s );
188 #endif
189 return( rc );
193 static LBER_SOCKET
194 nsldapi_os_socket( LDAP *ld, int secure, int domain, int type, int protocol )
196 int s, invalid_socket;
197 char *errmsg = NULL;
199 if ( secure ) {
200 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
201 nsldapi_strdup( dgettext(TEXT_DOMAIN,
202 "secure mode not supported") ));
203 return( -1 );
206 s = socket( domain, type, protocol );
209 * if the socket() call failed or it returned a socket larger
210 * than we can deal with, return a "local error."
212 if ( NSLDAPI_INVALID_OS_SOCKET( s )) {
213 errmsg = dgettext(TEXT_DOMAIN, "unable to create a socket");
214 invalid_socket = 1;
215 } else { /* valid socket -- check for overflow */
216 invalid_socket = 0;
217 #if !defined(NSLDAPI_HAVE_POLL) && !defined(_WINDOWS)
218 /* not on Windows and do not have poll() */
219 if ( s >= FD_SETSIZE ) {
220 errmsg = "can't use socket >= FD_SETSIZE";
222 #endif
225 if ( errmsg != NULL ) { /* local socket error */
226 if ( !invalid_socket ) {
227 nsldapi_os_closesocket( s );
229 errmsg = nsldapi_strdup( errmsg );
230 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, errmsg );
231 return( -1 );
234 return( s );
240 * Non-blocking connect call function
242 static int
243 nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
244 int salen, LDAP *ld)
246 #ifndef _WINDOWS
247 int flags;
248 #endif /* _WINDOWS */
249 int n, error;
250 socklen_t len;
251 fd_set rset, wset;
252 struct timeval tval;
253 #ifdef _WINDOWS
254 int nonblock = 1;
255 int block = 0;
256 fd_set eset;
257 #endif /* _WINDOWS */
258 int msec = ld->ld_connect_timeout; /* milliseconds */
259 int continue_on_intr = 0;
260 #ifdef _SOLARIS_SDK
261 hrtime_t start_time = 0, tmp_time, tv_time; /* nanoseconds */
262 #else
263 long start_time = 0, tmp_time; /* seconds */
264 #endif
267 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_nonblock timeout: %d (msec)\n",
268 msec, 0, 0);
270 #ifdef _WINDOWS
271 ioctlsocket(sockfd, FIONBIO, &nonblock);
272 #else
273 flags = fcntl(sockfd, F_GETFL, 0);
274 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
275 #endif /* _WINDOWS */
277 error = 0;
278 if ((n = connect(sockfd, saptr, salen)) < 0)
279 #ifdef _WINDOWS
280 if ((n != SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK)) {
281 #else
282 if (errno != EINPROGRESS) {
283 #endif /* _WINDOWS */
284 #ifdef LDAP_DEBUG
285 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
286 perror("connect");
288 #endif
289 return (-1);
292 /* success */
293 if (n == 0)
294 goto done;
296 FD_ZERO(&rset);
297 FD_SET(sockfd, &rset);
298 wset = rset;
300 #ifdef _WINDOWS
301 eset = rset;
302 #endif /* _WINDOWS */
304 if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
305 LDAPDebug( LDAP_DEBUG_TRACE, "Invalid timeout value detected.."
306 "resetting connect timeout to default value "
307 "(LDAP_X_IO_TIMEOUT_NO_TIMEOUT\n", 0, 0, 0);
308 msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
309 } else {
310 if (msec != 0) {
311 tval.tv_sec = msec / MILLISEC;
312 tval.tv_usec = (MICROSEC / MILLISEC) *
313 (msec % MILLISEC);
314 #ifdef _SOLARIS_SDK
315 start_time = gethrtime();
316 tv_time = MSEC2NSEC(msec);
317 #else
318 start_time = (long)time(NULL);
319 #endif
320 } else {
321 tval.tv_sec = 0;
322 tval.tv_usec = 0;
326 /* if timeval structure == NULL, select will block indefinitely */
327 /* != NULL, and value == 0, select will */
328 /* not block */
329 /* Windows is a bit quirky on how it behaves w.r.t nonblocking */
330 /* connects. If the connect fails, the exception fd, eset, is */
331 /* set to show the failure. The first argument in select is */
332 /* ignored */
334 #ifdef _WINDOWS
335 if ((n = select(sockfd +1, &rset, &wset, &eset,
336 (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
337 errno = WSAETIMEDOUT;
338 return (-1);
340 /* if wset is set, the connect worked */
341 if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
342 len = sizeof(error);
343 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
344 < 0)
345 return (-1);
346 goto done;
349 /* if eset is set, the connect failed */
350 if (FD_ISSET(sockfd, &eset)) {
351 return (-1);
354 /* failure on select call */
355 if (n == SOCKET_ERROR) {
356 perror("select error: SOCKET_ERROR returned");
357 return (-1);
359 #else
361 * if LDAP_BITOPT_RESTART and select() is interrupted
362 * try again.
364 do {
365 continue_on_intr = 0;
366 if ((n = select(sockfd +1, &rset, &wset, NULL,
367 (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? \
368 &tval : NULL)) == 0) {
369 errno = ETIMEDOUT;
370 return (-1);
372 if (n < 0) {
373 if ((ld->ld_options & LDAP_BITOPT_RESTART) &&
374 (errno == EINTR)) {
375 continue_on_intr = 1;
376 errno = 0;
377 FD_ZERO(&rset);
378 FD_SET(sockfd, &rset);
379 wset = rset;
380 /* honour the timeout */
381 if ((msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) &&
382 (msec != 0)) {
383 #ifdef _SOLARIS_SDK
384 tmp_time = gethrtime();
385 if ((tv_time -=
386 (tmp_time - start_time)) <= 0) {
387 #else
388 tmp_time = (long)time(NULL);
389 if ((tval.tv_sec -=
390 (tmp_time - start_time)) <= 0) {
391 #endif
392 /* timeout */
393 errno = ETIMEDOUT;
394 return (-1);
396 #ifdef _SOLARIS_SDK
397 tval.tv_sec = tv_time / NANOSEC;
398 tval.tv_usec = (tv_time % NANOSEC) /
399 (NANOSEC / MICROSEC);
400 #endif
401 start_time = tmp_time;
403 } else {
404 #ifdef LDAP_DEBUG
405 perror("select error: ");
406 #endif
407 return (-1);
410 } while (continue_on_intr == 1);
412 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
413 len = sizeof(error);
414 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
415 < 0)
416 return (-1);
417 #ifdef LDAP_DEBUG
418 } else if ( ldap_debug & LDAP_DEBUG_TRACE ) {
419 perror("select error: sockfd not set");
420 #endif
422 #endif /* _WINDOWS */
424 done:
425 #ifdef _WINDOWS
426 ioctlsocket(sockfd, FIONBIO, &block);
427 #else
428 fcntl(sockfd, F_SETFL, flags);
429 #endif /* _WINDOWS */
431 if (error) {
432 errno = error;
433 return (-1);
436 return (0);
440 static int
441 nsldapi_os_ioctl( LBER_SOCKET s, int option, int *statusp )
443 int err;
444 #ifdef _WINDOWS
445 u_long iostatus;
446 #endif
448 if ( FIONBIO != option ) {
449 return( -1 );
452 #ifdef _WINDOWS
453 iostatus = *(u_long *)statusp;
454 err = ioctlsocket( s, FIONBIO, &iostatus );
455 #else
456 err = ioctl( s, FIONBIO, (caddr_t)statusp );
457 #endif
459 return( err );
464 nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, const char *hostlist,
465 int defport, int secure, char **krbinstancep )
467 * "defport" must be in host byte order
468 * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
469 * if -1 is returned, ld_errno is set
472 int s;
474 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_connect_to_host: %s, port: %d\n",
475 NULL == hostlist ? "NULL" : hostlist, defport, 0 );
478 * If an extended I/O connect callback has been defined, just use it.
480 if ( NULL != ld->ld_extconnect_fn ) {
481 unsigned long connect_opts = 0;
483 if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
484 connect_opts |= LDAP_X_EXTIOF_OPT_NONBLOCKING;
486 if ( secure ) {
487 connect_opts |= LDAP_X_EXTIOF_OPT_SECURE;
489 s = ld->ld_extconnect_fn( hostlist, defport,
490 ld->ld_connect_timeout, connect_opts,
491 ld->ld_ext_session_arg,
492 &sb->sb_ext_io_fns.lbextiofn_socket_arg
493 #ifdef _SOLARIS_SDK
494 , NULL );
495 #else
497 #endif /* _SOLARIS_SDK */
499 } else {
500 s = nsldapi_try_each_host( ld, hostlist,
501 defport, secure, nsldapi_os_socket,
502 nsldapi_os_ioctl, nsldapi_os_connect_with_to,
503 NULL, nsldapi_os_closesocket );
506 if ( s < 0 ) {
507 LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
508 return( -1 );
511 sb->sb_sd = s;
514 * Set krbinstancep (canonical name of host for use by Kerberos).
516 #ifdef KERBEROS
517 char *p;
519 if (( *krbinstancep = nsldapi_host_connected_to( sb )) != NULL
520 && ( p = strchr( *krbinstancep, '.' )) != NULL ) {
521 *p = '\0';
523 #else /* KERBEROS */
524 *krbinstancep = NULL;
525 #endif /* KERBEROS */
527 return( 0 );
532 * Returns a socket number if successful and -1 if an error occurs.
534 static int
535 nsldapi_try_each_host( LDAP *ld, const char *hostlist,
536 int defport, int secure, NSLDAPI_SOCKET_FN *socketfn,
537 NSLDAPI_IOCTL_FN *ioctlfn, NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn,
538 NSLDAPI_CONNECT_FN *connectfn, NSLDAPI_CLOSE_FN *closefn )
540 int rc, i, s, err, connected, use_hp;
541 int parse_err, port;
542 struct sockaddr_in sin;
543 nsldapi_in_addr_t address;
544 char **addrlist, *ldhpbuf, *ldhpbuf_allocd;
545 char *host;
546 LDAPHostEnt ldhent, *ldhp;
547 struct hostent *hp;
548 struct ldap_x_hostlist_status *status;
549 #ifdef GETHOSTBYNAME_BUF_T
550 GETHOSTBYNAME_BUF_T hbuf;
551 struct hostent hent;
552 #endif /* GETHOSTBYNAME_BUF_T */
554 connected = 0;
555 parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
556 &status );
557 while ( !connected && LDAP_SUCCESS == parse_err && host != NULL ) {
558 ldhpbuf_allocd = NULL;
559 ldhp = NULL;
560 hp = NULL;
561 s = 0;
562 use_hp = 0;
563 addrlist = NULL;
566 if (( address = inet_addr( host )) == -1 ) {
567 if ( ld->ld_dns_gethostbyname_fn == NULL ) {
568 if (( hp = GETHOSTBYNAME( host, &hent, hbuf,
569 sizeof(hbuf), &err )) != NULL ) {
570 addrlist = hp->h_addr_list;
572 } else {
574 * DNS callback installed... use it.
576 #ifdef GETHOSTBYNAME_buf_t
577 /* avoid allocation by using hbuf if large enough */
578 if ( sizeof( hbuf ) < ld->ld_dns_bufsize ) {
579 ldhpbuf = ldhpbuf_allocd
580 = NSLDAPI_MALLOC( ld->ld_dns_bufsize );
581 } else {
582 ldhpbuf = (char *)hbuf;
584 #else /* GETHOSTBYNAME_buf_t */
585 ldhpbuf = ldhpbuf_allocd = NSLDAPI_MALLOC(
586 ld->ld_dns_bufsize );
587 #endif /* else GETHOSTBYNAME_buf_t */
589 if ( ldhpbuf == NULL ) {
590 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY,
591 NULL, NULL );
592 ldap_memfree( host );
593 ldap_x_hostlist_statusfree( status );
594 return( -1 );
597 if (( ldhp = ld->ld_dns_gethostbyname_fn( host,
598 &ldhent, ldhpbuf, ld->ld_dns_bufsize, &err,
599 ld->ld_dns_extradata )) != NULL ) {
600 addrlist = ldhp->ldaphe_addr_list;
604 if ( addrlist == NULL ) {
605 LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
606 LDAP_SET_ERRNO( ld, EHOSTUNREACH ); /* close enough */
607 if ( ldhpbuf_allocd != NULL ) {
608 NSLDAPI_FREE( ldhpbuf_allocd );
610 ldap_memfree( host );
611 ldap_x_hostlist_statusfree( status );
612 return( -1 );
614 use_hp = 1;
617 rc = -1;
618 for ( i = 0; !use_hp || ( addrlist[ i ] != 0 ); i++ ) {
619 if ( -1 == ( s = (*socketfn)( ld, secure, AF_INET,
620 SOCK_STREAM, 0 ))) {
621 if ( ldhpbuf_allocd != NULL ) {
622 NSLDAPI_FREE( ldhpbuf_allocd );
624 ldap_memfree( host );
625 ldap_x_hostlist_statusfree( status );
626 return( -1 );
629 if ( ld->ld_options & LDAP_BITOPT_ASYNC ) {
630 int iostatus = 1;
632 err = (*ioctlfn)( s, FIONBIO, &iostatus );
633 if ( err == -1 ) {
634 LDAPDebug( LDAP_DEBUG_ANY,
635 "FIONBIO ioctl failed on %d\n",
636 s, 0, 0 );
640 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
641 sin.sin_family = AF_INET;
642 sin.sin_port = htons( (unsigned short)port );
644 SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
645 ( use_hp ? (char *) addrlist[ i ] :
646 (char *) &address ), sizeof( sin.sin_addr.s_addr) );
649 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
651 * Block all of the signals that might interrupt connect() since there
652 * is an OS bug that causes connect() to fail if it is restarted. Look in
653 * ns/netsite/ldap/include/portable.h for the definition of
654 * LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
656 sigset_t ints_off, oldset;
658 sigemptyset( &ints_off );
659 sigaddset( &ints_off, SIGALRM );
660 sigaddset( &ints_off, SIGIO );
661 sigaddset( &ints_off, SIGCLD );
663 sigprocmask( SIG_BLOCK, &ints_off, &oldset );
664 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
666 if ( NULL != connectwithtofn ) {
667 err = (*connectwithtofn)(s,
668 (struct sockaddr *)&sin,
669 sizeof(struct sockaddr_in),
670 ld);
671 } else {
672 err = (*connectfn)(s,
673 (struct sockaddr *)&sin,
674 sizeof(struct sockaddr_in));
676 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
678 * restore original signal mask
680 sigprocmask( SIG_SETMASK, &oldset, 0 );
681 #endif /* LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED */
684 if ( err >= 0 ) {
685 connected = 1;
686 rc = 0;
687 break;
688 } else {
689 if ( ld->ld_options & LDAP_BITOPT_ASYNC) {
690 #ifdef _WINDOWS
691 if (err == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
692 LDAP_SET_ERRNO( ld, EWOULDBLOCK );
693 #endif /* _WINDOWS */
694 err = LDAP_GET_ERRNO( ld );
695 if ( NSLDAPI_ERRNO_IO_INPROGRESS( err )) {
696 LDAPDebug( LDAP_DEBUG_TRACE, "connect would block...\n",
697 0, 0, 0 );
698 rc = -2;
699 break;
703 #ifdef LDAP_DEBUG
704 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
705 perror( (char *)inet_ntoa( sin.sin_addr ));
707 #endif
708 (*closefn)( s );
709 if ( !use_hp ) {
710 break;
715 ldap_memfree( host );
716 parse_err = ldap_x_hostlist_next( &host, &port, status );
719 if ( ldhpbuf_allocd != NULL ) {
720 NSLDAPI_FREE( ldhpbuf_allocd );
722 ldap_memfree( host );
723 ldap_x_hostlist_statusfree( status );
725 if ( connected ) {
726 LDAPDebug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
727 s, inet_ntoa( sin.sin_addr ), 0 );
730 return( rc == 0 ? s : -1 );
734 void
735 nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
737 if ( ld->ld_extclose_fn == NULL ) {
738 nsldapi_os_closesocket( sb->sb_sd );
739 } else {
740 ld->ld_extclose_fn( sb->sb_sd,
741 sb->sb_ext_io_fns.lbextiofn_socket_arg );
746 #ifdef KERBEROS
747 char *
748 nsldapi_host_connected_to( Sockbuf *sb )
750 struct hostent *hp;
751 char *p;
752 int len;
753 struct sockaddr_in sin;
755 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
756 len = sizeof( sin );
757 if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
758 return( NULL );
762 * do a reverse lookup on the addr to get the official hostname.
763 * this is necessary for kerberos to work right, since the official
764 * hostname is used as the kerberos instance.
766 #error XXXmcs: need to use DNS callbacks here
767 if (( hp = gethostbyaddr((char *) &sin.sin_addr,
768 sizeof( sin.sin_addr ), AF_INET)) != NULL ) {
769 if ( hp->h_name != NULL ) {
770 return( nsldapi_strdup( hp->h_name ));
774 return( NULL );
776 #endif /* KERBEROS */
780 * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
781 * Also allocates initializes ld->ld_iostatus if needed..
784 nsldapi_iostatus_interest_write( LDAP *ld, Sockbuf *sb )
786 NSLDAPIIOStatus *iosp;
788 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
790 if ( ld->ld_iostatus == NULL
791 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
792 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
793 return( -1 );
796 iosp = ld->ld_iostatus;
798 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
799 #ifdef NSLDAPI_HAVE_POLL
800 if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
801 &iosp->ios_status.ios_osinfo, POLLOUT )) {
802 ++iosp->ios_write_count;
804 #else /* NSLDAPI_HAVE_POLL */
805 if ( !FD_ISSET( sb->sb_sd,
806 &iosp->ios_status.ios_osinfo.ossi_writefds )) {
807 FD_SET( sb->sb_sd,
808 &iosp->ios_status.ios_osinfo.ossi_writefds );
809 ++iosp->ios_write_count;
811 #endif /* else NSLDAPI_HAVE_POLL */
813 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
814 if ( nsldapi_add_to_cb_pollfds( sb,
815 &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
816 ++iosp->ios_write_count;
819 } else {
820 LDAPDebug( LDAP_DEBUG_ANY,
821 "nsldapi_iostatus_interest_write: unknown I/O type %d\n",
822 iosp->ios_type, 0, 0 );
825 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
827 return( 0 );
832 * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
833 * Also allocates initializes ld->ld_iostatus if needed..
836 nsldapi_iostatus_interest_read( LDAP *ld, Sockbuf *sb )
838 NSLDAPIIOStatus *iosp;
840 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
842 if ( ld->ld_iostatus == NULL
843 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
844 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
845 return( -1 );
848 iosp = ld->ld_iostatus;
850 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
851 #ifdef NSLDAPI_HAVE_POLL
852 if ( nsldapi_add_to_os_pollfds( sb->sb_sd,
853 &iosp->ios_status.ios_osinfo, POLLIN )) {
854 ++iosp->ios_read_count;
856 #else /* NSLDAPI_HAVE_POLL */
857 if ( !FD_ISSET( sb->sb_sd,
858 &iosp->ios_status.ios_osinfo.ossi_readfds )) {
859 FD_SET( sb->sb_sd,
860 &iosp->ios_status.ios_osinfo.ossi_readfds );
861 ++iosp->ios_read_count;
863 #endif /* else NSLDAPI_HAVE_POLL */
865 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
866 if ( nsldapi_add_to_cb_pollfds( sb,
867 &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
868 ++iosp->ios_read_count;
870 } else {
871 LDAPDebug( LDAP_DEBUG_ANY,
872 "nsldapi_iostatus_interest_read: unknown I/O type %d\n",
873 iosp->ios_type, 0, 0 );
876 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
878 return( 0 );
883 * Returns 0 if all goes well and -1 if an error occurs (error code set in ld)
884 * Also allocates initializes ld->ld_iostatus if needed..
887 nsldapi_iostatus_interest_clear( LDAP *ld, Sockbuf *sb )
889 NSLDAPIIOStatus *iosp;
891 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
893 if ( ld->ld_iostatus == NULL
894 && nsldapi_iostatus_init_nolock( ld ) < 0 ) {
895 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
896 return( -1 );
899 iosp = ld->ld_iostatus;
901 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
902 #ifdef NSLDAPI_HAVE_POLL
903 if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
904 &iosp->ios_status.ios_osinfo, POLLOUT )) {
905 --iosp->ios_write_count;
907 if ( nsldapi_clear_from_os_pollfds( sb->sb_sd,
908 &iosp->ios_status.ios_osinfo, POLLIN )) {
909 --iosp->ios_read_count;
911 #else /* NSLDAPI_HAVE_POLL */
912 if ( FD_ISSET( sb->sb_sd,
913 &iosp->ios_status.ios_osinfo.ossi_writefds )) {
914 FD_CLR( sb->sb_sd,
915 &iosp->ios_status.ios_osinfo.ossi_writefds );
916 --iosp->ios_write_count;
918 if ( FD_ISSET( sb->sb_sd,
919 &iosp->ios_status.ios_osinfo.ossi_readfds )) {
920 FD_CLR( sb->sb_sd,
921 &iosp->ios_status.ios_osinfo.ossi_readfds );
922 --iosp->ios_read_count;
924 #endif /* else NSLDAPI_HAVE_POLL */
926 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
927 if ( nsldapi_clear_from_cb_pollfds( sb,
928 &iosp->ios_status.ios_cbinfo, LDAP_X_POLLOUT )) {
929 --iosp->ios_write_count;
931 if ( nsldapi_clear_from_cb_pollfds( sb,
932 &iosp->ios_status.ios_cbinfo, LDAP_X_POLLIN )) {
933 --iosp->ios_read_count;
935 } else {
936 LDAPDebug( LDAP_DEBUG_ANY,
937 "nsldapi_iostatus_interest_clear: unknown I/O type %d\n",
938 iosp->ios_type, 0, 0 );
941 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
943 return( 0 );
948 * Return a non-zero value if sb is ready for write.
951 nsldapi_iostatus_is_write_ready( LDAP *ld, Sockbuf *sb )
953 int rc;
954 NSLDAPIIOStatus *iosp;
956 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
957 iosp = ld->ld_iostatus;
959 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
960 #ifdef NSLDAPI_HAVE_POLL
962 * if we are using poll() we do something a little tricky: if
963 * any bits in the socket's returned events field other than
964 * POLLIN (ready for read) are set, we return true. This
965 * is done so we notice when a server closes a connection
966 * or when another error occurs. The actual error will be
967 * noticed later when we call write() or send().
969 rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
970 &iosp->ios_status.ios_osinfo, ~POLLIN );
972 #else /* NSLDAPI_HAVE_POLL */
973 rc = FD_ISSET( sb->sb_sd,
974 &iosp->ios_status.ios_osinfo.ossi_use_writefds );
975 #endif /* else NSLDAPI_HAVE_POLL */
977 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
978 rc = nsldapi_find_in_cb_pollfds( sb,
979 &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLIN );
981 } else {
982 LDAPDebug( LDAP_DEBUG_ANY,
983 "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
984 iosp->ios_type, 0, 0 );
985 rc = 0;
988 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
989 return( rc );
994 * Return a non-zero value if sb is ready for read.
997 nsldapi_iostatus_is_read_ready( LDAP *ld, Sockbuf *sb )
999 int rc;
1000 NSLDAPIIOStatus *iosp;
1002 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1003 iosp = ld->ld_iostatus;
1005 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1006 #ifdef NSLDAPI_HAVE_POLL
1008 * if we are using poll() we do something a little tricky: if
1009 * any bits in the socket's returned events field other than
1010 * POLLOUT (ready for write) are set, we return true. This
1011 * is done so we notice when a server closes a connection
1012 * or when another error occurs. The actual error will be
1013 * noticed later when we call read() or recv().
1015 rc = nsldapi_find_in_os_pollfds( sb->sb_sd,
1016 &iosp->ios_status.ios_osinfo, ~POLLOUT );
1018 #else /* NSLDAPI_HAVE_POLL */
1019 rc = FD_ISSET( sb->sb_sd,
1020 &iosp->ios_status.ios_osinfo.ossi_use_readfds );
1021 #endif /* else NSLDAPI_HAVE_POLL */
1023 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1024 rc = nsldapi_find_in_cb_pollfds( sb,
1025 &iosp->ios_status.ios_cbinfo, ~LDAP_X_POLLOUT );
1027 } else {
1028 LDAPDebug( LDAP_DEBUG_ANY,
1029 "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
1030 iosp->ios_type, 0, 0 );
1031 rc = 0;
1034 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1035 return( rc );
1040 * Allocated and initialize ld->ld_iostatus if not already done.
1041 * Should be called with LDAP_IOSTATUS_LOCK locked.
1042 * Returns 0 if all goes well and -1 if not (sets error in ld)
1044 static int
1045 nsldapi_iostatus_init_nolock( LDAP *ld )
1047 NSLDAPIIOStatus *iosp;
1049 if ( ld->ld_iostatus != NULL ) {
1050 return( 0 );
1053 if (( iosp = (NSLDAPIIOStatus *)NSLDAPI_CALLOC( 1,
1054 sizeof( NSLDAPIIOStatus ))) == NULL ) {
1055 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
1056 return( -1 );
1059 if ( ld->ld_extpoll_fn == NULL ) {
1060 iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_OSNATIVE;
1061 #ifndef NSLDAPI_HAVE_POLL
1062 FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_readfds );
1063 FD_ZERO( &iosp->ios_status.ios_osinfo.ossi_writefds );
1064 #endif /* !NSLDAPI_HAVE_POLL */
1066 } else {
1067 iosp->ios_type = NSLDAPI_IOSTATUS_TYPE_CALLBACK;
1070 ld->ld_iostatus = iosp;
1071 return( 0 );
1075 void
1076 nsldapi_iostatus_free( LDAP *ld )
1078 if ( ld == NULL ) {
1079 return;
1083 /* clean up classic I/O compatibility glue */
1084 if ( ld->ld_io_fns_ptr != NULL ) {
1085 if ( ld->ld_ext_session_arg != NULL ) {
1086 NSLDAPI_FREE( ld->ld_ext_session_arg );
1088 NSLDAPI_FREE( ld->ld_io_fns_ptr );
1091 /* clean up I/O status tracking info. */
1092 if ( ld->ld_iostatus != NULL ) {
1093 NSLDAPIIOStatus *iosp = ld->ld_iostatus;
1095 if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1096 #ifdef NSLDAPI_HAVE_POLL
1097 if ( iosp->ios_status.ios_osinfo.ossi_pollfds
1098 != NULL ) {
1099 NSLDAPI_FREE(
1100 iosp->ios_status.ios_osinfo.ossi_pollfds );
1102 #endif /* NSLDAPI_HAVE_POLL */
1104 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1105 if ( iosp->ios_status.ios_cbinfo.cbsi_pollfds
1106 != NULL ) {
1107 NSLDAPI_FREE(
1108 iosp->ios_status.ios_cbinfo.cbsi_pollfds );
1110 } else {
1111 LDAPDebug( LDAP_DEBUG_ANY,
1112 "nsldapi_iostatus_free: unknown I/O type %d\n",
1113 iosp->ios_type, 0, 0 );
1116 NSLDAPI_FREE( iosp );
1121 static int
1122 nsldapi_get_select_table_size( void )
1124 static int tblsize = 0; /* static */
1126 if ( tblsize == 0 ) {
1127 #if defined(_WINDOWS) || defined(XP_OS2)
1128 tblsize = FOPEN_MAX; /* ANSI spec. */
1129 #else
1130 #ifdef USE_SYSCONF
1131 tblsize = sysconf( _SC_OPEN_MAX );
1132 #else /* USE_SYSCONF */
1133 tblsize = getdtablesize();
1134 #endif /* else USE_SYSCONF */
1135 #endif /* else _WINDOWS */
1137 if ( tblsize >= FD_SETSIZE ) {
1139 * clamp value so we don't overrun the fd_set structure
1141 tblsize = FD_SETSIZE - 1;
1145 return( tblsize );
1148 static int
1149 nsldapi_tv2ms( struct timeval *tv )
1151 if ( tv == NULL ) {
1152 return( -1 ); /* infinite timout for poll() */
1155 return( tv->tv_sec * 1000 + tv->tv_usec / 1000 );
1160 nsldapi_iostatus_poll( LDAP *ld, struct timeval *timeout )
1162 int rc;
1163 NSLDAPIIOStatus *iosp;
1165 LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_iostatus_poll\n", 0, 0, 0 );
1167 LDAP_MUTEX_LOCK( ld, LDAP_IOSTATUS_LOCK );
1168 iosp = ld->ld_iostatus;
1170 if ( iosp == NULL ||
1171 ( iosp->ios_read_count <= 0 && iosp->ios_read_count <= 0 )) {
1172 rc = 0; /* simulate a timeout */
1174 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_OSNATIVE ) {
1175 #ifdef NSLDAPI_HAVE_POLL
1177 rc = NSLDAPI_POLL( iosp->ios_status.ios_osinfo.ossi_pollfds,
1178 iosp->ios_status.ios_osinfo.ossi_pollfds_size,
1179 nsldapi_tv2ms( timeout ));
1181 #else /* NSLDAPI_HAVE_POLL */
1183 /* two (potentially large) struct copies */
1184 iosp->ios_status.ios_osinfo.ossi_use_readfds
1185 = iosp->ios_status.ios_osinfo.ossi_readfds;
1186 iosp->ios_status.ios_osinfo.ossi_use_writefds
1187 = iosp->ios_status.ios_osinfo.ossi_writefds;
1189 #ifdef HPUX9
1190 rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
1191 (int *)&iosp->ios_status.ios_osinfo.ossi_use_readfds
1192 (int *)&iosp->ios_status.ios_osinfo.ossi_use_writefds,
1193 NULL, timeout );
1194 #else
1195 rc = NSLDAPI_SELECT( nsldapi_get_select_table_size(),
1196 &iosp->ios_status.ios_osinfo.ossi_use_readfds,
1197 &iosp->ios_status.ios_osinfo.ossi_use_writefds,
1198 NULL, timeout );
1199 #endif /* else HPUX9 */
1200 #endif /* else NSLDAPI_HAVE_POLL */
1202 } else if ( iosp->ios_type == NSLDAPI_IOSTATUS_TYPE_CALLBACK ) {
1204 * We always pass the session extended I/O argument to
1205 * the extended poll() callback.
1207 rc = ld->ld_extpoll_fn(
1208 iosp->ios_status.ios_cbinfo.cbsi_pollfds,
1209 iosp->ios_status.ios_cbinfo.cbsi_pollfds_size,
1210 nsldapi_tv2ms( timeout ), ld->ld_ext_session_arg );
1212 } else {
1213 LDAPDebug( LDAP_DEBUG_ANY,
1214 "nsldapi_iostatus_poll: unknown I/O type %d\n",
1215 iosp->ios_type, 0, 0 );
1216 rc = 0; /* simulate a timeout (what else to do?) */
1219 LDAP_MUTEX_UNLOCK( ld, LDAP_IOSTATUS_LOCK );
1220 return( rc );
1224 #ifdef NSLDAPI_HAVE_POLL
1226 * returns 1 if "fd" was added to pollfds.
1227 * returns 1 if some of the bits in "events" were added to pollfds.
1228 * returns 0 if no changes were made.
1230 static int
1231 nsldapi_add_to_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1232 short events )
1234 int i, openslot;
1236 /* first we check to see if "fd" is already in our pollfds */
1237 openslot = -1;
1238 for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1239 if ( pip->ossi_pollfds[ i ].fd == fd ) {
1240 if (( pip->ossi_pollfds[ i ].events & events )
1241 != events ) {
1242 pip->ossi_pollfds[ i ].events |= events;
1243 return( 1 );
1244 } else {
1245 return( 0 );
1248 if ( pip->ossi_pollfds[ i ].fd == -1 && openslot == -1 ) {
1249 openslot = i; /* remember for later */
1254 * "fd" is not currently being poll'd on -- add to array.
1255 * if we need to expand the pollfds array, we do it in increments of
1256 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
1258 if ( openslot == -1 ) {
1259 struct pollfd *newpollfds;
1261 if ( pip->ossi_pollfds_size == 0 ) {
1262 newpollfds = (struct pollfd *)NSLDAPI_MALLOC(
1263 NSLDAPI_POLL_ARRAY_GROWTH
1264 * sizeof( struct pollfd ));
1265 } else {
1266 newpollfds = (struct pollfd *)NSLDAPI_REALLOC(
1267 pip->ossi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
1268 + pip->ossi_pollfds_size)
1269 * sizeof( struct pollfd ));
1271 if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1272 return( 0 );
1274 pip->ossi_pollfds = newpollfds;
1275 openslot = pip->ossi_pollfds_size;
1276 pip->ossi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
1277 for ( i = openslot + 1; i < pip->ossi_pollfds_size; ++i ) {
1278 pip->ossi_pollfds[ i ].fd = -1;
1279 pip->ossi_pollfds[ i ].events =
1280 pip->ossi_pollfds[ i ].revents = 0;
1283 pip->ossi_pollfds[ openslot ].fd = fd;
1284 pip->ossi_pollfds[ openslot ].events = events;
1285 pip->ossi_pollfds[ openslot ].revents = 0;
1286 return( 1 );
1291 * returns 1 if any "events" from "fd" were removed from pollfds
1292 * returns 0 of "fd" wasn't in pollfds or if events did not overlap.
1294 static int
1295 nsldapi_clear_from_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1296 short events )
1298 int i;
1300 for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1301 if ( pip->ossi_pollfds[i].fd == fd ) {
1302 if (( pip->ossi_pollfds[ i ].events & events ) != 0 ) {
1303 pip->ossi_pollfds[ i ].events &= ~events;
1304 if ( pip->ossi_pollfds[ i ].events == 0 ) {
1305 pip->ossi_pollfds[i].fd = -1;
1307 return( 1 ); /* events overlap */
1308 } else {
1309 return( 0 ); /* events do not overlap */
1314 return( 0 ); /* "fd" was not found */
1319 * returns 1 if any "revents" from "fd" were set in pollfds revents field.
1320 * returns 0 if not.
1322 static int
1323 nsldapi_find_in_os_pollfds( int fd, struct nsldapi_os_statusinfo *pip,
1324 short revents )
1326 int i;
1328 for ( i = 0; i < pip->ossi_pollfds_size; ++i ) {
1329 if ( pip->ossi_pollfds[i].fd == fd ) {
1330 if (( pip->ossi_pollfds[ i ].revents & revents ) != 0 ) {
1331 return( 1 ); /* revents overlap */
1332 } else {
1333 return( 0 ); /* revents do not overlap */
1338 return( 0 ); /* "fd" was not found */
1340 #endif /* NSLDAPI_HAVE_POLL */
1344 * returns 1 if "sb" was added to pollfds.
1345 * returns 1 if some of the bits in "events" were added to pollfds.
1346 * returns 0 if no changes were made.
1348 static int
1349 nsldapi_add_to_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1350 short events )
1352 int i, openslot;
1354 /* first we check to see if "sb" is already in our pollfds */
1355 openslot = -1;
1356 for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1357 if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1358 if (( pip->cbsi_pollfds[ i ].lpoll_events & events )
1359 != events ) {
1360 pip->cbsi_pollfds[ i ].lpoll_events |= events;
1361 return( 1 );
1362 } else {
1363 return( 0 );
1366 if ( pip->cbsi_pollfds[ i ].lpoll_fd == -1 && openslot == -1 ) {
1367 openslot = i; /* remember for later */
1372 * "sb" is not currently being poll'd on -- add to array.
1373 * if we need to expand the pollfds array, we do it in increments of
1374 * NSLDAPI_POLL_ARRAY_GROWTH (#define near the top of this file).
1376 if ( openslot == -1 ) {
1377 LDAP_X_PollFD *newpollfds;
1379 if ( pip->cbsi_pollfds_size == 0 ) {
1380 newpollfds = (LDAP_X_PollFD *)NSLDAPI_MALLOC(
1381 NSLDAPI_POLL_ARRAY_GROWTH
1382 * sizeof( LDAP_X_PollFD ));
1383 } else {
1384 newpollfds = (LDAP_X_PollFD *)NSLDAPI_REALLOC(
1385 pip->cbsi_pollfds, (NSLDAPI_POLL_ARRAY_GROWTH
1386 + pip->cbsi_pollfds_size)
1387 * sizeof( LDAP_X_PollFD ));
1389 if ( newpollfds == NULL ) { /* XXXmcs: no way to return err! */
1390 return( 0 );
1392 pip->cbsi_pollfds = newpollfds;
1393 openslot = pip->cbsi_pollfds_size;
1394 pip->cbsi_pollfds_size += NSLDAPI_POLL_ARRAY_GROWTH;
1395 for ( i = openslot + 1; i < pip->cbsi_pollfds_size; ++i ) {
1396 pip->cbsi_pollfds[ i ].lpoll_fd = -1;
1397 pip->cbsi_pollfds[ i ].lpoll_socketarg = NULL;
1398 pip->cbsi_pollfds[ i ].lpoll_events =
1399 pip->cbsi_pollfds[ i ].lpoll_revents = 0;
1402 pip->cbsi_pollfds[ openslot ].lpoll_fd = sb->sb_sd;
1403 pip->cbsi_pollfds[ openslot ].lpoll_socketarg =
1404 sb->sb_ext_io_fns.lbextiofn_socket_arg;
1405 pip->cbsi_pollfds[ openslot ].lpoll_events = events;
1406 pip->cbsi_pollfds[ openslot ].lpoll_revents = 0;
1407 return( 1 );
1412 * returns 1 if any "events" from "sb" were removed from pollfds
1413 * returns 0 of "sb" wasn't in pollfds or if events did not overlap.
1415 static int
1416 nsldapi_clear_from_cb_pollfds( Sockbuf *sb,
1417 struct nsldapi_cb_statusinfo *pip, short events )
1419 int i;
1421 for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1422 if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1423 if (( pip->cbsi_pollfds[ i ].lpoll_events
1424 & events ) != 0 ) {
1425 pip->cbsi_pollfds[ i ].lpoll_events &= ~events;
1426 if ( pip->cbsi_pollfds[ i ].lpoll_events
1427 == 0 ) {
1428 pip->cbsi_pollfds[i].lpoll_fd = -1;
1430 return( 1 ); /* events overlap */
1431 } else {
1432 return( 0 ); /* events do not overlap */
1437 return( 0 ); /* "sb" was not found */
1442 * returns 1 if any "revents" from "sb" were set in pollfds revents field.
1443 * returns 0 if not.
1445 static int
1446 nsldapi_find_in_cb_pollfds( Sockbuf *sb, struct nsldapi_cb_statusinfo *pip,
1447 short revents )
1449 int i;
1451 for ( i = 0; i < pip->cbsi_pollfds_size; ++i ) {
1452 if ( NSLDAPI_CB_POLL_MATCH( sb, pip->cbsi_pollfds[ i ] )) {
1453 if (( pip->cbsi_pollfds[ i ].lpoll_revents
1454 & revents ) != 0 ) {
1455 return( 1 ); /* revents overlap */
1456 } else {
1457 return( 0 ); /* revents do not overlap */
1462 return( 0 ); /* "sb" was not found */
1467 * Install read and write functions into lber layer / sb
1470 nsldapi_install_lber_extiofns( LDAP *ld, Sockbuf *sb )
1472 struct lber_x_ext_io_fns lberiofns;
1474 memset( &lberiofns, 0, sizeof(struct lber_x_ext_io_fns) );
1475 if ( NULL != sb ) {
1476 lberiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
1477 lberiofns.lbextiofn_read = ld->ld_extread_fn;
1478 lberiofns.lbextiofn_write = ld->ld_extwrite_fn;
1479 lberiofns.lbextiofn_writev = ld->ld_extwritev_fn;
1480 lberiofns.lbextiofn_socket_arg = ld->ld_ext_session_arg;
1482 if ( ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_EXT_IO_FNS,
1483 &lberiofns ) != 0 ) {
1484 return( LDAP_LOCAL_ERROR );
1488 return( LDAP_SUCCESS );
1493 ******************************************************************************
1494 * One struct and several functions to bridge the gap between new extended
1495 * I/O functions that are installed using ldap_set_option( ...,
1496 * LDAP_OPT_EXTIO_FN_PTRS, ... ) and the original "classic" I/O functions
1497 * (installed using LDAP_OPT_IO_FN_PTRS) follow.
1499 * Our basic strategy is to use the new extended arg to hold a pointer to a
1500 * structure that contains a pointer to the LDAP * (which contains pointers
1501 * to the old functions so we can call them) as well as a pointer to an
1502 * LBER_SOCKET to hold the socket used by the classic functions (the new
1503 * functions use a simple int for the socket).
1505 typedef struct nsldapi_compat_socket_info {
1506 LBER_SOCKET csi_socket;
1507 LDAP *csi_ld;
1508 } NSLDAPICompatSocketInfo;
1510 static int LDAP_CALLBACK
1511 nsldapi_ext_compat_read( int s, void *buf, int len,
1512 struct lextiof_socket_private *arg )
1514 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1515 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1517 return( iofns->liof_read( csip->csi_socket, buf, len ));
1521 static int LDAP_CALLBACK
1522 nsldapi_ext_compat_write( int s, const void *buf, int len,
1523 struct lextiof_socket_private *arg )
1525 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1526 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1528 return( iofns->liof_write( csip->csi_socket, buf, len ));
1532 static int LDAP_CALLBACK
1533 nsldapi_ext_compat_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
1534 struct lextiof_session_private *arg )
1536 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1537 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1538 fd_set readfds, writefds;
1539 int i, rc, maxfd = 0;
1540 struct timeval tv, *tvp;
1543 * Prepare fd_sets for select()
1545 FD_ZERO( &readfds );
1546 FD_ZERO( &writefds );
1547 for ( i = 0; i < nfds; ++i ) {
1548 if ( fds[ i ].lpoll_fd < 0 ) {
1549 continue;
1552 if ( fds[ i ].lpoll_fd >= FD_SETSIZE ) {
1553 LDAP_SET_ERRNO( csip->csi_ld, EINVAL );
1554 return( -1 );
1557 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )) {
1558 FD_SET( fds[i].lpoll_fd, &readfds );
1561 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )) {
1562 FD_SET( fds[i].lpoll_fd, &writefds );
1565 fds[i].lpoll_revents = 0; /* clear revents */
1567 if ( fds[i].lpoll_fd >= maxfd ) {
1568 maxfd = fds[i].lpoll_fd;
1573 * select() using callback.
1575 ++maxfd;
1576 if ( timeout == -1 ) {
1577 tvp = NULL;
1578 } else {
1579 tv.tv_sec = timeout / 1000;
1580 tv.tv_usec = 1000 * ( timeout - tv.tv_sec * 1000 );
1581 tvp = &tv;
1583 rc = iofns->liof_select( maxfd, &readfds, &writefds, NULL, tvp );
1584 if ( rc <= 0 ) { /* timeout or fatal error */
1585 return( rc );
1589 * Use info. in fd_sets to populate poll() revents.
1591 for ( i = 0; i < nfds; ++i ) {
1592 if ( fds[ i ].lpoll_fd < 0 ) {
1593 continue;
1596 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLIN )
1597 && FD_ISSET( fds[i].lpoll_fd, &readfds )) {
1598 fds[i].lpoll_revents |= LDAP_X_POLLIN;
1601 if ( 0 != ( fds[i].lpoll_events & LDAP_X_POLLOUT )
1602 && FD_ISSET( fds[i].lpoll_fd, &writefds )) {
1603 fds[i].lpoll_revents |= LDAP_X_POLLOUT;
1606 /* XXXmcs: any other cases to deal with? LDAP_X_POLLERR? */
1609 return( rc );
1613 static LBER_SOCKET
1614 nsldapi_compat_socket( LDAP *ld, int secure, int domain, int type,
1615 int protocol )
1617 int s;
1619 s = ld->ld_io_fns_ptr->liof_socket( domain, type, protocol );
1621 if ( s >= 0 ) {
1622 char *errmsg = NULL;
1624 #ifdef NSLDAPI_HAVE_POLL
1625 if ( ld->ld_io_fns_ptr->liof_select != NULL
1626 && s >= FD_SETSIZE ) {
1627 errmsg = dgettext(TEXT_DOMAIN,
1628 "can't use socket >= FD_SETSIZE");
1630 #elif !defined(_WINDOWS) /* not on Windows and do not have poll() */
1631 if ( s >= FD_SETSIZE ) {
1632 errmsg = "can't use socket >= FD_SETSIZE";
1634 #endif
1636 if ( NULL == errmsg && secure &&
1637 ld->ld_io_fns_ptr->liof_ssl_enable( s ) < 0 ) {
1638 errmsg = dgettext(TEXT_DOMAIN,
1639 "failed to enable secure mode");
1642 if ( NULL != errmsg ) {
1643 if ( NULL == ld->ld_io_fns_ptr->liof_close ) {
1644 nsldapi_os_closesocket( s );
1645 } else {
1646 ld->ld_io_fns_ptr->liof_close( s );
1648 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL,
1649 nsldapi_strdup( errmsg ));
1650 return( -1 );
1654 return( s );
1659 * Note: timeout is ignored because we have no way to pass it via
1660 * the old I/O callback interface.
1662 static int LDAP_CALLBACK
1663 nsldapi_ext_compat_connect( const char *hostlist, int defport, int timeout,
1664 unsigned long options, struct lextiof_session_private *sessionarg,
1665 struct lextiof_socket_private **socketargp
1666 #ifdef _SOLARIS_SDK
1667 , void **not_used )
1668 #else
1670 #endif /* _SOLARIS_SDK */
1672 NSLDAPICompatSocketInfo *defcsip;
1673 struct ldap_io_fns *iofns;
1674 int s, secure;
1675 NSLDAPI_SOCKET_FN *socketfn;
1676 NSLDAPI_IOCTL_FN *ioctlfn;
1677 NSLDAPI_CONNECT_WITH_TO_FN *connectwithtofn;
1678 NSLDAPI_CONNECT_FN *connectfn;
1679 NSLDAPI_CLOSE_FN *closefn;
1681 defcsip = (NSLDAPICompatSocketInfo *)sessionarg;
1682 iofns = defcsip->csi_ld->ld_io_fns_ptr;
1684 if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
1685 if ( NULL == iofns->liof_ssl_enable ) {
1686 LDAP_SET_ERRNO( defcsip->csi_ld, EINVAL );
1687 return( -1 );
1689 secure = 1;
1690 } else {
1691 secure = 0;
1694 socketfn = ( iofns->liof_socket == NULL ) ?
1695 nsldapi_os_socket : nsldapi_compat_socket;
1696 ioctlfn = ( iofns->liof_ioctl == NULL ) ?
1697 nsldapi_os_ioctl : (NSLDAPI_IOCTL_FN *)(iofns->liof_ioctl);
1698 if ( NULL == iofns->liof_connect ) {
1699 connectwithtofn = nsldapi_os_connect_with_to;
1700 connectfn = NULL;
1701 } else {
1702 connectwithtofn = NULL;
1703 connectfn = iofns->liof_connect;
1705 closefn = ( iofns->liof_close == NULL ) ?
1706 nsldapi_os_closesocket : iofns->liof_close;
1708 s = nsldapi_try_each_host( defcsip->csi_ld, hostlist, defport,
1709 secure, socketfn, ioctlfn, connectwithtofn,
1710 connectfn, closefn );
1712 if ( s >= 0 ) {
1713 NSLDAPICompatSocketInfo *csip;
1715 if (( csip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
1716 sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
1717 (*closefn)( s );
1718 LDAP_SET_LDERRNO( defcsip->csi_ld, LDAP_NO_MEMORY,
1719 NULL, NULL );
1720 return( -1 );
1723 csip->csi_socket = s;
1724 csip->csi_ld = defcsip->csi_ld;
1725 *socketargp = (void *)csip;
1728 * We always return 1, which is a valid but not unique socket
1729 * (file descriptor) number. The extended I/O functions only
1730 * require that the combination of the void *arg and the int
1731 * socket be unique. Since we allocate the
1732 * NSLDAPICompatSocketInfo that we assign to arg, we meet
1733 * that requirement.
1735 s = 1;
1738 return( s );
1742 static int LDAP_CALLBACK
1743 nsldapi_ext_compat_close( int s, struct lextiof_socket_private *arg )
1745 NSLDAPICompatSocketInfo *csip = (NSLDAPICompatSocketInfo *)arg;
1746 struct ldap_io_fns *iofns = csip->csi_ld->ld_io_fns_ptr;
1747 int rc;
1749 rc = iofns->liof_close( csip->csi_socket );
1751 NSLDAPI_FREE( csip );
1753 return( rc );
1757 * Install the I/O functions.
1758 * Return an LDAP error code (LDAP_SUCCESS if all goes well).
1761 nsldapi_install_compat_io_fns( LDAP *ld, struct ldap_io_fns *iofns )
1763 NSLDAPICompatSocketInfo *defcsip;
1765 if (( defcsip = (NSLDAPICompatSocketInfo *)NSLDAPI_CALLOC( 1,
1766 sizeof( NSLDAPICompatSocketInfo ))) == NULL ) {
1767 return( LDAP_NO_MEMORY );
1770 defcsip->csi_socket = -1;
1771 defcsip->csi_ld = ld;
1773 if ( ld->ld_io_fns_ptr != NULL ) {
1774 (void)memset( (char *)ld->ld_io_fns_ptr, 0,
1775 sizeof( struct ldap_io_fns ));
1776 } else if (( ld->ld_io_fns_ptr = (struct ldap_io_fns *)NSLDAPI_CALLOC(
1777 1, sizeof( struct ldap_io_fns ))) == NULL ) {
1778 NSLDAPI_FREE( defcsip );
1779 return( LDAP_NO_MEMORY );
1782 /* struct copy */
1783 *(ld->ld_io_fns_ptr) = *iofns;
1785 ld->ld_extio_size = LBER_X_EXTIO_FNS_SIZE;
1786 ld->ld_ext_session_arg = defcsip;
1787 ld->ld_extread_fn = nsldapi_ext_compat_read;
1788 ld->ld_extwrite_fn = nsldapi_ext_compat_write;
1789 ld->ld_extpoll_fn = nsldapi_ext_compat_poll;
1790 ld->ld_extconnect_fn = nsldapi_ext_compat_connect;
1791 ld->ld_extclose_fn = nsldapi_ext_compat_close;
1793 return( nsldapi_install_lber_extiofns( ld, ld->ld_sbp ));
1796 * end of compat I/O functions
1797 ******************************************************************************
1799 #ifdef _SOLARIS_SDK
1801 * _ns_gethostbyaddr is a helper function for the ssl layer so that
1802 * it can use the ldap layer's gethostbyaddr resolver.
1805 LDAPHostEnt *
1806 _ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type,
1807 LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
1808 void *extradata)
1810 if (ld == NULL || ld->ld_dns_gethostbyaddr_fn == NULL)
1811 return (NULL);
1812 return (ld->ld_dns_gethostbyaddr_fn(addr, length, type,
1813 result, buffer, buflen, statusp, extradata));
1816 #endif /* _SOLARIS_SDK */