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 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 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 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