1 /*
2 * Copyright (c) 1995-2001 by Sun Microsystems, Inc.
3 * All rights reserved.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * Copyright (c) 1995 Regents of the University of Michigan.
10 * All rights reserved.
11 *
12 * os-ip.c -- platform-specific TCP & UDP related code
13 */
14
15 #ifndef lint
16 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
17 #endif
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <arpa/inet.h>
23
24 #ifdef _WIN32
25 #include <io.h>
26 #include "msdos.h"
27 #else /* _WIN32 */
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #endif /* _WIN32 */
34 #ifdef _AIX
35 #include <sys/select.h>
36 #endif /* _AIX */
37 #ifdef VMS
38 #include "ucx_select.h"
39 #endif /* VMS */
40 #include "portable.h"
41 #include "lber.h"
42 #include "ldap.h"
43 #include "ldap-private.h"
44 #include "ldap-int.h"
45
46 #ifdef LDAP_REFERRALS
47 #ifdef USE_SYSCONF
48 #include <unistd.h>
49 #endif /* USE_SYSCONF */
50 #ifdef notyet
51 #ifdef NEED_FILIO
52 #include <sys/filio.h>
53 #else /* NEED_FILIO */
54 #include <sys/ioctl.h>
55 #endif /* NEED_FILIO */
56 #endif /* notyet */
57 #endif /* LDAP_REFERRALS */
58
59 #ifdef MACOS
60 #define tcp_close(s) tcpclose(s)
61 #else /* MACOS */
62 #ifdef DOS
63 #ifdef PCNFS
64 #define tcp_close(s) close(s)
65 #endif /* PCNFS */
66 #ifdef NCSA
67 #define tcp_close(s) netclose(s); netshut()
68 #endif /* NCSA */
69 #ifdef WINSOCK
70 #define tcp_close(s) closesocket(s); WSACleanup();
71 #endif /* WINSOCK */
72 #else /* DOS */
73 #define tcp_close(s) close(s)
74 #endif /* DOS */
75 #endif /* MACOS */
76 #ifdef SUN
77 #include <nss_dbdefs.h>
78 #endif
79
80 #include <fcntl.h>
81 #include <sys/poll.h>
82
83
84 /*
85 * Do an async connect or blocking connect depending on the timeout
86 * value. LDAP_X_IO_TIMEOUT_NO_TIMEOUT means do a blocking connect.
87 * Otherwise wait for timeout milliseconds for the connection.
88 * Returns 0 on success and -1 on failure.
89 */
90 static int
do_connect(int s,struct sockaddr * sin,int timeout)91 do_connect(int s, struct sockaddr *sin, int timeout)
92 {
93 int flags, connected = 0;
94 int retval, error, n;
95 fd_set wfds;
96 struct timeval waittime, *sel_timeout;
97
98 /* set the socket to do non-blocking i/o */
99 flags = fcntl(s, F_GETFL, 0);
100 fcntl(s, F_SETFL, flags | O_NONBLOCK);
101
102 if (connect(s, sin, sizeof (struct sockaddr_in)) == 0) {
103 connected = 1;
104 } else if (errno == EINPROGRESS) {
105 /* if NO_TIMEOUT is specified do a blocking connect */
106 if (timeout <= LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
107 sel_timeout = NULL;
108 } else {
109 /* set the timeout to the specified value */
110 waittime.tv_sec = timeout / MILLISEC;
111 waittime.tv_usec = (timeout % MILLISEC) * 1000;
112 sel_timeout = &waittime;
113 }
114
115 FD_ZERO(&wfds);
116 FD_SET(s, &wfds);
117 n = sizeof (error);
118 if (select(s+1, NULL, &wfds, NULL, sel_timeout) > 0 &&
119 FD_ISSET(s, &wfds) &&
120 getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &n) == 0 &&
121 error == 0) {
122 connected = 1;
123 }
124 }
125
126 /* if we are connected restore the flags for the socket */
127 if (connected) {
128 fcntl(s, F_SETFL, flags);
129 }
130
131 return (connected ? 0 : -1);
132 }
133
134
135 int
connect_to_host(Sockbuf * sb,char * host,in_addr_t address,int port,int async,int timeout)136 connect_to_host(Sockbuf *sb, char *host, in_addr_t address,
137 int port, int async, int timeout)
138 /*
139 * if host == NULL, connect using address
140 * "address" and "port" must be in network byte order
141 * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
142 * async is only used ifdef LDAP_REFERRALS (non-0 means don't wait for connect)
143 * XXX async is not used yet!
144 */
145 {
146 int rc, i, s, connected, use_hp;
147 struct sockaddr_in sin;
148 struct hostent *hp;
149 #ifdef notyet
150 #ifdef LDAP_REFERRALS
151 int status; /* for ioctl call */
152 #endif /* LDAP_REFERRALS */
153 #endif /* notyet */
154 #ifdef SUN
155 struct hostent hpret;
156 char hpbuf[NSS_BUFLEN_HOSTS];
157 int hperrno;
158 #endif
159
160 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 201, "connect_to_host: "
161 "%1$s:%2$d\n"), (host == NULL) ? catgets(slapdcat, 1, 202,
162 "(by address)") : host, ntohs(port), 0);
163
164 connected = use_hp = 0;
165
166 if (host != NULL && (address = inet_addr(host)) == -1) {
167 #ifdef SUN
168 if ((hp = gethostbyname_r(host, &hpret, hpbuf,
169 NSS_BUFLEN_HOSTS, &hperrno)) == NULL) {
170 #else
171 if ((hp = gethostbyname(host)) == NULL) {
172 #endif
173 errno = EHOSTUNREACH; /* not exactly right, but... */
174 return (-1);
175 }
176 use_hp = 1;
177 }
178
179 rc = -1;
180 for (i = 0; !use_hp || (hp->h_addr_list[i] != 0); i++) {
181 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
182 return (-1);
183 }
184 #ifdef notyet
185 #ifdef LDAP_REFERRALS
186 status = 1;
187 if (async && ioctl(s, FIONBIO, (caddr_t)&status) == -1) {
188 Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 203,
189 "FIONBIO ioctl failed on %d\n"), s, 0, 0);
190 }
191 #endif /* LDAP_REFERRALS */
192 #endif /* notyet */
193 (void) memset((char *)&sin, 0, sizeof (struct sockaddr_in));
194 sin.sin_family = AF_INET;
195 sin.sin_port = port;
196 SAFEMEMCPY((char *) &sin.sin_addr.s_addr,
197 (use_hp ? (char *) hp->h_addr_list[i] :
198 (char *)&address), sizeof (sin.sin_addr.s_addr));
199
200 if (do_connect(s, (struct sockaddr *)&sin, timeout) == 0) {
201 connected = 1;
202 break;
203 }
204
205 #ifdef notyet
206 #ifdef LDAP_REFERRALS
207 #ifdef EAGAIN
208 if (errno == EINPROGRESS || errno == EAGAIN) {
209 #else /* EAGAIN */
210 if (errno == EINPROGRESS) {
211 #endif /* EAGAIN */
212 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 204,
213 "connect would block...\n"), 0, 0, 0);
214 rc = -2;
215 break;
216 }
217 #endif /* LDAP_REFERRALS */
218 #endif /* notyet */
219
220 #ifdef LDAP_DEBUG
221 if (ldap_debug & LDAP_DEBUG_TRACE) {
222 perror((char *)inet_ntoa(sin.sin_addr));
223 }
224 #endif
225 close(s);
226 if (!use_hp) {
227 break;
228 }
229 }
230
231 if (connected) {
232 rc = 0;
233 sb->sb_sd = s;
234 #ifdef notyet
235 #ifdef LDAP_REFERRALS
236 status = 0;
237 if (!async && ioctl(s, FIONBIO, (caddr_t)&on) == -1) {
238 Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 203,
239 "FIONBIO ioctl failed on %d\n"), s, 0, 0);
240 }
241 #endif /* LDAP_REFERRALS */
242 #endif /* notyet */
243
244 Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 205,
245 "sd %1$d connected to: %2$s\n"), s,
246 inet_ntoa(sin.sin_addr), 0);
247 }
248
249 return (rc);
250 }
251
252
253 void
254 close_ldap_connection( Sockbuf *sb )
255 {
256 #ifdef LDAP_SSL
257 if (sb->sb_ssl){
258 SSL_close(sb->sb_ssl);
259 SSL_delete(sb->sb_ssl);
260 }
261 sb->sb_ssl = NULL;
262 sb->sb_ssl_tls = 0;
263 #endif
264 tcp_close( sb->sb_sd );
265 }
266
267
268 #ifdef KERBEROS
269 char *
270 host_connected_to( Sockbuf *sb )
271 {
272 struct hostent *hp;
273 char *p;
274 int len;
275 struct sockaddr_in sin;
276 #ifdef SUN
277 struct hostent hpret;
278 char hpbuf[NSS_BUFLEN_HOSTS];
279 int hperrno;
280 #endif
281
282 (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
283 len = sizeof( sin );
284 if ( getpeername( sb->sb_sd, (struct sockaddr *)&sin, &len ) == -1 ) {
285 return( NULL );
286 }
287
288 /*
289 * do a reverse lookup on the addr to get the official hostname.
290 * this is necessary for kerberos to work right, since the official
291 * hostname is used as the kerberos instance.
292 */
293 #ifdef SUN
294 if (( hp = gethostbyaddr_r((char *) &sin.sin_addr,
295 sizeof( sin.sin_addr ), AF_INET,
296 &hpret, hpbuf, NSS_BUFLEN_HOSTS, &hperrno)) != NULL ) {
297 #else
298 if (( hp = gethostbyaddr( (char *) &sin.sin_addr,
299 sizeof( sin.sin_addr ), AF_INET )) != NULL ) {
300 #endif
301 if ( hp->h_name != NULL ) {
302 return( strdup( hp->h_name ));
303 }
304 }
305
306 return( NULL );
307 }
308 #endif /* KERBEROS */
309
310
311 #ifdef LDAP_REFERRALS
312 #ifdef SUN
313 /* for UNIX */
314 #include <stropts.h>
315 #include <poll.h>
316
317 struct selectinfo {
318 struct pollfd fds[LDAP_DEFAULT_REFHOPLIMIT];
319 int nbfds;
320 };
321
322
323 void
324 mark_select_write( LDAP *ld, Sockbuf *sb )
325 {
326 struct selectinfo *sip;
327 int i;
328
329 sip = (struct selectinfo *)ld->ld_selectinfo;
330
331 /* find if sb is in fds */
332 for (i=0; i< sip->nbfds; i++) {
333 if (sip->fds[i].fd == sb->sb_sd){
334 sip->fds[i].events |= POLLOUT;
335 return;
336 }
337 }
338 if (sip->nbfds < LDAP_DEFAULT_REFHOPLIMIT) {
339 sip->fds[sip->nbfds].fd = sb->sb_sd;
340 sip->fds[sip->nbfds].events |= POLLOUT;
341 sip->nbfds++;
342 }
343 else {
344 /* Should not happen */
345 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 206, "Mark for poll : Too many descriptors\n"), 0, 0, 0 );
346 }
347 }
348
349
350 void
351 mark_select_read( LDAP *ld, Sockbuf *sb )
352 {
353 struct selectinfo *sip;
354 int i;
355
356 sip = (struct selectinfo *)ld->ld_selectinfo;
357
358 /* find if sb is in fds */
359 for (i=0; i< sip->nbfds; i++) {
360 if (sip->fds[i].fd == sb->sb_sd) {
361 sip->fds[i].events |= POLLIN;
362 return;
363 }
364 }
365
366 if (sip->nbfds < LDAP_DEFAULT_REFHOPLIMIT) {
367 sip->fds[sip->nbfds].fd = sb->sb_sd;
368 sip->fds[sip->nbfds].events |= POLLIN;
369 sip->nbfds++;
370 }
371 else {
372 /* Should not happen */
373 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 206, "Mark for poll : Too many descriptors\n"), 0, 0, 0 );
374 }
375 }
376
377
378 void
379 mark_select_clear( LDAP *ld, Sockbuf *sb )
380 {
381 struct selectinfo *sip;
382 int i;
383
384 sip = (struct selectinfo *)ld->ld_selectinfo;
385
386 for (i = 0; i< sip->nbfds; i++) {
387 if (sip->fds[i].fd == sb->sb_sd){
388 i++;
389 for (; i < sip->nbfds; i ++) {
390 sip->fds[ i - 1] = sip->fds[i];
391 }
392 sip->fds[i].fd = -1;
393 sip->fds[i].events = -1;
394 sip->nbfds--;
395 return;
396 }
397 }
398 /* If we reach here, there's a pb. */
399 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 207, "Clear poll : descriptor not found\n"), 0, 0, 0 );
400 }
401
402
403 long
404 is_write_ready( LDAP *ld, Sockbuf *sb )
405 {
406 struct selectinfo *sip;
407 int i;
408
409 sip = (struct selectinfo *)ld->ld_selectinfo;
410
411 for (i=0; i< sip->nbfds; i++) {
412 if (sip->fds[i].fd == sb->sb_sd) {
413 if ( sip->fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
414 return (-1);
415 }
416 return( sip->fds[i].revents & POLLOUT );
417 }
418 }
419 return(0);
420 }
421
422
423 long
424 is_read_ready( LDAP *ld, Sockbuf *sb )
425 {
426 struct selectinfo *sip;
427 int i;
428
429 sip = (struct selectinfo *)ld->ld_selectinfo;
430
431 for (i=0; i< sip->nbfds; i++) {
432 if (sip->fds[i].fd == sb->sb_sd) {
433 if (sip->fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
434 return (-1);
435 }
436 return( sip->fds[i].revents & POLLIN );
437 }
438 }
439 return(0);
440 }
441
442 void *
443 new_select_info()
444 {
445 struct selectinfo *sip;
446
447 sip = (struct selectinfo *)calloc( 1, sizeof( struct selectinfo ));
448
449 return( (void *)sip );
450 }
451
452
453 void
454 free_select_info( void *sip )
455 {
456 free( sip );
457 }
458
459
460 int
461 do_ldap_select( LDAP *ld, struct timeval *timeout )
462 {
463 struct selectinfo *sip;
464 int tim;
465 #if defined( SUN ) && defined( _REENTRANT )
466 int rv;
467 #endif
468
469 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 208, "do_ldap_select\n"), 0, 0, 0 );
470
471 sip = (struct selectinfo *)ld->ld_selectinfo;
472
473 /* sip->fds[0].revents = 0; */
474
475 if ( timeout ) {
476 tim = (timeout->tv_sec*1000)+(timeout->tv_usec/1000);
477 } else {
478 tim = INFTIM;
479 } /* end if */
480 errno=0;
481 #if defined( SUN ) && defined( _REENTRANT )
482 /* UNLOCK_LDAP(ld); */
483 LOCK_POLL(ld);
484 rv = poll(sip->fds,sip->nbfds,tim);
485 /* LOCK_LDAP(ld); */
486 UNLOCK_POLL(ld);
487 return(rv);
488 #else
489 return( poll(sip->fds,sip->nbfds,tim) );
490 #endif
491 }
492 #else
493 /* for UNIX */
494 struct selectinfo {
495 fd_set si_readfds;
496 fd_set si_writefds;
497 fd_set si_use_readfds;
498 fd_set si_use_writefds;
499 };
500
501
502 void
503 mark_select_write( LDAP *ld, Sockbuf *sb )
504 {
505 struct selectinfo *sip;
506
507 sip = (struct selectinfo *)ld->ld_selectinfo;
508
509 if ( !FD_ISSET( sb->sb_sd, &sip->si_writefds )) {
510 FD_SET( sb->sb_sd, &sip->si_writefds );
511 }
512 }
513
514
515 void
516 mark_select_read( LDAP *ld, Sockbuf *sb )
517 {
518 struct selectinfo *sip;
519
520 sip = (struct selectinfo *)ld->ld_selectinfo;
521
522 if ( !FD_ISSET( sb->sb_sd, &sip->si_readfds )) {
523 FD_SET( sb->sb_sd, &sip->si_readfds );
524 }
525 }
526
527
528 void
529 mark_select_clear( LDAP *ld, Sockbuf *sb )
530 {
531 struct selectinfo *sip;
532
533 sip = (struct selectinfo *)ld->ld_selectinfo;
534
535 FD_CLR( sb->sb_sd, &sip->si_writefds );
536 FD_CLR( sb->sb_sd, &sip->si_readfds );
537 }
538
539
540 long
541 is_write_ready( LDAP *ld, Sockbuf *sb )
542 {
543 struct selectinfo *sip;
544
545 sip = (struct selectinfo *)ld->ld_selectinfo;
546
547 return( FD_ISSET( sb->sb_sd, &sip->si_use_writefds ));
548 }
549
550
551 long
552 is_read_ready( LDAP *ld, Sockbuf *sb )
553 {
554 struct selectinfo *sip;
555
556 sip = (struct selectinfo *)ld->ld_selectinfo;
557
558 return( FD_ISSET( sb->sb_sd, &sip->si_use_readfds ));
559 }
560
561
562 void *
563 new_select_info()
564 {
565 struct selectinfo *sip;
566
567 if (( sip = (struct selectinfo *)calloc( 1,
568 sizeof( struct selectinfo ))) != NULL ) {
569 FD_ZERO( &sip->si_readfds );
570 FD_ZERO( &sip->si_writefds );
571 }
572
573 return( (void *)sip );
574 }
575
576
577 void
578 free_select_info( void *sip )
579 {
580 free( sip );
581 }
582
583
584 int
585 do_ldap_select( LDAP *ld, struct timeval *timeout )
586 {
587 struct selectinfo *sip;
588 static int tblsize;
589
590 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 208, "do_ldap_select\n"), 0, 0, 0 );
591
592 #if defined( SUN ) && defined( _REENTRANT )
593 LOCK_LDAP(ld);
594 #endif
595 if ( tblsize == 0 ) {
596 #ifdef USE_SYSCONF
597 tblsize = (int)sysconf( _SC_OPEN_MAX );
598 #else /* USE_SYSCONF */
599 tblsize = getdtablesize();
600 #endif /* USE_SYSCONF */
601 }
602
603 sip = (struct selectinfo *)ld->ld_selectinfo;
604 sip->si_use_readfds = sip->si_readfds;
605 sip->si_use_writefds = sip->si_writefds;
606
607 #if defined( SUN ) && defined( _REENTRANT )
608 UNLOCK_LDAP(ld);
609 #endif
610 return( select( tblsize, &sip->si_use_readfds, &sip->si_use_writefds,
611 NULL, timeout ));
612 }
613 #endif /* SUN */
614 #endif /* LDAP_REFERRALS */
615