2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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
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
28 * Copyright (c) 1995 Regents of the University of Michigan.
29 * All rights reserved.
32 * os-ip.c -- platform-specific TCP & UDP related code
37 static char copyright
[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
42 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
46 #ifdef NSLDAPI_HAVE_POLL
52 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) == INVALID_SOCKET)
54 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) < 0 )
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() */
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.
88 #define NSLDAPI_CB_POLL_SD_CAST (unsigned int)
90 #define NSLDAPI_CB_POLL_SD_CAST
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) ) )
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)
104 struct nsldapi_iostatus_info
{
106 #define NSLDAPI_IOSTATUS_TYPE_OSNATIVE 1 /* poll() or select() */
107 #define NSLDAPI_IOSTATUS_TYPE_CALLBACK 2 /* poll()-like */
111 struct nsldapi_os_statusinfo ios_osinfo
;
112 struct nsldapi_cb_statusinfo ios_cbinfo
;
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
);
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 */
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
,
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
);
182 nsldapi_os_closesocket( LBER_SOCKET s
)
187 rc
= closesocket( s
);
196 nsldapi_os_socket( LDAP
*ld
, int secure
, int domain
, int type
, int protocol
)
198 int s
, invalid_socket
;
202 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
,
203 nsldapi_strdup( dgettext(TEXT_DOMAIN
,
204 "secure mode not supported") ));
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");
217 } else { /* valid socket -- check for overflow */
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";
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
);
242 * Non-blocking connect call function
245 nsldapi_os_connect_with_to(LBER_SOCKET sockfd
, struct sockaddr
*saptr
,
250 #endif /* _WINDOWS */
259 #endif /* _WINDOWS */
260 int msec
= ld
->ld_connect_timeout
; /* milliseconds */
261 int continue_on_intr
= 0;
263 hrtime_t start_time
= 0, tmp_time
, tv_time
; /* nanoseconds */
265 long start_time
= 0, tmp_time
; /* seconds */
269 LDAPDebug( LDAP_DEBUG_TRACE
, "nsldapi_connect_nonblock timeout: %d (msec)\n",
273 ioctlsocket(sockfd
, FIONBIO
, &nonblock
);
275 flags
= fcntl(sockfd
, F_GETFL
, 0);
276 fcntl(sockfd
, F_SETFL
, flags
| O_NONBLOCK
);
277 #endif /* _WINDOWS */
280 if ((n
= connect(sockfd
, saptr
, salen
)) < 0)
282 if ((n
!= SOCKET_ERROR
) && (WSAGetLastError() != WSAEWOULDBLOCK
)) {
284 if (errno
!= EINPROGRESS
) {
285 #endif /* _WINDOWS */
287 if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
299 FD_SET(sockfd
, &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
;
313 tval
.tv_sec
= msec
/ MILLISEC
;
314 tval
.tv_usec
= (MICROSEC
/ MILLISEC
) *
317 start_time
= gethrtime();
318 tv_time
= MSEC2NSEC(msec
);
320 start_time
= (long)time(NULL
);
328 /* if timeval structure == NULL, select will block indefinitely */
329 /* != NULL, and value == 0, select will */
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 */
337 if ((n
= select(sockfd
+1, &rset
, &wset
, &eset
,
338 (msec
!= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
) ? &tval
: NULL
)) == 0) {
339 errno
= WSAETIMEDOUT
;
342 /* if wset is set, the connect worked */
343 if (FD_ISSET(sockfd
, &wset
) || FD_ISSET(sockfd
, &rset
)) {
345 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, (char *)&error
, &len
)
351 /* if eset is set, the connect failed */
352 if (FD_ISSET(sockfd
, &eset
)) {
356 /* failure on select call */
357 if (n
== SOCKET_ERROR
) {
358 perror("select error: SOCKET_ERROR returned");
363 * if LDAP_BITOPT_RESTART and select() is interrupted
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) {
375 if ((ld
->ld_options
& LDAP_BITOPT_RESTART
) &&
377 continue_on_intr
= 1;
380 FD_SET(sockfd
, &rset
);
382 /* honour the timeout */
383 if ((msec
!= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
) &&
386 tmp_time
= gethrtime();
388 (tmp_time
- start_time
)) <= 0) {
390 tmp_time
= (long)time(NULL
);
392 (tmp_time
- start_time
)) <= 0) {
399 tval
.tv_sec
= tv_time
/ NANOSEC
;
400 tval
.tv_usec
= (tv_time
% NANOSEC
) /
401 (NANOSEC
/ MICROSEC
);
403 start_time
= tmp_time
;
407 perror("select error: ");
412 } while (continue_on_intr
== 1);
414 if (FD_ISSET(sockfd
, &rset
) || FD_ISSET(sockfd
, &wset
)) {
416 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, (char *)&error
, &len
)
420 } else if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
421 perror("select error: sockfd not set");
424 #endif /* _WINDOWS */
428 ioctlsocket(sockfd
, FIONBIO
, &block
);
430 fcntl(sockfd
, F_SETFL
, flags
);
431 #endif /* _WINDOWS */
443 nsldapi_os_ioctl( LBER_SOCKET s
, int option
, int *statusp
)
450 if ( FIONBIO
!= option
) {
455 iostatus
= *(u_long
*)statusp
;
456 err
= ioctlsocket( s
, FIONBIO
, &iostatus
);
458 err
= ioctl( s
, FIONBIO
, (caddr_t
)statusp
);
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
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
;
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
499 #endif /* _SOLARIS_SDK */
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
);
509 LDAP_SET_LDERRNO( ld
, LDAP_CONNECT_ERROR
, NULL
, NULL
);
516 * Set krbinstancep (canonical name of host for use by Kerberos).
521 if (( *krbinstancep
= nsldapi_host_connected_to( sb
)) != NULL
522 && ( p
= strchr( *krbinstancep
, '.' )) != NULL
) {
526 *krbinstancep
= NULL
;
527 #endif /* KERBEROS */
534 * Returns a socket number if successful and -1 if an error occurs.
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
;
544 struct sockaddr_in sin
;
545 nsldapi_in_addr_t address
;
546 char **addrlist
, *ldhpbuf
, *ldhpbuf_allocd
;
548 LDAPHostEnt ldhent
, *ldhp
;
550 struct ldap_x_hostlist_status
*status
;
551 #ifdef GETHOSTBYNAME_BUF_T
552 GETHOSTBYNAME_BUF_T hbuf
;
554 #endif /* GETHOSTBYNAME_BUF_T */
557 parse_err
= ldap_x_hostlist_first( hostlist
, defport
, &host
, &port
,
559 while ( !connected
&& LDAP_SUCCESS
== parse_err
&& host
!= NULL
) {
560 ldhpbuf_allocd
= 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
;
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
);
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
,
594 ldap_memfree( host
);
595 ldap_x_hostlist_statusfree( status
);
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
);
620 for ( i
= 0; !use_hp
|| ( addrlist
[ i
] != 0 ); i
++ ) {
621 if ( -1 == ( s
= (*socketfn
)( ld
, secure
, AF_INET
,
623 if ( ldhpbuf_allocd
!= NULL
) {
624 NSLDAPI_FREE( ldhpbuf_allocd
);
626 ldap_memfree( host
);
627 ldap_x_hostlist_statusfree( status
);
631 if ( ld
->ld_options
& LDAP_BITOPT_ASYNC
) {
634 err
= (*ioctlfn
)( s
, FIONBIO
, &iostatus
);
636 LDAPDebug( LDAP_DEBUG_ANY
,
637 "FIONBIO ioctl failed on %d\n",
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
),
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 */
691 if ( ld
->ld_options
& LDAP_BITOPT_ASYNC
) {
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",
706 if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
707 perror( (char *)inet_ntoa( sin
.sin_addr
));
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
);
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 );
737 nsldapi_close_connection( LDAP
*ld
, Sockbuf
*sb
)
739 if ( ld
->ld_extclose_fn
== NULL
) {
740 nsldapi_os_closesocket( sb
->sb_sd
);
742 ld
->ld_extclose_fn( sb
->sb_sd
,
743 sb
->sb_ext_io_fns
.lbextiofn_socket_arg
);
750 nsldapi_host_connected_to( Sockbuf
*sb
)
755 struct sockaddr_in sin
;
757 (void)memset( (char *)&sin
, 0, sizeof( struct sockaddr_in
));
759 if ( getpeername( sb
->sb_sd
, (struct sockaddr
*)&sin
, &len
) == -1 ) {
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
));
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
);
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
)) {
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
;
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
);
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
);
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
)) {
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
;
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
);
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
);
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
)) {
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
)) {
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
;
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
);
950 * Return a non-zero value if sb is ready for write.
953 nsldapi_iostatus_is_write_ready( LDAP
*ld
, Sockbuf
*sb
)
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
);
984 LDAPDebug( LDAP_DEBUG_ANY
,
985 "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
986 iosp
->ios_type
, 0, 0 );
990 LDAP_MUTEX_UNLOCK( ld
, LDAP_IOSTATUS_LOCK
);
996 * Return a non-zero value if sb is ready for read.
999 nsldapi_iostatus_is_read_ready( LDAP
*ld
, Sockbuf
*sb
)
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
);
1030 LDAPDebug( LDAP_DEBUG_ANY
,
1031 "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
1032 iosp
->ios_type
, 0, 0 );
1036 LDAP_MUTEX_UNLOCK( ld
, LDAP_IOSTATUS_LOCK
);
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)
1047 nsldapi_iostatus_init_nolock( LDAP
*ld
)
1049 NSLDAPIIOStatus
*iosp
;
1051 if ( ld
->ld_iostatus
!= NULL
) {
1055 if (( iosp
= (NSLDAPIIOStatus
*)NSLDAPI_CALLOC( 1,
1056 sizeof( NSLDAPIIOStatus
))) == NULL
) {
1057 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
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 */
1069 iosp
->ios_type
= NSLDAPI_IOSTATUS_TYPE_CALLBACK
;
1072 ld
->ld_iostatus
= iosp
;
1078 nsldapi_iostatus_free( LDAP
*ld
)
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
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
1110 iosp
->ios_status
.ios_cbinfo
.cbsi_pollfds
);
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
);
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. */
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;
1151 nsldapi_tv2ms( struct timeval
*tv
)
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
)
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
;
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
,
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
,
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
);
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
);
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.
1233 nsldapi_add_to_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
1238 /* first we check to see if "fd" is already in our pollfds */
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
)
1244 pip
->ossi_pollfds
[ i
].events
|= events
;
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
));
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! */
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;
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.
1297 nsldapi_clear_from_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
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 */
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.
1325 nsldapi_find_in_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
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 */
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.
1351 nsldapi_add_to_cb_pollfds( Sockbuf
*sb
, struct nsldapi_cb_statusinfo
*pip
,
1356 /* first we check to see if "sb" is already in our pollfds */
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
)
1362 pip
->cbsi_pollfds
[ i
].lpoll_events
|= events
;
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
));
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! */
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;
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.
1418 nsldapi_clear_from_cb_pollfds( Sockbuf
*sb
,
1419 struct nsldapi_cb_statusinfo
*pip
, short events
)
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
1427 pip
->cbsi_pollfds
[ i
].lpoll_events
&= ~events
;
1428 if ( pip
->cbsi_pollfds
[ i
].lpoll_events
1430 pip
->cbsi_pollfds
[i
].lpoll_fd
= -1;
1432 return( 1 ); /* events overlap */
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.
1448 nsldapi_find_in_cb_pollfds( Sockbuf
*sb
, struct nsldapi_cb_statusinfo
*pip
,
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 */
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
) );
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
;
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 ) {
1554 if ( fds
[ i
].lpoll_fd
>= FD_SETSIZE
) {
1555 LDAP_SET_ERRNO( csip
->csi_ld
, EINVAL
);
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.
1578 if ( timeout
== -1 ) {
1581 tv
.tv_sec
= timeout
/ 1000;
1582 tv
.tv_usec
= 1000 * ( timeout
- tv
.tv_sec
* 1000 );
1585 rc
= iofns
->liof_select( maxfd
, &readfds
, &writefds
, NULL
, tvp
);
1586 if ( rc
<= 0 ) { /* timeout or fatal error */
1591 * Use info. in fd_sets to populate poll() revents.
1593 for ( i
= 0; i
< nfds
; ++i
) {
1594 if ( fds
[ i
].lpoll_fd
< 0 ) {
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? */
1616 nsldapi_compat_socket( LDAP
*ld
, int secure
, int domain
, int type
,
1621 s
= ld
->ld_io_fns_ptr
->liof_socket( domain
, type
, protocol
);
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";
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
);
1648 ld
->ld_io_fns_ptr
->liof_close( s
);
1650 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
,
1651 nsldapi_strdup( errmsg
));
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
1672 #endif /* _SOLARIS_SDK */
1674 NSLDAPICompatSocketInfo
*defcsip
;
1675 struct ldap_io_fns
*iofns
;
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
);
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
;
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
);
1715 NSLDAPICompatSocketInfo
*csip
;
1717 if (( csip
= (NSLDAPICompatSocketInfo
*)NSLDAPI_CALLOC( 1,
1718 sizeof( NSLDAPICompatSocketInfo
))) == NULL
) {
1720 LDAP_SET_LDERRNO( defcsip
->csi_ld
, LDAP_NO_MEMORY
,
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
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
;
1751 rc
= iofns
->liof_close( csip
->csi_socket
);
1753 NSLDAPI_FREE( csip
);
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
);
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 ******************************************************************************
1803 * _ns_gethostbyaddr is a helper function for the ssl layer so that
1804 * it can use the ldap layer's gethostbyaddr resolver.
1808 _ns_gethostbyaddr(LDAP
*ld
, const char *addr
, int length
, int type
,
1809 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
1812 if (ld
== NULL
|| ld
->ld_dns_gethostbyaddr_fn
== NULL
)
1814 return (ld
->ld_dns_gethostbyaddr_fn(addr
, length
, type
,
1815 result
, buffer
, buflen
, statusp
, extradata
));
1818 #endif /* _SOLARIS_SDK */