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
36 static char copyright
[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
40 #ifdef LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
44 #ifdef NSLDAPI_HAVE_POLL
50 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) == INVALID_SOCKET)
52 #define NSLDAPI_INVALID_OS_SOCKET( s ) ((s) < 0 )
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() */
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.
86 #define NSLDAPI_CB_POLL_SD_CAST (unsigned int)
88 #define NSLDAPI_CB_POLL_SD_CAST
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) ) )
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)
102 struct nsldapi_iostatus_info
{
104 #define NSLDAPI_IOSTATUS_TYPE_OSNATIVE 1 /* poll() or select() */
105 #define NSLDAPI_IOSTATUS_TYPE_CALLBACK 2 /* poll()-like */
109 struct nsldapi_os_statusinfo ios_osinfo
;
110 struct nsldapi_cb_statusinfo ios_cbinfo
;
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
);
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 */
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
,
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
);
180 nsldapi_os_closesocket( LBER_SOCKET s
)
185 rc
= closesocket( s
);
194 nsldapi_os_socket( LDAP
*ld
, int secure
, int domain
, int type
, int protocol
)
196 int s
, invalid_socket
;
200 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
,
201 nsldapi_strdup( dgettext(TEXT_DOMAIN
,
202 "secure mode not supported") ));
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");
215 } else { /* valid socket -- check for overflow */
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";
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
);
240 * Non-blocking connect call function
243 nsldapi_os_connect_with_to(LBER_SOCKET sockfd
, struct sockaddr
*saptr
,
248 #endif /* _WINDOWS */
257 #endif /* _WINDOWS */
258 int msec
= ld
->ld_connect_timeout
; /* milliseconds */
259 int continue_on_intr
= 0;
261 hrtime_t start_time
= 0, tmp_time
, tv_time
; /* nanoseconds */
263 long start_time
= 0, tmp_time
; /* seconds */
267 LDAPDebug( LDAP_DEBUG_TRACE
, "nsldapi_connect_nonblock timeout: %d (msec)\n",
271 ioctlsocket(sockfd
, FIONBIO
, &nonblock
);
273 flags
= fcntl(sockfd
, F_GETFL
, 0);
274 fcntl(sockfd
, F_SETFL
, flags
| O_NONBLOCK
);
275 #endif /* _WINDOWS */
278 if ((n
= connect(sockfd
, saptr
, salen
)) < 0)
280 if ((n
!= SOCKET_ERROR
) && (WSAGetLastError() != WSAEWOULDBLOCK
)) {
282 if (errno
!= EINPROGRESS
) {
283 #endif /* _WINDOWS */
285 if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
297 FD_SET(sockfd
, &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
;
311 tval
.tv_sec
= msec
/ MILLISEC
;
312 tval
.tv_usec
= (MICROSEC
/ MILLISEC
) *
315 start_time
= gethrtime();
316 tv_time
= MSEC2NSEC(msec
);
318 start_time
= (long)time(NULL
);
326 /* if timeval structure == NULL, select will block indefinitely */
327 /* != NULL, and value == 0, select will */
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 */
335 if ((n
= select(sockfd
+1, &rset
, &wset
, &eset
,
336 (msec
!= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
) ? &tval
: NULL
)) == 0) {
337 errno
= WSAETIMEDOUT
;
340 /* if wset is set, the connect worked */
341 if (FD_ISSET(sockfd
, &wset
) || FD_ISSET(sockfd
, &rset
)) {
343 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, (char *)&error
, &len
)
349 /* if eset is set, the connect failed */
350 if (FD_ISSET(sockfd
, &eset
)) {
354 /* failure on select call */
355 if (n
== SOCKET_ERROR
) {
356 perror("select error: SOCKET_ERROR returned");
361 * if LDAP_BITOPT_RESTART and select() is interrupted
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) {
373 if ((ld
->ld_options
& LDAP_BITOPT_RESTART
) &&
375 continue_on_intr
= 1;
378 FD_SET(sockfd
, &rset
);
380 /* honour the timeout */
381 if ((msec
!= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
) &&
384 tmp_time
= gethrtime();
386 (tmp_time
- start_time
)) <= 0) {
388 tmp_time
= (long)time(NULL
);
390 (tmp_time
- start_time
)) <= 0) {
397 tval
.tv_sec
= tv_time
/ NANOSEC
;
398 tval
.tv_usec
= (tv_time
% NANOSEC
) /
399 (NANOSEC
/ MICROSEC
);
401 start_time
= tmp_time
;
405 perror("select error: ");
410 } while (continue_on_intr
== 1);
412 if (FD_ISSET(sockfd
, &rset
) || FD_ISSET(sockfd
, &wset
)) {
414 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, (char *)&error
, &len
)
418 } else if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
419 perror("select error: sockfd not set");
422 #endif /* _WINDOWS */
426 ioctlsocket(sockfd
, FIONBIO
, &block
);
428 fcntl(sockfd
, F_SETFL
, flags
);
429 #endif /* _WINDOWS */
441 nsldapi_os_ioctl( LBER_SOCKET s
, int option
, int *statusp
)
448 if ( FIONBIO
!= option
) {
453 iostatus
= *(u_long
*)statusp
;
454 err
= ioctlsocket( s
, FIONBIO
, &iostatus
);
456 err
= ioctl( s
, FIONBIO
, (caddr_t
)statusp
);
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
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
;
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
497 #endif /* _SOLARIS_SDK */
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
);
507 LDAP_SET_LDERRNO( ld
, LDAP_CONNECT_ERROR
, NULL
, NULL
);
514 * Set krbinstancep (canonical name of host for use by Kerberos).
519 if (( *krbinstancep
= nsldapi_host_connected_to( sb
)) != NULL
520 && ( p
= strchr( *krbinstancep
, '.' )) != NULL
) {
524 *krbinstancep
= NULL
;
525 #endif /* KERBEROS */
532 * Returns a socket number if successful and -1 if an error occurs.
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
;
542 struct sockaddr_in sin
;
543 nsldapi_in_addr_t address
;
544 char **addrlist
, *ldhpbuf
, *ldhpbuf_allocd
;
546 LDAPHostEnt ldhent
, *ldhp
;
548 struct ldap_x_hostlist_status
*status
;
549 #ifdef GETHOSTBYNAME_BUF_T
550 GETHOSTBYNAME_BUF_T hbuf
;
552 #endif /* GETHOSTBYNAME_BUF_T */
555 parse_err
= ldap_x_hostlist_first( hostlist
, defport
, &host
, &port
,
557 while ( !connected
&& LDAP_SUCCESS
== parse_err
&& host
!= NULL
) {
558 ldhpbuf_allocd
= 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
;
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
);
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
,
592 ldap_memfree( host
);
593 ldap_x_hostlist_statusfree( status
);
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
);
618 for ( i
= 0; !use_hp
|| ( addrlist
[ i
] != 0 ); i
++ ) {
619 if ( -1 == ( s
= (*socketfn
)( ld
, secure
, AF_INET
,
621 if ( ldhpbuf_allocd
!= NULL
) {
622 NSLDAPI_FREE( ldhpbuf_allocd
);
624 ldap_memfree( host
);
625 ldap_x_hostlist_statusfree( status
);
629 if ( ld
->ld_options
& LDAP_BITOPT_ASYNC
) {
632 err
= (*ioctlfn
)( s
, FIONBIO
, &iostatus
);
634 LDAPDebug( LDAP_DEBUG_ANY
,
635 "FIONBIO ioctl failed on %d\n",
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
),
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 */
689 if ( ld
->ld_options
& LDAP_BITOPT_ASYNC
) {
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",
704 if ( ldap_debug
& LDAP_DEBUG_TRACE
) {
705 perror( (char *)inet_ntoa( sin
.sin_addr
));
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
);
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 );
735 nsldapi_close_connection( LDAP
*ld
, Sockbuf
*sb
)
737 if ( ld
->ld_extclose_fn
== NULL
) {
738 nsldapi_os_closesocket( sb
->sb_sd
);
740 ld
->ld_extclose_fn( sb
->sb_sd
,
741 sb
->sb_ext_io_fns
.lbextiofn_socket_arg
);
748 nsldapi_host_connected_to( Sockbuf
*sb
)
753 struct sockaddr_in sin
;
755 (void)memset( (char *)&sin
, 0, sizeof( struct sockaddr_in
));
757 if ( getpeername( sb
->sb_sd
, (struct sockaddr
*)&sin
, &len
) == -1 ) {
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
));
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
);
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
)) {
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
;
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
);
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
);
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
)) {
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
;
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
);
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
);
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
)) {
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
)) {
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
;
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
);
948 * Return a non-zero value if sb is ready for write.
951 nsldapi_iostatus_is_write_ready( LDAP
*ld
, Sockbuf
*sb
)
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
);
982 LDAPDebug( LDAP_DEBUG_ANY
,
983 "nsldapi_iostatus_is_write_ready: unknown I/O type %d\n",
984 iosp
->ios_type
, 0, 0 );
988 LDAP_MUTEX_UNLOCK( ld
, LDAP_IOSTATUS_LOCK
);
994 * Return a non-zero value if sb is ready for read.
997 nsldapi_iostatus_is_read_ready( LDAP
*ld
, Sockbuf
*sb
)
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
);
1028 LDAPDebug( LDAP_DEBUG_ANY
,
1029 "nsldapi_iostatus_is_read_ready: unknown I/O type %d\n",
1030 iosp
->ios_type
, 0, 0 );
1034 LDAP_MUTEX_UNLOCK( ld
, LDAP_IOSTATUS_LOCK
);
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)
1045 nsldapi_iostatus_init_nolock( LDAP
*ld
)
1047 NSLDAPIIOStatus
*iosp
;
1049 if ( ld
->ld_iostatus
!= NULL
) {
1053 if (( iosp
= (NSLDAPIIOStatus
*)NSLDAPI_CALLOC( 1,
1054 sizeof( NSLDAPIIOStatus
))) == NULL
) {
1055 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
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 */
1067 iosp
->ios_type
= NSLDAPI_IOSTATUS_TYPE_CALLBACK
;
1070 ld
->ld_iostatus
= iosp
;
1076 nsldapi_iostatus_free( LDAP
*ld
)
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
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
1108 iosp
->ios_status
.ios_cbinfo
.cbsi_pollfds
);
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
);
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. */
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;
1149 nsldapi_tv2ms( struct timeval
*tv
)
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
)
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
;
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
,
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
,
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
);
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
);
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.
1231 nsldapi_add_to_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
1236 /* first we check to see if "fd" is already in our pollfds */
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
)
1242 pip
->ossi_pollfds
[ i
].events
|= events
;
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
));
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! */
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;
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.
1295 nsldapi_clear_from_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
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 */
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.
1323 nsldapi_find_in_os_pollfds( int fd
, struct nsldapi_os_statusinfo
*pip
,
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 */
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.
1349 nsldapi_add_to_cb_pollfds( Sockbuf
*sb
, struct nsldapi_cb_statusinfo
*pip
,
1354 /* first we check to see if "sb" is already in our pollfds */
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
)
1360 pip
->cbsi_pollfds
[ i
].lpoll_events
|= events
;
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
));
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! */
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;
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.
1416 nsldapi_clear_from_cb_pollfds( Sockbuf
*sb
,
1417 struct nsldapi_cb_statusinfo
*pip
, short events
)
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
1425 pip
->cbsi_pollfds
[ i
].lpoll_events
&= ~events
;
1426 if ( pip
->cbsi_pollfds
[ i
].lpoll_events
1428 pip
->cbsi_pollfds
[i
].lpoll_fd
= -1;
1430 return( 1 ); /* events overlap */
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.
1446 nsldapi_find_in_cb_pollfds( Sockbuf
*sb
, struct nsldapi_cb_statusinfo
*pip
,
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 */
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
) );
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
;
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 ) {
1552 if ( fds
[ i
].lpoll_fd
>= FD_SETSIZE
) {
1553 LDAP_SET_ERRNO( csip
->csi_ld
, EINVAL
);
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.
1576 if ( timeout
== -1 ) {
1579 tv
.tv_sec
= timeout
/ 1000;
1580 tv
.tv_usec
= 1000 * ( timeout
- tv
.tv_sec
* 1000 );
1583 rc
= iofns
->liof_select( maxfd
, &readfds
, &writefds
, NULL
, tvp
);
1584 if ( rc
<= 0 ) { /* timeout or fatal error */
1589 * Use info. in fd_sets to populate poll() revents.
1591 for ( i
= 0; i
< nfds
; ++i
) {
1592 if ( fds
[ i
].lpoll_fd
< 0 ) {
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? */
1614 nsldapi_compat_socket( LDAP
*ld
, int secure
, int domain
, int type
,
1619 s
= ld
->ld_io_fns_ptr
->liof_socket( domain
, type
, protocol
);
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";
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
);
1646 ld
->ld_io_fns_ptr
->liof_close( s
);
1648 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
,
1649 nsldapi_strdup( errmsg
));
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
1670 #endif /* _SOLARIS_SDK */
1672 NSLDAPICompatSocketInfo
*defcsip
;
1673 struct ldap_io_fns
*iofns
;
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
);
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
;
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
);
1713 NSLDAPICompatSocketInfo
*csip
;
1715 if (( csip
= (NSLDAPICompatSocketInfo
*)NSLDAPI_CALLOC( 1,
1716 sizeof( NSLDAPICompatSocketInfo
))) == NULL
) {
1718 LDAP_SET_LDERRNO( defcsip
->csi_ld
, LDAP_NO_MEMORY
,
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
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
;
1749 rc
= iofns
->liof_close( csip
->csi_socket
);
1751 NSLDAPI_FREE( csip
);
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
);
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 ******************************************************************************
1801 * _ns_gethostbyaddr is a helper function for the ssl layer so that
1802 * it can use the ldap layer's gethostbyaddr resolver.
1806 _ns_gethostbyaddr(LDAP
*ld
, const char *addr
, int length
, int type
,
1807 LDAPHostEnt
*result
, char *buffer
, int buflen
, int *statusp
,
1810 if (ld
== NULL
|| ld
->ld_dns_gethostbyaddr_fn
== NULL
)
1812 return (ld
->ld_dns_gethostbyaddr_fn(addr
, length
, type
,
1813 result
, buffer
, buflen
, statusp
, extradata
));
1816 #endif /* _SOLARIS_SDK */