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