]> git.sur5r.net Git - openldap/blob - libraries/libldap/os-ip.c
fix test when slapo-memberof(5) built as module (ITS#5132)
[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-2007 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 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
43 #  ifdef LDAP_PF_INET6
44 int ldap_int_inet4or6 = AF_UNSPEC;
45 #  else
46 int ldap_int_inet4or6 = AF_INET;
47 #  endif
48 #endif
49
50 #ifdef LDAP_DEBUG
51
52 #define osip_debug(ld,fmt,arg1,arg2,arg3) \
53 do { \
54         ldap_log_printf(NULL, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
55 } while(0)
56
57 #else
58
59 #define osip_debug(ld,fmt,arg1,arg2,arg3) ((void)0)
60
61 #endif /* LDAP_DEBUG */
62
63 static void
64 ldap_pvt_set_errno(int err)
65 {
66         sock_errset(err);
67 }
68
69 int
70 ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src )
71 {
72         struct timeval *new;
73
74         assert( dest != NULL );
75
76         if (src == NULL) {
77                 *dest = NULL;
78                 return 0;
79         }
80
81         new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval));
82
83         if( new == NULL ) {
84                 *dest = NULL;
85                 return 1;
86         }
87
88         AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval));
89
90         *dest = new;
91         return 0;
92 }
93
94 static int
95 ldap_pvt_ndelay_on(LDAP *ld, int fd)
96 {
97         osip_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
98         return ber_pvt_socket_set_nonblock( fd, 1 );
99 }
100    
101 static int
102 ldap_pvt_ndelay_off(LDAP *ld, int fd)
103 {
104         osip_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
105         return ber_pvt_socket_set_nonblock( fd, 0 );
106 }
107
108 static ber_socket_t
109 ldap_int_socket(LDAP *ld, int family, int type )
110 {
111         ber_socket_t s = socket(family, type, 0);
112         osip_debug(ld, "ldap_new_socket: %d\n",s,0,0);
113         return ( s );
114 }
115
116 static int
117 ldap_pvt_close_socket(LDAP *ld, int s)
118 {
119         osip_debug(ld, "ldap_close_socket: %d\n",s,0,0);
120         return tcp_close(s);
121 }
122
123 static int
124 ldap_int_prepare_socket(LDAP *ld, int s, int proto )
125 {
126         osip_debug( ld, "ldap_prepare_socket: %d\n", s, 0, 0 );
127
128 #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY )
129         if ( proto == LDAP_PROTO_TCP ) {
130                 int dummy = 1;
131 #ifdef SO_KEEPALIVE
132                 if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE,
133                         (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
134                 {
135                         osip_debug( ld, "ldap_prepare_socket: "
136                                 "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
137                                 s, 0, 0 );
138                 }
139 #endif /* SO_KEEPALIVE */
140 #ifdef TCP_NODELAY
141                 if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
142                         (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR )
143                 {
144                         osip_debug( ld, "ldap_prepare_socket: "
145                                 "setsockopt(%d, TCP_NODELAY) failed (ignored).\n",
146                                 s, 0, 0 );
147                 }
148 #endif /* TCP_NODELAY */
149         }
150 #endif /* SO_KEEPALIVE || TCP_NODELAY */
151
152         return 0;
153 }
154
155 #ifndef HAVE_WINSOCK
156
157 #undef TRACE
158 #define TRACE do { \
159         osip_debug(ld, \
160                 "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \
161                 s, \
162                 errno, \
163                 sock_errstr(errno) ); \
164 } while( 0 )
165
166 /*
167  * check the socket for errors after select returned.
168  */
169 static int
170 ldap_pvt_is_socket_ready(LDAP *ld, int s)
171 {
172         osip_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
173
174 #if defined( notyet ) /* && defined( SO_ERROR ) */
175 {
176         int so_errno;
177         ber_socklen_t dummy = sizeof(so_errno);
178         if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
179                 == AC_SOCKET_ERROR )
180         {
181                 return -1;
182         }
183         if ( so_errno ) {
184                 ldap_pvt_set_errno(so_errno);
185                 TRACE;
186                 return -1;
187         }
188         return 0;
189 }
190 #else
191 {
192         /* error slippery */
193 #ifdef LDAP_PF_INET6
194         struct sockaddr_storage sin;
195 #else
196         struct sockaddr_in sin;
197 #endif
198         char ch;
199         ber_socklen_t dummy = sizeof(sin);
200         if ( getpeername( s, (struct sockaddr *) &sin, &dummy )
201                 == AC_SOCKET_ERROR )
202         {
203                 /* XXX: needs to be replace with ber_stream_read() */
204                 read(s, &ch, 1);
205                 TRACE;
206                 return -1;
207         }
208         return 0;
209 }
210 #endif
211         return -1;
212 }
213 #undef TRACE
214
215 #endif /* HAVE_WINSOCK */
216
217 /* NOTE: this is identical to analogous code in os-local.c */
218 int
219 ldap_int_poll(
220         LDAP *ld,
221         ber_socket_t s,
222         struct timeval *tvp )
223 {
224         int             rc;
225                 
226
227         osip_debug(ld, "ldap_int_poll: fd: %d tm: %ld\n",
228                 s, tvp ? tvp->tv_sec : -1L, 0);
229
230 #ifdef HAVE_POLL
231         {
232                 struct pollfd fd;
233                 int timeout = INFTIM;
234
235                 fd.fd = s;
236                 fd.events = POLL_WRITE;
237
238                 if ( tvp != NULL ) {
239                         timeout = TV2MILLISEC( tvp );
240                 }
241                 do {
242                         fd.revents = 0;
243                         rc = poll( &fd, 1, timeout );
244                 
245                 } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
246                         LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
247
248                 if ( rc == AC_SOCKET_ERROR ) {
249                         return rc;
250                 }
251
252                 if ( timeout == 0 && rc == 0 ) {
253                         return -2;
254                 }
255
256                 if ( fd.revents & POLL_WRITE ) {
257                         if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
258                                 return -1;
259                         }
260
261                         if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) {
262                                 return -1;
263                         }
264                         return 0;
265                 }
266         }
267 #else
268         {
269                 fd_set          wfds, *z = NULL;
270 #ifdef HAVE_WINSOCK
271                 fd_set          efds;
272 #endif
273                 struct timeval  tv = { 0 };
274
275 #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK )
276                 if ( s >= FD_SETSIZE ) {
277                         rc = AC_SOCKET_ERROR;
278                         tcp_close( s );
279                         ldap_pvt_set_errno( EMFILE );
280                         return rc;
281                 }
282 #endif
283
284                 if ( tvp != NULL ) {
285                         tv = *tvp;
286                 }
287
288                 do {
289                         FD_ZERO(&wfds);
290                         FD_SET(s, &wfds );
291
292 #ifdef HAVE_WINSOCK
293                         FD_ZERO(&efds);
294                         FD_SET(s, &efds );
295 #endif
296
297                         rc = select( ldap_int_tblsize, z, &wfds,
298 #ifdef HAVE_WINSOCK
299                                 &efds,
300 #else
301                                 z,
302 #endif
303                                 tvp ? &tv : NULL );
304                 } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
305                         LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
306
307                 if ( rc == AC_SOCKET_ERROR ) {
308                         return rc;
309                 }
310
311                 if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) {
312                         return -2;
313                 }
314
315 #ifdef HAVE_WINSOCK
316                 /* This means the connection failed */
317                 if ( FD_ISSET(s, &efds) ) {
318                         int so_errno;
319                         ber_socklen_t dummy = sizeof(so_errno);
320                         if ( getsockopt( s, SOL_SOCKET, SO_ERROR,
321                                 (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno )
322                         {
323                                 /* impossible */
324                                 so_errno = WSAGetLastError();
325                         }
326                         ldap_pvt_set_errno( so_errno );
327                         osip_debug(ld, "ldap_int_poll: error on socket %d: "
328                                "errno: %d (%s)\n", s, errno, sock_errstr( errno ));
329                         return -1;
330                 }
331 #endif
332                 if ( FD_ISSET(s, &wfds) ) {
333 #ifndef HAVE_WINSOCK
334                         if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
335                                 return -1;
336                         }
337 #endif
338                         if ( ldap_pvt_ndelay_off(ld, s) == -1 ) {
339                                 return -1;
340                         }
341                         return 0;
342                 }
343         }
344 #endif
345
346         osip_debug(ld, "ldap_int_poll: timed out\n",0,0,0);
347         ldap_pvt_set_errno( ETIMEDOUT );
348         return -1;
349 }
350
351 static int
352 ldap_pvt_connect(LDAP *ld, ber_socket_t s,
353         struct sockaddr *sin, ber_socklen_t addrlen,
354         int async)
355 {
356         int rc, err;
357         struct timeval  tv, *opt_tv = NULL;
358
359 #ifdef LDAP_CONNECTIONLESS
360         /* We could do a connect() but that would interfere with
361          * attempts to poll a broadcast address
362          */
363         if (LDAP_IS_UDP(ld)) {
364                 if (ld->ld_options.ldo_peer)
365                         ldap_memfree(ld->ld_options.ldo_peer);
366                 ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr));
367                 AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr));
368                 return ( 0 );
369         }
370 #endif
371         if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
372                 tv = ld->ld_options.ldo_tm_net;
373                 opt_tv = &tv;
374         }
375
376         osip_debug(ld, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n",
377                         s, opt_tv ? tv.tv_sec : -1L, async);
378
379         if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 )
380                 return ( -1 );
381
382         if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) {
383                 if ( opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 )
384                         return ( -1 );
385                 return ( 0 );
386         }
387
388         err = sock_errno();
389         if ( err != EINPROGRESS && err != EWOULDBLOCK ) {
390                 return ( -1 );
391         }
392         
393         if ( async ) {
394                 /* caller will call ldap_int_poll() as appropriate? */
395                 return ( -2 );
396         }
397
398         rc = ldap_int_poll( ld, s, opt_tv );
399
400         osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0);
401
402         return rc;
403 }
404
405 #ifndef HAVE_INET_ATON
406 int
407 ldap_pvt_inet_aton( const char *host, struct in_addr *in)
408 {
409         unsigned long u = inet_addr( host );
410
411 #ifdef INADDR_NONE
412         if ( u == INADDR_NONE ) return 0;
413 #endif
414         if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0;
415
416         in->s_addr = u;
417         return 1;
418 }
419 #endif
420
421
422 int
423 ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
424         int proto,
425         const char *host, int port,
426         int async )
427 {
428         int     rc;
429         int     socktype;
430         ber_socket_t            s = AC_SOCKET_INVALID;
431
432 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
433         char serv[7];
434         int err;
435         struct addrinfo hints, *res, *sai;
436 #else
437         int i;
438         int use_hp = 0;
439         struct hostent *hp = NULL;
440         struct hostent he_buf;
441         struct in_addr in;
442         char *ha_buf=NULL;
443 #endif
444
445         if( host == NULL ) host = "localhost";
446         
447         switch(proto) {
448         case LDAP_PROTO_TCP: socktype = SOCK_STREAM;
449                 osip_debug( ld,
450                         "ldap_connect_to_host: TCP %s:%d\n",
451                         host, port, 0);
452                 break;
453         case LDAP_PROTO_UDP: socktype = SOCK_DGRAM;
454                 osip_debug( ld,
455                         "ldap_connect_to_host: UDP %s:%d\n",
456                         host, port, 0);
457                 break;
458         default:
459                 osip_debug( ld, "ldap_connect_to_host: unknown proto: %d\n",
460                         proto, 0, 0 );
461                 return -1;
462         }
463
464 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
465         memset( &hints, '\0', sizeof(hints) );
466 #ifdef USE_AI_ATTRCONFIG /* FIXME: configure test needed */
467         /* Use AI_ATTRCONFIG only on systems where its known to be needed. */
468         hints.ai_flags = AI_ATTRCONFIG;
469 #endif
470         hints.ai_family = ldap_int_inet4or6;
471         hints.ai_socktype = socktype;
472         snprintf(serv, sizeof serv, "%d", port );
473
474 #ifdef LDAP_R_COMPILE
475         /* most getaddrinfo(3) use non-threadsafe resolver libraries */
476         ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex);
477 #endif
478
479         err = getaddrinfo( host, serv, &hints, &res );
480
481 #ifdef LDAP_R_COMPILE
482         ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex);
483 #endif
484
485         if ( err != 0 ) {
486                 osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n",
487                         AC_GAI_STRERROR(err), 0, 0);
488                 return -1;
489         }
490         rc = -1;
491
492         for( sai=res; sai != NULL; sai=sai->ai_next) {
493                 if( sai->ai_addr == NULL ) {
494                         osip_debug(ld, "ldap_connect_to_host: getaddrinfo "
495                                 "ai_addr is NULL?\n", 0, 0, 0);
496                         continue;
497                 }
498
499                 /* we assume AF_x and PF_x are equal for all x */
500                 s = ldap_int_socket( ld, sai->ai_family, socktype );
501                 if ( s == AC_SOCKET_INVALID ) {
502                         continue;
503                 }
504
505                 if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) {
506                         ldap_pvt_close_socket(ld, s);
507                         break;
508                 }
509
510                 switch (sai->ai_family) {
511 #ifdef LDAP_PF_INET6
512                         case AF_INET6: {
513                                 char addr[INET6_ADDRSTRLEN];
514                                 inet_ntop( AF_INET6,
515                                         &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr,
516                                         addr, sizeof addr);
517                                 osip_debug(ld, "ldap_connect_to_host: Trying %s %s\n", 
518                                         addr, serv, 0);
519                         } break;
520 #endif
521                         case AF_INET: {
522                                 char addr[INET_ADDRSTRLEN];
523                                 inet_ntop( AF_INET,
524                                         &((struct sockaddr_in *)sai->ai_addr)->sin_addr,
525                                         addr, sizeof addr);
526                                 osip_debug(ld, "ldap_connect_to_host: Trying %s:%s\n", 
527                                         addr, serv, 0);
528                         } break;
529                 }
530
531                 rc = ldap_pvt_connect( ld, s,
532                         sai->ai_addr, sai->ai_addrlen, async );
533                 if ( rc == 0 || rc == -2 ) {
534                         ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
535                         break;
536                 }
537                 ldap_pvt_close_socket(ld, s);
538         }
539         freeaddrinfo(res);
540
541 #else
542         if (! inet_aton( host, &in ) ) {
543                 int local_h_errno;
544                 rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
545                         &hp, &local_h_errno );
546
547                 if ( (rc < 0) || (hp == NULL) ) {
548 #ifdef HAVE_WINSOCK
549                         ldap_pvt_set_errno( WSAGetLastError() );
550 #else
551                         /* not exactly right, but... */
552                         ldap_pvt_set_errno( EHOSTUNREACH );
553 #endif
554                         if (ha_buf) LDAP_FREE(ha_buf);
555                         return -1;
556                 }
557
558                 use_hp = 1;
559         }
560
561         rc = s = -1;
562         for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
563                 struct sockaddr_in      sin;
564
565                 s = ldap_int_socket( ld, PF_INET, socktype );
566                 if ( s == AC_SOCKET_INVALID ) {
567                         /* use_hp ? continue : break; */
568                         break;
569                 }
570            
571                 if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
572                         ldap_pvt_close_socket(ld, s);
573                         break;
574                 }
575
576                 (void)memset((char *)&sin, '\0', sizeof sin);
577                 sin.sin_family = AF_INET;
578                 sin.sin_port = htons((short) port);
579
580                 if( use_hp ) {
581                         AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i],
582                                 sizeof(sin.sin_addr) );
583                 } else {
584                         AC_MEMCPY( &sin.sin_addr, &in.s_addr,
585                                 sizeof(sin.sin_addr) );
586                 }
587
588 #ifdef HAVE_INET_NTOA_B
589                 {
590                         /* for VxWorks */
591                         char address[INET_ADDR_LEN];
592                         inet_ntoa_b(sin.sin_address, address);
593                         osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 
594                                 address, port, 0);
595                 }
596 #else
597                 osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 
598                         inet_ntoa(sin.sin_addr), port, 0);
599 #endif
600
601                 rc = ldap_pvt_connect(ld, s,
602                         (struct sockaddr *)&sin, sizeof(sin),
603                         async);
604    
605                 if ( (rc == 0) || (rc == -2) ) {
606                         ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
607                         break;
608                 }
609
610                 ldap_pvt_close_socket(ld, s);
611
612                 if (!use_hp) break;
613         }
614         if (ha_buf) LDAP_FREE(ha_buf);
615 #endif
616
617         return rc;
618 }
619
620 #if defined( HAVE_CYRUS_SASL )
621 char *
622 ldap_host_connected_to( Sockbuf *sb, const char *host )
623 {
624         ber_socklen_t   len;
625 #ifdef LDAP_PF_INET6
626         struct sockaddr_storage sabuf;
627 #else
628         struct sockaddr sabuf;
629 #endif
630         struct sockaddr *sa = (struct sockaddr *) &sabuf;
631         ber_socket_t    sd;
632
633         (void)memset( (char *)sa, '\0', sizeof sabuf );
634         len = sizeof sabuf;
635
636         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
637         if ( getpeername( sd, sa, &len ) == -1 ) {
638                 return( NULL );
639         }
640
641         /*
642          * do a reverse lookup on the addr to get the official hostname.
643          * this is necessary for kerberos to work right, since the official
644          * hostname is used as the kerberos instance.
645          */
646
647         switch (sa->sa_family) {
648 #ifdef LDAP_PF_LOCAL
649         case AF_LOCAL:
650                 return LDAP_STRDUP( ldap_int_hostname );
651 #endif
652 #ifdef LDAP_PF_INET6
653         case AF_INET6:
654                 {
655                         struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT;
656                         if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr,
657                                 &localhost, sizeof(localhost)) == 0 )
658                         {
659                                 return LDAP_STRDUP( ldap_int_hostname );
660                         }
661                 }
662                 break;
663 #endif
664         case AF_INET:
665                 {
666                         struct in_addr localhost;
667                         localhost.s_addr = htonl( INADDR_ANY );
668
669                         if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
670                                 &localhost, sizeof(localhost) ) == 0 )
671                         {
672                                 return LDAP_STRDUP( ldap_int_hostname );
673                         }
674
675 #ifdef INADDR_LOOPBACK
676                         localhost.s_addr = htonl( INADDR_LOOPBACK );
677
678                         if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
679                                 &localhost, sizeof(localhost) ) == 0 )
680                         {
681                                 return LDAP_STRDUP( ldap_int_hostname );
682                         }
683 #endif
684                 }
685                 break;
686
687         default:
688                 return( NULL );
689                 break;
690         }
691
692         {
693                 char *herr;
694 #ifdef NI_MAXHOST
695                 char hbuf[NI_MAXHOST];
696 #elif defined( MAXHOSTNAMELEN
697                 char hbuf[MAXHOSTNAMELEN];
698 #else
699                 char hbuf[256];
700 #endif
701                 hbuf[0] = 0;
702
703                 if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0
704                         && hbuf[0] ) 
705                 {
706                         return LDAP_STRDUP( hbuf );   
707                 }
708         }
709
710         return host ? LDAP_STRDUP( host ) : NULL;
711 }
712 #endif
713
714
715 struct selectinfo {
716 #ifdef HAVE_POLL
717         /* for UNIX poll(2) */
718         int si_maxfd;
719         struct pollfd si_fds[FD_SETSIZE];
720 #else
721         /* for UNIX select(2) */
722         fd_set  si_readfds;
723         fd_set  si_writefds;
724         fd_set  si_use_readfds;
725         fd_set  si_use_writefds;
726 #endif
727 };
728
729 void
730 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
731 {
732         struct selectinfo       *sip;
733         ber_socket_t            sd;
734
735         sip = (struct selectinfo *)ld->ld_selectinfo;
736         
737         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
738
739 #ifdef HAVE_POLL
740         /* for UNIX poll(2) */
741         {
742                 int empty=-1;
743                 int i;
744                 for(i=0; i < sip->si_maxfd; i++) {
745                         if( sip->si_fds[i].fd == sd ) {
746                                 sip->si_fds[i].events |= POLL_WRITE;
747                                 return;
748                         }
749                         if( empty==-1 && sip->si_fds[i].fd == -1 ) {
750                                 empty=i;
751                         }
752                 }
753
754                 if( empty == -1 ) {
755                         if( sip->si_maxfd >= FD_SETSIZE ) {
756                                 /* FIXME */
757                                 return;
758                         }
759                         empty = sip->si_maxfd++;
760                 }
761
762                 sip->si_fds[empty].fd = sd;
763                 sip->si_fds[empty].events = POLL_WRITE;
764         }
765 #else
766         /* for UNIX select(2) */
767         if ( !FD_ISSET( sd, &sip->si_writefds )) {
768                 FD_SET( sd, &sip->si_writefds );
769         }
770 #endif
771 }
772
773
774 void
775 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
776 {
777         struct selectinfo       *sip;
778         ber_socket_t            sd;
779
780         sip = (struct selectinfo *)ld->ld_selectinfo;
781
782         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
783
784 #ifdef HAVE_POLL
785         /* for UNIX poll(2) */
786         {
787                 int empty=-1;
788                 int i;
789                 for(i=0; i < sip->si_maxfd; i++) {
790                         if( sip->si_fds[i].fd == sd ) {
791                                 sip->si_fds[i].events |= POLL_READ;
792                                 return;
793                         }
794                         if( empty==-1 && sip->si_fds[i].fd == -1 ) {
795                                 empty=i;
796                         }
797                 }
798
799                 if( empty == -1 ) {
800                         if( sip->si_maxfd >= FD_SETSIZE ) {
801                                 /* FIXME */
802                                 return;
803                         }
804                         empty = sip->si_maxfd++;
805                 }
806
807                 sip->si_fds[empty].fd = sd;
808                 sip->si_fds[empty].events = POLL_READ;
809         }
810 #else
811         /* for UNIX select(2) */
812         if ( !FD_ISSET( sd, &sip->si_readfds )) {
813                 FD_SET( sd, &sip->si_readfds );
814         }
815 #endif
816 }
817
818
819 void
820 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
821 {
822         struct selectinfo       *sip;
823         ber_socket_t            sd;
824
825         sip = (struct selectinfo *)ld->ld_selectinfo;
826
827         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
828
829 #ifdef HAVE_POLL
830         /* for UNIX poll(2) */
831         {
832                 int i;
833                 for(i=0; i < sip->si_maxfd; i++) {
834                         if( sip->si_fds[i].fd == sd ) {
835                                 sip->si_fds[i].fd = -1;
836                         }
837                 }
838         }
839 #else
840         /* for UNIX select(2) */
841         FD_CLR( sd, &sip->si_writefds );
842         FD_CLR( sd, &sip->si_readfds );
843 #endif
844 }
845
846
847 int
848 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
849 {
850         struct selectinfo       *sip;
851         ber_socket_t            sd;
852
853         sip = (struct selectinfo *)ld->ld_selectinfo;
854
855         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
856
857 #ifdef HAVE_POLL
858         /* for UNIX poll(2) */
859         {
860                 int i;
861                 for(i=0; i < sip->si_maxfd; i++) {
862                         if( sip->si_fds[i].fd == sd ) {
863                                 return sip->si_fds[i].revents & POLL_WRITE;
864                         }
865                 }
866
867                 return 0;
868         }
869 #else
870         /* for UNIX select(2) */
871         return( FD_ISSET( sd, &sip->si_use_writefds ));
872 #endif
873 }
874
875
876 int
877 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
878 {
879         struct selectinfo       *sip;
880         ber_socket_t            sd;
881
882         sip = (struct selectinfo *)ld->ld_selectinfo;
883
884         ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
885
886 #ifdef HAVE_POLL
887         /* for UNIX poll(2) */
888         {
889                 int i;
890                 for(i=0; i < sip->si_maxfd; i++) {
891                         if( sip->si_fds[i].fd == sd ) {
892                                 return sip->si_fds[i].revents & POLL_READ;
893                         }
894                 }
895
896                 return 0;
897         }
898 #else
899         /* for UNIX select(2) */
900         return( FD_ISSET( sd, &sip->si_use_readfds ));
901 #endif
902 }
903
904
905 void *
906 ldap_new_select_info( void )
907 {
908         struct selectinfo       *sip;
909
910         sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo ));
911
912         if ( sip == NULL ) return NULL;
913
914 #ifdef HAVE_POLL
915         /* for UNIX poll(2) */
916         /* sip->si_maxfd=0 */
917 #else
918         /* for UNIX select(2) */
919         FD_ZERO( &sip->si_readfds );
920         FD_ZERO( &sip->si_writefds );
921 #endif
922
923         return( (void *)sip );
924 }
925
926
927 void
928 ldap_free_select_info( void *sip )
929 {
930         LDAP_FREE( sip );
931 }
932
933
934 #ifndef HAVE_POLL
935 int ldap_int_tblsize = 0;
936
937 void
938 ldap_int_ip_init( void )
939 {
940 #if defined( HAVE_SYSCONF )
941         long tblsize = sysconf( _SC_OPEN_MAX );
942         if( tblsize > INT_MAX ) tblsize = INT_MAX;
943
944 #elif defined( HAVE_GETDTABLESIZE )
945         int tblsize = getdtablesize();
946 #else
947         int tblsize = FD_SETSIZE;
948 #endif /* !USE_SYSCONF */
949
950 #ifdef FD_SETSIZE
951         if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE;
952 #endif  /* FD_SETSIZE */
953
954         ldap_int_tblsize = tblsize;
955 }
956 #endif
957
958
959 int
960 ldap_int_select( LDAP *ld, struct timeval *timeout )
961 {
962         int rc;
963         struct selectinfo       *sip;
964
965         Debug( LDAP_DEBUG_TRACE, "ldap_int_select\n", 0, 0, 0 );
966
967 #ifndef HAVE_POLL
968         if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
969 #endif
970
971         sip = (struct selectinfo *)ld->ld_selectinfo;
972         assert( sip != NULL );
973
974 #ifdef HAVE_POLL
975         {
976                 int to = timeout ? TV2MILLISEC( timeout ) : INFTIM;
977                 rc = poll( sip->si_fds, sip->si_maxfd, to );
978         }
979 #else
980         sip->si_use_readfds = sip->si_readfds;
981         sip->si_use_writefds = sip->si_writefds;
982         
983         rc = select( ldap_int_tblsize,
984                 &sip->si_use_readfds, &sip->si_use_writefds,
985                 NULL, timeout );
986 #endif
987
988         return rc;
989 }