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