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