]> git.sur5r.net Git - openldap/blob - libraries/libldap/os-ip.c
s/<stdlib.h>/<ac/stdlib.h>/
[openldap] / libraries / libldap / os-ip.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /*  Portions
6  *  Copyright (c) 1995 Regents of the University of Michigan.
7  *  All rights reserved.
8  *
9  *  os-ip.c -- platform-specific TCP & UDP related code
10  */
11
12 #include "portable.h"
13
14 #include <stdio.h>
15
16 #include <ac/stdlib.h>
17
18 #include <ac/errno.h>
19 #include <ac/socket.h>
20 #include <ac/string.h>
21 #include <ac/time.h>
22 #include <ac/unistd.h>
23
24 #ifdef HAVE_IO_H
25 #include <io.h>
26 #endif /* HAVE_IO_H */
27
28 #if defined( HAVE_SYS_FILIO_H )
29 #include <sys/filio.h>
30 #elif defined( HAVE_SYS_IOCTL_H )
31 #include <sys/ioctl.h>
32 #endif
33
34 #include "ldap-int.h"
35
36 int
37 ldap_connect_to_host( Sockbuf *sb, const char *host, unsigned long address,
38         int port, int async )
39 /*
40  * if host == NULL, connect using address
41  * "address" and "port" must be in network byte order
42  * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
43  * async is only used ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS (non-0 means don't wait for connect)
44  * XXX async is not used yet!
45  */
46 {
47         int                     rc, i, s = 0;
48         int                     connected, use_hp;
49         struct sockaddr_in      sin;
50         struct hostent          *hp = NULL;
51 #ifdef notyet
52         ioctl_t                 status; /* for ioctl call */
53 #endif /* notyet */
54    
55         /* buffers for ldap_pvt_gethostbyname_a */
56         struct hostent          he_buf;
57         int                     local_h_errno;
58         char                    *ha_buf=NULL;
59 #define DO_RETURN(x) if (ha_buf) LDAP_FREE(ha_buf); return (x);
60    
61         Debug( LDAP_DEBUG_TRACE, "ldap_connect_to_host: %s:%d\n",
62             ( host == NULL ) ? "(by address)" : host, (int) ntohs( (short) port ), 0 );
63
64         connected = use_hp = 0;
65
66         if ( host != NULL ) {
67             address = inet_addr( host );
68             /* This was just a test for -1 until OSF1 let inet_addr return
69                unsigned int, which is narrower than 'unsigned long address' */
70             if ( address == 0xffffffff || address == (unsigned long) -1 ) {
71                 if ( ( ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
72                         &hp, &local_h_errno) < 0) || (hp==NULL))
73                 {
74 #ifdef HAVE_WINSOCK
75                         errno = WSAGetLastError();
76 #else
77                         errno = EHOSTUNREACH;   /* not exactly right, but... */
78 #endif
79                         DO_RETURN( -1 );
80                 }
81                 use_hp = 1;
82             }
83         }
84
85         rc = -1;
86         for ( i = 0; !use_hp || ( hp->h_addr_list[ i ] != 0 ); i++ ) {
87                 if (( s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
88                         DO_RETURN( -1 );
89                 }
90 #ifdef notyet
91                 status = 1;
92                 if ( async && ioctl( s, FIONBIO, (caddr_t)&status ) == -1 ) {
93                         Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
94                             s, 0, 0 );
95                 }
96 #endif /* notyet */
97                 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
98                 sin.sin_family = AF_INET;
99                 sin.sin_port = port;
100                 SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
101                     ( use_hp ? (char *) hp->h_addr_list[ i ] :
102                     (char *) &address ), sizeof( sin.sin_addr.s_addr) );
103
104                 if ( connect( s, (struct sockaddr *)&sin,
105                     sizeof( struct sockaddr_in )) >= 0 ) {
106                         connected = 1;
107                         rc = 0;
108                         break;
109                 } else {
110 #ifdef HAVE_WINSOCK
111                         errno = WSAGetLastError();
112 #endif
113 #ifdef notyet
114 #ifdef EAGAIN
115                         if ( errno == EINPROGRESS || errno == EAGAIN ) {
116 #else /* EAGAIN */
117                         if ( errno == EINPROGRESS ) {
118 #endif /* EAGAIN */
119                                 Debug( LDAP_DEBUG_TRACE,
120                                         "connect would block...\n", 0, 0, 0 );
121                                 rc = -2;
122                                 break;
123                         }
124 #endif /* notyet */
125
126 #ifdef LDAP_DEBUG               
127                         if ( ldap_debug & LDAP_DEBUG_TRACE ) {
128                                 perror( (char *)inet_ntoa( sin.sin_addr ));
129                         }
130 #endif
131                         tcp_close( s );
132                         if ( !use_hp ) {
133                                 break;
134                         }
135                 }
136         }
137
138         ber_pvt_sb_set_desc( sb, s );           
139
140         if ( connected ) {
141            
142 #ifdef notyet
143                 status = 0;
144                 if ( !async && ioctl( s, FIONBIO, (caddr_t)&on ) == -1 ) {
145                         Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
146                             s, 0, 0 );
147                 }
148 #endif /* notyet */
149
150                 Debug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
151                     s, (char *) inet_ntoa( sin.sin_addr ), 0 );
152         }
153
154         DO_RETURN( rc );
155 }
156    
157 #undef DO_RETURN
158
159
160 void
161 ldap_close_connection( Sockbuf *sb )
162 {
163         ber_pvt_sb_close( sb );
164 }
165
166
167 #if defined( HAVE_KERBEROS ) || defined( HAVE_TLS )
168 char *
169 ldap_host_connected_to( Sockbuf *sb )
170 {
171         struct hostent          *hp;
172         char                    *p;
173         int                     len;
174         struct sockaddr_in      sin;
175
176         /* buffers for gethostbyaddr_r */
177         struct hostent          he_buf;
178         int                     local_h_errno;
179         char                    *ha_buf=NULL;
180 #define DO_RETURN(x) if (ha_buf) LDAP_FREE(ha_buf); return (x);
181    
182         (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
183         len = sizeof( sin );
184
185         if ( getpeername( ber_pvt_sb_get_desc(sb), (struct sockaddr *)&sin, &len ) == -1 ) {
186                 return( NULL );
187         }
188
189         /*
190          * do a reverse lookup on the addr to get the official hostname.
191          * this is necessary for kerberos to work right, since the official
192          * hostname is used as the kerberos instance.
193          */
194         if ((ldap_pvt_gethostbyaddr_a( (char *) &sin.sin_addr,
195                 sizeof( sin.sin_addr ), 
196                 AF_INET, &he_buf, &ha_buf,
197                 &hp,&local_h_errno ) ==0 ) && (hp != NULL) )
198         {
199                 if ( hp->h_name != NULL ) {
200                         char *host = LDAP_STRDUP( hp->h_name );   
201                         DO_RETURN( host );
202                 }
203         }
204
205         DO_RETURN( NULL );
206 }
207 #undef DO_RETURN   
208    
209 #endif /* HAVE_KERBEROS || HAVE_TLS */
210
211
212 /* for UNIX */
213 struct selectinfo {
214         fd_set  si_readfds;
215         fd_set  si_writefds;
216         fd_set  si_use_readfds;
217         fd_set  si_use_writefds;
218 };
219
220
221 void
222 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
223 {
224         struct selectinfo       *sip;
225
226         sip = (struct selectinfo *)ld->ld_selectinfo;
227         
228         if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_writefds )) {
229                 FD_SET( (u_int) sb->sb_sd, &sip->si_writefds );
230         }
231 }
232
233
234 void
235 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
236 {
237         struct selectinfo       *sip;
238
239         sip = (struct selectinfo *)ld->ld_selectinfo;
240
241         if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_readfds )) {
242                 FD_SET( (u_int) sb->sb_sd, &sip->si_readfds );
243         }
244 }
245
246
247 void
248 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
249 {
250         struct selectinfo       *sip;
251
252         sip = (struct selectinfo *)ld->ld_selectinfo;
253
254         FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_writefds );
255         FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_readfds );
256 }
257
258
259 int
260 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
261 {
262         struct selectinfo       *sip;
263
264         sip = (struct selectinfo *)ld->ld_selectinfo;
265
266         return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_writefds ));
267 }
268
269
270 int
271 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
272 {
273         struct selectinfo       *sip;
274
275         sip = (struct selectinfo *)ld->ld_selectinfo;
276
277         return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_readfds ));
278 }
279
280
281 void *
282 ldap_new_select_info( void )
283 {
284         struct selectinfo       *sip;
285
286         if (( sip = (struct selectinfo *)LDAP_CALLOC( 1,
287             sizeof( struct selectinfo ))) != NULL ) {
288                 FD_ZERO( &sip->si_readfds );
289                 FD_ZERO( &sip->si_writefds );
290         }
291
292         return( (void *)sip );
293 }
294
295
296 void
297 ldap_free_select_info( void *sip )
298 {
299         LDAP_FREE( sip );
300 }
301
302
303 int
304 do_ldap_select( LDAP *ld, struct timeval *timeout )
305 {
306         struct selectinfo       *sip;
307         static int              tblsize;
308
309         Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
310
311         if ( tblsize == 0 ) {
312 #if defined( HAVE_SYSCONF )
313                 tblsize = sysconf( _SC_OPEN_MAX );
314 #elif defined( HAVE_GETDTABLESIZE )
315                 tblsize = getdtablesize();
316 #else
317                 tblsize = FD_SETSIZE;
318 #endif /* !USE_SYSCONF */
319
320 #ifdef FD_SETSIZE
321                 if( tblsize > FD_SETSIZE ) {
322                         tblsize = FD_SETSIZE;
323                 }
324 #endif  /* FD_SETSIZE*/
325         }
326
327         sip = (struct selectinfo *)ld->ld_selectinfo;
328         sip->si_use_readfds = sip->si_readfds;
329         sip->si_use_writefds = sip->si_writefds;
330         
331         return( select( tblsize, &sip->si_use_readfds, &sip->si_use_writefds,
332             NULL, timeout ));
333 }