home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / os-ip.c < prev    next >
C/C++ Source or Header  |  2001-07-22  |  14KB  |  655 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.33.2.13 2001/07/21 19:01:39 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  4.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  5.  */
  6. /*  Portions
  7.  *  Copyright (c) 1995 Regents of the University of Michigan.
  8.  *  All rights reserved.
  9.  *
  10.  *  os-ip.c -- platform-specific TCP & UDP related code
  11.  */
  12.  
  13. #include "portable.h"
  14.  
  15. #include <stdio.h>
  16.  
  17. #include <ac/stdlib.h>
  18.  
  19. #include <ac/errno.h>
  20. #include <ac/socket.h>
  21. #include <ac/string.h>
  22. #include <ac/time.h>
  23. #include <ac/unistd.h>
  24.  
  25. #ifdef HAVE_IO_H
  26. #include <io.h>
  27. #endif /* HAVE_IO_H */
  28.  
  29. #include "ldap-int.h"
  30.  
  31. int ldap_int_tblsize = 0;
  32.  
  33. /*
  34.  * nonblock connect code
  35.  * written by Lars Uffmann, <lars.uffmann@mediaway.net>.
  36.  *
  37.  * Copyright 1999, Lars Uffmann, All rights reserved.
  38.  * This software is not subject to any license of my employer
  39.  * mediaWays GmbH.
  40.  *
  41.  * OpenLDAP COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  42.  *
  43.  * Read about the rationale in ldap_connect_timeout: 
  44.  * ftp://koobera.math.uic.edu/www/docs/connect.html.
  45.  */
  46.  
  47. #define osip_debug(ld,fmt,arg1,arg2,arg3) \
  48. do { \
  49.     ldap_log_printf(NULL, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
  50. } while(0)
  51.  
  52. static void
  53. ldap_pvt_set_errno(int err)
  54. {
  55.     errno = err;
  56. }
  57.  
  58. int
  59. ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src )
  60. {
  61.     struct timeval *new;
  62.  
  63.     assert( dest != NULL );
  64.  
  65.     if (src == NULL) {
  66.         *dest = NULL;
  67.         return 0;
  68.     }
  69.  
  70.     new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval));
  71.  
  72.     if( new == NULL ) {
  73.         *dest = NULL;
  74.         return 1;
  75.     }
  76.  
  77.     AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval));
  78.  
  79.     *dest = new;
  80.     return 0;
  81. }
  82.  
  83. static int
  84. ldap_pvt_ndelay_on(LDAP *ld, int fd)
  85. {
  86.     osip_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
  87.     return ber_pvt_socket_set_nonblock( fd, 1 );
  88. }
  89.    
  90. static int
  91. ldap_pvt_ndelay_off(LDAP *ld, int fd)
  92. {
  93.     osip_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
  94.     return ber_pvt_socket_set_nonblock( fd, 0 );
  95. }
  96.  
  97. static ber_socket_t
  98. ldap_int_socket(LDAP *ld, int family, int type )
  99. {
  100.     ber_socket_t s = socket(family, type, 0);
  101.     osip_debug(ld, "ldap_new_socket: %d\n",s,0,0);
  102.     return ( s );
  103. }
  104.  
  105. static int
  106. ldap_pvt_close_socket(LDAP *ld, int s)
  107. {
  108.     osip_debug(ld, "ldap_close_socket: %d\n",s,0,0);
  109.     return tcp_close(s);
  110. }
  111.  
  112. static int
  113. ldap_int_prepare_socket(LDAP *ld, int s, int proto )
  114. {
  115.     osip_debug(ld, "ldap_prepare_socket: %d\n", s,0,0);
  116.  
  117. #ifdef TCP_NODELAY
  118.     if( proto == LDAP_PROTO_TCP ) {
  119.         int dummy = 1;
  120.         if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
  121.             (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
  122.         {
  123.             osip_debug(ld, "ldap_prepare_socket: "
  124.                 "setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
  125.                 s, 0, 0);
  126.         }
  127.     }
  128. #endif
  129.  
  130.     return 0;
  131. }
  132.  
  133. #undef TRACE
  134. #define TRACE do { \
  135.     osip_debug(ld, \
  136.         "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \
  137.         s, \
  138.         errno, \
  139.         sock_errstr(errno) ); \
  140. } while( 0 )
  141.  
  142. /*
  143.  * check the socket for errors after select returned.
  144.  */
  145. static int
  146. ldap_pvt_is_socket_ready(LDAP *ld, int s)
  147. {
  148.     osip_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
  149.  
  150. #if defined( notyet ) /* && defined( SO_ERROR ) */
  151. {
  152.     int so_errno;
  153.     int dummy = sizeof(so_errno);
  154.     if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
  155.         == AC_SOCKET_ERROR )
  156.     {
  157.         return -1;
  158.     }
  159.     if ( so_errno ) {
  160.         ldap_pvt_set_errno(so_errno);
  161.         TRACE;
  162.         return -1;
  163.     }
  164.     return 0;
  165. }
  166. #else
  167. {
  168.     /* error slippery */
  169.     struct sockaddr_in sin;
  170.     char ch;
  171.     int dummy = sizeof(sin);
  172.     if ( getpeername( s, (struct sockaddr *) &sin, &dummy )
  173.         == AC_SOCKET_ERROR )
  174.     {
  175.         /* XXX: needs to be replace with ber_stream_read() */
  176.         read(s, &ch, 1);
  177. #ifdef HAVE_WINSOCK
  178.         ldap_pvt_set_errno( WSAGetLastError() );
  179. #endif
  180.         TRACE;
  181.         return -1;
  182.     }
  183.     return 0;
  184. }
  185. #endif
  186.     return -1;
  187. }
  188. #undef TRACE
  189.  
  190. static int
  191. ldap_pvt_connect(LDAP *ld, ber_socket_t s,
  192.     struct sockaddr *sin, socklen_t addrlen,
  193.     int async)
  194. {
  195.     struct timeval    tv, *opt_tv=NULL;
  196.     fd_set        wfds, *z=NULL;
  197. #ifdef HAVE_WINSOCK
  198.     fd_set        efds;
  199. #endif
  200.  
  201.     if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) {
  202.         tv.tv_usec = opt_tv->tv_usec;
  203.         tv.tv_sec = opt_tv->tv_sec;
  204.     }
  205.  
  206.     osip_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n",
  207.             s, opt_tv ? tv.tv_sec : -1L, async);
  208.  
  209.     if ( ldap_pvt_ndelay_on(ld, s) == -1 )
  210.         return ( -1 );
  211.  
  212.     if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR )
  213.     {
  214.         if ( ldap_pvt_ndelay_off(ld, s) == -1 )
  215.             return ( -1 );
  216.         return ( 0 );
  217.     }
  218.  
  219. #ifdef HAVE_WINSOCK
  220.     ldap_pvt_set_errno( WSAGetLastError() );
  221. #endif
  222.  
  223.     if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
  224.         return ( -1 );
  225.     }
  226.     
  227. #ifdef notyet
  228.     if ( async ) return ( -2 );
  229. #endif
  230.  
  231.     FD_ZERO(&wfds);
  232.     FD_SET(s, &wfds );
  233.  
  234. #ifdef HAVE_WINSOCK
  235.     FD_ZERO(&efds);
  236.     FD_SET(s, &efds );
  237. #endif
  238.  
  239.     if ( select(ldap_int_tblsize, z, &wfds,
  240. #ifdef HAVE_WINSOCK
  241.             &efds,
  242. #else
  243.             z,
  244. #endif
  245.             opt_tv ? &tv : NULL) == AC_SOCKET_ERROR )
  246.     {
  247.         return ( -1 );
  248.     }
  249.  
  250. #ifdef HAVE_WINSOCK
  251.     /* This means the connection failed */
  252.     if ( FD_ISSET(s, &efds) ) {
  253.         ldap_pvt_set_errno(WSAECONNREFUSED);
  254.         osip_debug(ld, "ldap_pvt_connect: error on socket %d: "
  255.                "errno: %d (%s)\n", s, errno, sock_errstr(errno));
  256.         return -1;
  257.     }
  258. #endif
  259.     if ( FD_ISSET(s, &wfds) ) {
  260.         if ( ldap_pvt_is_socket_ready(ld, s) == -1 )
  261.             return ( -1 );
  262.         if ( ldap_pvt_ndelay_off(ld, s) == -1 )
  263.             return ( -1 );
  264.         return ( 0 );
  265.     }
  266.     osip_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0);
  267.     ldap_pvt_set_errno( ETIMEDOUT );
  268.     return ( -1 );
  269. }
  270.  
  271. #ifndef HAVE_INET_ATON
  272. int
  273. ldap_pvt_inet_aton( const char *host, struct in_addr *in)
  274. {
  275.     unsigned long u = inet_addr( host );
  276.     if ( u != 0xffffffff || u != (unsigned long) -1 ) {
  277.         in->s_addr = u;
  278.         return 1;
  279.     }
  280.     return 0;
  281. }
  282. #endif
  283.  
  284.  
  285. int
  286. ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
  287.     int proto,
  288.     const char *host,
  289.     unsigned long address, int port, int async)
  290. {
  291.     struct sockaddr_in    sin;
  292.     ber_socket_t        s = AC_SOCKET_INVALID;
  293.     int            rc, i, use_hp = 0;
  294.     struct hostent        *hp = NULL;
  295.     char               *ha_buf=NULL, *p, *q;
  296.  
  297.     osip_debug(ld, "ldap_connect_to_host: %s\n",host,0,0);
  298.     
  299.     if (host != NULL) {
  300. #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
  301.         char serv[7];
  302.         int err;
  303.         struct addrinfo hints, *res, *sai;
  304.  
  305.         memset( &hints, '\0', sizeof(hints) );
  306.         hints.ai_family = AF_UNSPEC;
  307.         hints.ai_socktype = SOCK_STREAM;
  308.  
  309.         snprintf(serv, sizeof serv, "%d", ntohs(port));
  310.         if ( err = getaddrinfo(host, serv, &hints, &res) ) {
  311.             osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n",
  312.                 AC_GAI_STRERROR(err), 0, 0);
  313.             return -1;
  314.         }
  315.         sai = res;
  316.         rc = -1;
  317.         do {
  318.             /* we assume AF_x and PF_x are equal for all x */
  319.             s = ldap_int_socket( ld, sai->ai_family, SOCK_STREAM );
  320.             if ( s == AC_SOCKET_INVALID ) {
  321.                 continue;
  322.             }
  323.  
  324.             if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) {
  325.                 ldap_pvt_close_socket(ld, s);
  326.                 break;
  327.             }
  328.  
  329.             switch (sai->ai_family) {
  330. #ifdef LDAP_PF_INET6
  331.             case AF_INET6: {
  332.                 char addr[INET6_ADDRSTRLEN];
  333.                 inet_ntop( AF_INET6,
  334.                     &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
  335.                     addr, sizeof addr);
  336.                 osip_debug(ld, "ldap_connect_to_host: Trying %s %s\n", 
  337.                     addr, serv, 0);
  338.             } break;
  339. #endif
  340.             case AF_INET: {
  341.                 char addr[INET_ADDRSTRLEN];
  342.                 inet_ntop( AF_INET,
  343.                     &((struct sockaddr_in *)sai->ai_addr)->sin_addr,
  344.                     addr, sizeof addr);
  345.                 osip_debug(ld, "ldap_connect_to_host: Trying %s:%s\n", 
  346.                     addr, serv, 0);
  347.             } break;
  348.             }
  349.  
  350.             rc = ldap_pvt_connect(ld, s, sai->ai_addr, sai->ai_addrlen, async);
  351.             if ( (rc == 0) || (rc == -2) ) {
  352.                 ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
  353.                 break;
  354.             }
  355.             ldap_pvt_close_socket(ld, s);
  356.         } while ((sai = sai->ai_next) != NULL);
  357.         freeaddrinfo(res);
  358.         return rc;
  359.  
  360. #else
  361.         struct in_addr in;
  362.         if (! inet_aton( host, &in) ) {
  363.             int local_h_errno;
  364.             struct hostent he_buf;
  365.             rc = ldap_pvt_gethostbyname_a(host, &he_buf, &ha_buf,
  366.                     &hp, &local_h_errno);
  367.  
  368.             if ( (rc < 0) || (hp == NULL) ) {
  369. #ifdef HAVE_WINSOCK
  370.                 ldap_pvt_set_errno( WSAGetLastError() );
  371. #else
  372.                 /* not exactly right, but... */
  373.                 ldap_pvt_set_errno( EHOSTUNREACH );
  374. #endif
  375.                 if (ha_buf) LDAP_FREE(ha_buf);
  376.                 return -1;
  377.             }
  378.             use_hp = 1;
  379.         }
  380.         address = in.s_addr;
  381. #endif
  382.     }
  383.  
  384.     rc = s = -1;
  385.     for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
  386.  
  387.         s = ldap_int_socket( ld, PF_INET, SOCK_STREAM );
  388.         if ( s == AC_SOCKET_INVALID ) {
  389.             /* use_hp ? continue : break; */
  390.             break;
  391.         }
  392.        
  393.         if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
  394.             ldap_pvt_close_socket(ld, s);
  395.             break;
  396.         }
  397.  
  398.         (void)memset((char *)&sin, '\0', sizeof(struct sockaddr_in));
  399.         sin.sin_family = AF_INET;
  400.         sin.sin_port = port;
  401.         p = (char *)&sin.sin_addr;
  402.         q = use_hp ? (char *)hp->h_addr_list[i] : (char *)&address;
  403.         AC_MEMCPY(p, q, sizeof(sin.sin_addr) );
  404.  
  405.         osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 
  406.                 inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),0);
  407.  
  408.         rc = ldap_pvt_connect(ld, s,
  409.             (struct sockaddr *)&sin, sizeof(struct sockaddr_in),
  410.             async);
  411.    
  412.         if ( (rc == 0) || (rc == -2) ) {
  413.             ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
  414.             break;
  415.         }
  416.  
  417.         ldap_pvt_close_socket(ld, s);
  418.  
  419.         if (!use_hp)
  420.             break;
  421.     }
  422.     if (ha_buf) LDAP_FREE(ha_buf);
  423.     return rc;
  424. }
  425.  
  426. #if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND ) || \
  427.     defined( HAVE_CYRUS_SASL )
  428. char *
  429. ldap_host_connected_to( Sockbuf *sb )
  430. {
  431.     struct hostent    *hp;
  432.     socklen_t        len;
  433.     struct sockaddr    sa;
  434.     char            *addr;
  435.     char            *host;
  436.  
  437.        /* buffers for gethostbyaddr_r */
  438.        struct hostent    he_buf;
  439.     int                local_h_errno;
  440.        char            *ha_buf=NULL;
  441.     ber_socket_t    sd;
  442.  
  443.     (void)memset( (char *)&sa, '\0', sizeof( struct sockaddr ));
  444.     len = sizeof( sa );
  445.  
  446.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  447.     if ( getpeername( sd, &sa, &len ) == -1 ) {
  448.         return( NULL );
  449.     }
  450.  
  451.     /*
  452.      * do a reverse lookup on the addr to get the official hostname.
  453.      * this is necessary for kerberos to work right, since the official
  454.      * hostname is used as the kerberos instance.
  455.      */
  456.  
  457.     switch (sa.sa_family) {
  458. #ifdef LDAP_PF_LOCAL
  459.     case AF_LOCAL:
  460.         return LDAP_STRDUP( ldap_int_hostname );
  461. #endif
  462. #ifdef LDAP_PF_INET6
  463.     case AF_INET6:
  464.         addr = (char *) &((struct sockaddr_in6 *)&sa)->sin6_addr;
  465.         len = sizeof( struct in6_addr );
  466.         break;
  467. #endif
  468.     case AF_INET:
  469.         addr = (char *) &((struct sockaddr_in *)&sa)->sin_addr;
  470.         len = sizeof( struct in_addr );
  471.  
  472.         {
  473.             struct sockaddr_in localhost;
  474.             localhost.sin_addr.s_addr = htonl( INADDR_ANY );
  475.  
  476.             if( memcmp ( &localhost.sin_addr,
  477.                 &((struct sockaddr_in *)&sa)->sin_addr,
  478.                 sizeof(localhost.sin_addr) ) == 0 )
  479.             {
  480.                 return LDAP_STRDUP( ldap_int_hostname );
  481.             }
  482.  
  483. #ifdef INADDR_LOOPBACK
  484.             localhost.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
  485.  
  486.             if( memcmp ( &localhost.sin_addr,
  487.                 &((struct sockaddr_in *)&sa)->sin_addr,
  488.                 sizeof(localhost.sin_addr) ) == 0 )
  489.             {
  490.                 return LDAP_STRDUP( ldap_int_hostname );
  491.             }
  492. #endif
  493.         }
  494.         break;
  495.  
  496.     default:
  497.         return( NULL );
  498.         break;
  499.     }
  500.  
  501.     host = NULL;
  502.     if ((ldap_pvt_gethostbyaddr_a( addr, len,
  503.         sa.sa_family, &he_buf, &ha_buf,
  504.         &hp,&local_h_errno ) == 0 ) &&
  505.         (hp != NULL) && ( hp->h_name != NULL ) )
  506.     {
  507.         host = LDAP_STRDUP( hp->h_name );   
  508.     }
  509.  
  510.     LDAP_FREE( ha_buf );
  511.     return host;
  512. }
  513. #endif
  514.  
  515.  
  516. /* for UNIX */
  517. struct selectinfo {
  518.     fd_set    si_readfds;
  519.     fd_set    si_writefds;
  520.     fd_set    si_use_readfds;
  521.     fd_set    si_use_writefds;
  522. };
  523.  
  524.  
  525. void
  526. ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
  527. {
  528.     struct selectinfo    *sip;
  529.     ber_socket_t        sd;
  530.  
  531.     sip = (struct selectinfo *)ld->ld_selectinfo;
  532.     
  533.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  534.     if ( !FD_ISSET( sd, &sip->si_writefds )) {
  535.         FD_SET( sd, &sip->si_writefds );
  536.     }
  537. }
  538.  
  539.  
  540. void
  541. ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
  542. {
  543.     struct selectinfo    *sip;
  544.     ber_socket_t        sd;
  545.  
  546.     sip = (struct selectinfo *)ld->ld_selectinfo;
  547.  
  548.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  549.     if ( !FD_ISSET( sd, &sip->si_readfds )) {
  550.         FD_SET( sd, &sip->si_readfds );
  551.     }
  552. }
  553.  
  554.  
  555. void
  556. ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
  557. {
  558.     struct selectinfo    *sip;
  559.     ber_socket_t        sd;
  560.  
  561.     sip = (struct selectinfo *)ld->ld_selectinfo;
  562.  
  563.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  564.     FD_CLR( sd, &sip->si_writefds );
  565.     FD_CLR( sd, &sip->si_readfds );
  566. }
  567.  
  568.  
  569. int
  570. ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
  571. {
  572.     struct selectinfo    *sip;
  573.     ber_socket_t        sd;
  574.  
  575.     sip = (struct selectinfo *)ld->ld_selectinfo;
  576.  
  577.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  578.     return( FD_ISSET( sd, &sip->si_use_writefds ));
  579. }
  580.  
  581.  
  582. int
  583. ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
  584. {
  585.     struct selectinfo    *sip;
  586.     ber_socket_t        sd;
  587.  
  588.     sip = (struct selectinfo *)ld->ld_selectinfo;
  589.  
  590.     ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
  591.     return( FD_ISSET( sd, &sip->si_use_readfds ));
  592. }
  593.  
  594.  
  595. void *
  596. ldap_new_select_info( void )
  597. {
  598.     struct selectinfo    *sip;
  599.  
  600.     if (( sip = (struct selectinfo *)LDAP_CALLOC( 1,
  601.         sizeof( struct selectinfo ))) != NULL ) {
  602.         FD_ZERO( &sip->si_readfds );
  603.         FD_ZERO( &sip->si_writefds );
  604.     }
  605.  
  606.     return( (void *)sip );
  607. }
  608.  
  609.  
  610. void
  611. ldap_free_select_info( void *sip )
  612. {
  613.     LDAP_FREE( sip );
  614. }
  615.  
  616.  
  617. void
  618. ldap_int_ip_init( void )
  619. {
  620.     int tblsize;
  621. #if defined( HAVE_SYSCONF )
  622.     tblsize = sysconf( _SC_OPEN_MAX );
  623. #elif defined( HAVE_GETDTABLESIZE )
  624.     tblsize = getdtablesize();
  625. #else
  626.     tblsize = FD_SETSIZE;
  627. #endif /* !USE_SYSCONF */
  628.  
  629. #ifdef FD_SETSIZE
  630.     if( tblsize > FD_SETSIZE )
  631.         tblsize = FD_SETSIZE;
  632. #endif    /* FD_SETSIZE*/
  633.     ldap_int_tblsize = tblsize;
  634. }
  635.  
  636.  
  637. int
  638. do_ldap_select( LDAP *ld, struct timeval *timeout )
  639. {
  640.     struct selectinfo    *sip;
  641.  
  642.     Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
  643.  
  644.     if ( ldap_int_tblsize == 0 )
  645.         ldap_int_ip_init();
  646.  
  647.     sip = (struct selectinfo *)ld->ld_selectinfo;
  648.     sip->si_use_readfds = sip->si_readfds;
  649.     sip->si_use_writefds = sip->si_writefds;
  650.     
  651.     return( select( ldap_int_tblsize,
  652.                     &sip->si_use_readfds, &sip->si_use_writefds,
  653.                     NULL, timeout ));
  654. }
  655.