]> git.sur5r.net Git - openldap/blob - libraries/libldap/os-ip.c
ce1ab0e2a8cb925abc1c3fcd2842aa4e32f6a788
[openldap] / libraries / libldap / os-ip.c
1 /*
2  *  Copyright (c) 1995 Regents of the University of Michigan.
3  *  All rights reserved.
4  *
5  *  os-ip.c -- platform-specific TCP & UDP related code
6  */
7
8 #ifndef lint 
9 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
10 #endif
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #ifdef _WIN32
17 #include <io.h>
18 #include "msdos.h"
19 #else /* _WIN32 */
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #endif /* _WIN32 */
26 #ifdef _AIX
27 #include <sys/select.h>
28 #endif /* _AIX */
29 #ifdef VMS
30 #include "ucx_select.h"
31 #endif /* VMS */
32 #include "portable.h"
33 #include "lber.h"
34 #include "ldap.h"
35
36 #ifdef LDAP_REFERRALS
37 #ifdef USE_SYSCONF
38 #include <unistd.h>
39 #endif /* USE_SYSCONF */
40 #ifdef notyet
41 #ifdef NEED_FILIO
42 #include <sys/filio.h>
43 #else /* NEED_FILIO */
44 #include <sys/ioctl.h>
45 #endif /* NEED_FILIO */
46 #endif /* notyet */
47 #endif /* LDAP_REFERRALS */
48
49 #ifdef MACOS
50 #define tcp_close( s )          tcpclose( s )
51 #else /* MACOS */
52 #ifdef DOS
53 #ifdef PCNFS
54 #define tcp_close( s )          close( s )
55 #endif /* PCNFS */
56 #ifdef NCSA
57 #define tcp_close( s )          netclose( s ); netshut()
58 #endif /* NCSA */
59 #ifdef WINSOCK
60 #define tcp_close( s )          closesocket( s ); WSACleanup();
61 #endif /* WINSOCK */
62 #else /* DOS */
63 #define tcp_close( s )          close( s )
64 #endif /* DOS */
65 #endif /* MACOS */
66
67
68 int
69 connect_to_host( Sockbuf *sb, char *host, unsigned long address,
70         int port, int async )
71 /*
72  * if host == NULL, connect using address
73  * "address" and "port" must be in network byte order
74  * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
75  * async is only used ifdef LDAP_REFERRALS (non-0 means don't wait for connect)
76  * XXX async is not used yet!
77  */
78 {
79         int                     rc, i, s, connected, use_hp;
80         struct sockaddr_in      sin;
81         struct hostent          *hp;
82 #ifdef notyet
83 #ifdef LDAP_REFERRALS
84         int                     status; /* for ioctl call */
85 #endif /* LDAP_REFERRALS */
86 #endif /* notyet */
87
88         Debug( LDAP_DEBUG_TRACE, "connect_to_host: %s:%d\n",
89             ( host == NULL ) ? "(by address)" : host, ntohs( port ), 0 );
90
91         connected = use_hp = 0;
92
93         if ( host != NULL && ( address = inet_addr( host )) == -1 ) {
94                 if ( (hp = gethostbyname( host )) == NULL ) {
95                         errno = EHOSTUNREACH;   /* not exactly right, but... */
96                         return( -1 );
97                 }
98                 use_hp = 1;
99         }
100
101         rc = -1;
102         for ( i = 0; !use_hp || ( hp->h_addr_list[ i ] != 0 ); i++ ) {
103                 if (( s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
104                         return( -1 );
105                 }
106 #ifdef notyet
107 #ifdef LDAP_REFERRALS
108                 status = 1;
109                 if ( async && ioctl( s, FIONBIO, (caddr_t)&status ) == -1 ) {
110                         Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
111                             s, 0, 0 );
112                 }
113 #endif /* LDAP_REFERRALS */
114 #endif /* notyet */
115                 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
116                 sin.sin_family = AF_INET;
117                 sin.sin_port = port;
118                 SAFEMEMCPY( (char *) &sin.sin_addr.s_addr,
119                     ( use_hp ? (char *) hp->h_addr_list[ i ] :
120                     (char *) &address ), sizeof( sin.sin_addr.s_addr) );
121
122                 if ( connect( s, (struct sockaddr *)&sin,
123                     sizeof( struct sockaddr_in )) >= 0 ) {
124                         connected = 1;
125                         rc = 0;
126                         break;
127                 } else {
128 #ifdef notyet
129 #ifdef LDAP_REFERRALS
130 #ifdef EAGAIN
131                         if ( errno == EINPROGRESS || errno == EAGAIN ) {
132 #else /* EAGAIN */
133                         if ( errno == EINPROGRESS ) {
134 #endif /* EAGAIN */
135                                 Debug( LDAP_DEBUG_TRACE,
136                                         "connect would block...\n", 0, 0, 0 );
137                                 rc = -2;
138                                 break;
139                         }
140 #endif /* LDAP_REFERRALS */
141 #endif /* notyet */
142
143 #ifdef LDAP_DEBUG               
144                         if ( ldap_debug & LDAP_DEBUG_TRACE ) {
145                                 perror( (char *)inet_ntoa( sin.sin_addr ));
146                         }
147 #endif
148                         close( s );
149                         if ( !use_hp ) {
150                                 break;
151                         }
152                 }
153         }
154
155         sb->sb_sd = s;
156
157         if ( connected ) {
158 #ifdef notyet
159 #ifdef LDAP_REFERRALS
160                 status = 0;
161                 if ( !async && ioctl( s, FIONBIO, (caddr_t)&on ) == -1 ) {
162                         Debug( LDAP_DEBUG_ANY, "FIONBIO ioctl failed on %d\n",
163                             s, 0, 0 );
164                 }
165 #endif /* LDAP_REFERRALS */
166 #endif /* notyet */
167
168                 Debug( LDAP_DEBUG_TRACE, "sd %d connected to: %s\n",
169                     s, inet_ntoa( sin.sin_addr ), 0 );
170         }
171
172         return( rc );
173 }
174
175
176 void
177 close_connection( Sockbuf *sb )
178 {
179     tcp_close( sb->sb_sd );
180 }
181
182
183 #ifdef KERBEROS
184 char *
185 host_connected_to( Sockbuf *sb )
186 {
187         struct hostent          *hp;
188         char                    *p;
189         int                     len;
190         struct sockaddr_in      sin;
191
192         (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
193         len = sizeof( sin );
194         if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
195                 return( NULL );
196         }
197
198         /*
199          * do a reverse lookup on the addr to get the official hostname.
200          * this is necessary for kerberos to work right, since the official
201          * hostname is used as the kerberos instance.
202          */
203         if (( hp = gethostbyaddr( (char *) &sin.sin_addr,
204             sizeof( sin.sin_addr ), AF_INET )) != NULL ) {
205                 if ( hp->h_name != NULL ) {
206                         return( strdup( hp->h_name ));
207                 }
208         }
209
210         return( NULL );
211 }
212 #endif /* KERBEROS */
213
214
215 #ifdef LDAP_REFERRALS
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 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( sb->sb_sd, &sip->si_writefds )) {
233                 FD_SET( sb->sb_sd, &sip->si_writefds );
234         }
235 }
236
237
238 void
239 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( sb->sb_sd, &sip->si_readfds )) {
246                 FD_SET( sb->sb_sd, &sip->si_readfds );
247         }
248 }
249
250
251 void
252 mark_select_clear( LDAP *ld, Sockbuf *sb )
253 {
254         struct selectinfo       *sip;
255
256         sip = (struct selectinfo *)ld->ld_selectinfo;
257
258         FD_CLR( sb->sb_sd, &sip->si_writefds );
259         FD_CLR( sb->sb_sd, &sip->si_readfds );
260 }
261
262
263 int
264 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( sb->sb_sd, &sip->si_use_writefds ));
271 }
272
273
274 int
275 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( sb->sb_sd, &sip->si_use_readfds ));
282 }
283
284
285 void *
286 new_select_info()
287 {
288         struct selectinfo       *sip;
289
290         if (( sip = (struct selectinfo *)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 free_select_info( void *sip )
302 {
303         free( sip );
304 }
305
306
307 int
308 do_ldap_select( LDAP *ld, struct timeval *timeout )
309 {
310         struct selectinfo       *sip;
311         static int              tblsize;
312
313         Debug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
314
315         if ( tblsize == 0 ) {
316 #ifdef USE_SYSCONF
317                 tblsize = sysconf( _SC_OPEN_MAX );
318 #else /* USE_SYSCONF */
319                 tblsize = getdtablesize();
320 #endif /* USE_SYSCONF */
321         }
322
323         sip = (struct selectinfo *)ld->ld_selectinfo;
324         sip->si_use_readfds = sip->si_readfds;
325         sip->si_use_writefds = sip->si_writefds;
326         
327         return( select( tblsize, &sip->si_use_readfds, &sip->si_use_writefds,
328             NULL, timeout ));
329 }
330 #endif /* LDAP_REFERRALS */