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