xref: /onnv-gate/usr/src/lib/libldap4/common/os-ip.c (revision 0:68f95e015346)
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