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