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