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