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