os-ip.c revision 1.1
1/* os-ip.c -- platform-specific TCP & UDP related code */ 2/* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.118.2.7 2008/04/15 00:00:36 quanah Exp $ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * Portions Copyright 1999 Lars Uffmann. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* Portions Copyright (c) 1995 Regents of the University of Michigan. 18 * All rights reserved. 19 */ 20/* Significant additional contributors include: 21 * Lars Uffman 22 */ 23 24#include "portable.h" 25 26#include <stdio.h> 27 28#include <ac/stdlib.h> 29 30#include <ac/errno.h> 31#include <ac/socket.h> 32#include <ac/string.h> 33#include <ac/time.h> 34#include <ac/unistd.h> 35 36#ifdef HAVE_IO_H 37#include <io.h> 38#endif /* HAVE_IO_H */ 39 40#include "ldap-int.h" 41 42#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 43# ifdef LDAP_PF_INET6 44int ldap_int_inet4or6 = AF_UNSPEC; 45# else 46int ldap_int_inet4or6 = AF_INET; 47# endif 48#endif 49 50#ifdef LDAP_DEBUG 51 52#define osip_debug(ld,fmt,arg1,arg2,arg3) \ 53do { \ 54 ldap_log_printf(NULL, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \ 55} while(0) 56 57#else 58 59#define osip_debug(ld,fmt,arg1,arg2,arg3) ((void)0) 60 61#endif /* LDAP_DEBUG */ 62 63static void 64ldap_pvt_set_errno(int err) 65{ 66 sock_errset(err); 67} 68 69int 70ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src ) 71{ 72 struct timeval *new; 73 74 assert( dest != NULL ); 75 76 if (src == NULL) { 77 *dest = NULL; 78 return 0; 79 } 80 81 new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval)); 82 83 if( new == NULL ) { 84 *dest = NULL; 85 return 1; 86 } 87 88 AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval)); 89 90 *dest = new; 91 return 0; 92} 93 94static int 95ldap_pvt_ndelay_on(LDAP *ld, int fd) 96{ 97 osip_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0); 98 return ber_pvt_socket_set_nonblock( fd, 1 ); 99} 100 101static int 102ldap_pvt_ndelay_off(LDAP *ld, int fd) 103{ 104 osip_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0); 105 return ber_pvt_socket_set_nonblock( fd, 0 ); 106} 107 108static ber_socket_t 109ldap_int_socket(LDAP *ld, int family, int type ) 110{ 111 ber_socket_t s = socket(family, type, 0); 112 osip_debug(ld, "ldap_new_socket: %d\n",s,0,0); 113 return ( s ); 114} 115 116static int 117ldap_pvt_close_socket(LDAP *ld, int s) 118{ 119 osip_debug(ld, "ldap_close_socket: %d\n",s,0,0); 120 return tcp_close(s); 121} 122 123static int 124ldap_int_prepare_socket(LDAP *ld, int s, int proto ) 125{ 126 osip_debug( ld, "ldap_prepare_socket: %d\n", s, 0, 0 ); 127 128#if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY ) 129 if ( proto == LDAP_PROTO_TCP ) { 130 int dummy = 1; 131#ifdef SO_KEEPALIVE 132 if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, 133 (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) 134 { 135 osip_debug( ld, "ldap_prepare_socket: " 136 "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n", 137 s, 0, 0 ); 138 } 139#endif /* SO_KEEPALIVE */ 140#ifdef TCP_NODELAY 141 if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, 142 (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) 143 { 144 osip_debug( ld, "ldap_prepare_socket: " 145 "setsockopt(%d, TCP_NODELAY) failed (ignored).\n", 146 s, 0, 0 ); 147 } 148#endif /* TCP_NODELAY */ 149 } 150#endif /* SO_KEEPALIVE || TCP_NODELAY */ 151 152 return 0; 153} 154 155#ifndef HAVE_WINSOCK 156 157#undef TRACE 158#define TRACE do { \ 159 osip_debug(ld, \ 160 "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \ 161 s, \ 162 errno, \ 163 sock_errstr(errno) ); \ 164} while( 0 ) 165 166/* 167 * check the socket for errors after select returned. 168 */ 169static int 170ldap_pvt_is_socket_ready(LDAP *ld, int s) 171{ 172 osip_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0); 173 174#if defined( notyet ) /* && defined( SO_ERROR ) */ 175{ 176 int so_errno; 177 ber_socklen_t dummy = sizeof(so_errno); 178 if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) 179 == AC_SOCKET_ERROR ) 180 { 181 return -1; 182 } 183 if ( so_errno ) { 184 ldap_pvt_set_errno(so_errno); 185 TRACE; 186 return -1; 187 } 188 return 0; 189} 190#else 191{ 192 /* error slippery */ 193#ifdef LDAP_PF_INET6 194 struct sockaddr_storage sin; 195#else 196 struct sockaddr_in sin; 197#endif 198 char ch; 199 ber_socklen_t dummy = sizeof(sin); 200 if ( getpeername( s, (struct sockaddr *) &sin, &dummy ) 201 == AC_SOCKET_ERROR ) 202 { 203 /* XXX: needs to be replace with ber_stream_read() */ 204 read(s, &ch, 1); 205 TRACE; 206 return -1; 207 } 208 return 0; 209} 210#endif 211 return -1; 212} 213#undef TRACE 214 215#endif /* HAVE_WINSOCK */ 216 217/* NOTE: this is identical to analogous code in os-local.c */ 218int 219ldap_int_poll( 220 LDAP *ld, 221 ber_socket_t s, 222 struct timeval *tvp ) 223{ 224 int rc; 225 226 227 osip_debug(ld, "ldap_int_poll: fd: %d tm: %ld\n", 228 s, tvp ? tvp->tv_sec : -1L, 0); 229 230#ifdef HAVE_POLL 231 { 232 struct pollfd fd; 233 int timeout = INFTIM; 234 235 fd.fd = s; 236 fd.events = POLL_WRITE; 237 238 if ( tvp != NULL ) { 239 timeout = TV2MILLISEC( tvp ); 240 } 241 do { 242 fd.revents = 0; 243 rc = poll( &fd, 1, timeout ); 244 245 } while ( rc == AC_SOCKET_ERROR && errno == EINTR && 246 LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); 247 248 if ( rc == AC_SOCKET_ERROR ) { 249 return rc; 250 } 251 252 if ( timeout == 0 && rc == 0 ) { 253 return -2; 254 } 255 256 if ( fd.revents & POLL_WRITE ) { 257 if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { 258 return -1; 259 } 260 261 if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) { 262 return -1; 263 } 264 return 0; 265 } 266 } 267#else 268 { 269 fd_set wfds, *z = NULL; 270#ifdef HAVE_WINSOCK 271 fd_set efds; 272#endif 273 struct timeval tv = { 0 }; 274 275#if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK ) 276 if ( s >= FD_SETSIZE ) { 277 rc = AC_SOCKET_ERROR; 278 tcp_close( s ); 279 ldap_pvt_set_errno( EMFILE ); 280 return rc; 281 } 282#endif 283 284 if ( tvp != NULL ) { 285 tv = *tvp; 286 } 287 288 do { 289 FD_ZERO(&wfds); 290 FD_SET(s, &wfds ); 291 292#ifdef HAVE_WINSOCK 293 FD_ZERO(&efds); 294 FD_SET(s, &efds ); 295#endif 296 297 rc = select( ldap_int_tblsize, z, &wfds, 298#ifdef HAVE_WINSOCK 299 &efds, 300#else 301 z, 302#endif 303 tvp ? &tv : NULL ); 304 } while ( rc == AC_SOCKET_ERROR && errno == EINTR && 305 LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); 306 307 if ( rc == AC_SOCKET_ERROR ) { 308 return rc; 309 } 310 311 if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) { 312 return -2; 313 } 314 315#ifdef HAVE_WINSOCK 316 /* This means the connection failed */ 317 if ( FD_ISSET(s, &efds) ) { 318 int so_errno; 319 ber_socklen_t dummy = sizeof(so_errno); 320 if ( getsockopt( s, SOL_SOCKET, SO_ERROR, 321 (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno ) 322 { 323 /* impossible */ 324 so_errno = WSAGetLastError(); 325 } 326 ldap_pvt_set_errno( so_errno ); 327 osip_debug(ld, "ldap_int_poll: error on socket %d: " 328 "errno: %d (%s)\n", s, errno, sock_errstr( errno )); 329 return -1; 330 } 331#endif 332 if ( FD_ISSET(s, &wfds) ) { 333#ifndef HAVE_WINSOCK 334 if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { 335 return -1; 336 } 337#endif 338 if ( ldap_pvt_ndelay_off(ld, s) == -1 ) { 339 return -1; 340 } 341 return 0; 342 } 343 } 344#endif 345 346 osip_debug(ld, "ldap_int_poll: timed out\n",0,0,0); 347 ldap_pvt_set_errno( ETIMEDOUT ); 348 return -1; 349} 350 351static int 352ldap_pvt_connect(LDAP *ld, ber_socket_t s, 353 struct sockaddr *sin, ber_socklen_t addrlen, 354 int async) 355{ 356 int rc, err; 357 struct timeval tv, *opt_tv = NULL; 358 359#ifdef LDAP_CONNECTIONLESS 360 /* We could do a connect() but that would interfere with 361 * attempts to poll a broadcast address 362 */ 363 if (LDAP_IS_UDP(ld)) { 364 if (ld->ld_options.ldo_peer) 365 ldap_memfree(ld->ld_options.ldo_peer); 366 ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr)); 367 AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr)); 368 return ( 0 ); 369 } 370#endif 371 if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) { 372 tv = ld->ld_options.ldo_tm_net; 373 opt_tv = &tv; 374 } 375 376 osip_debug(ld, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n", 377 s, opt_tv ? tv.tv_sec : -1L, async); 378 379 if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 ) 380 return ( -1 ); 381 382 if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) { 383 if ( opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 ) 384 return ( -1 ); 385 return ( 0 ); 386 } 387 388 err = sock_errno(); 389 if ( err != EINPROGRESS && err != EWOULDBLOCK ) { 390 return ( -1 ); 391 } 392 393 if ( async ) { 394 /* caller will call ldap_int_poll() as appropriate? */ 395 return ( -2 ); 396 } 397 398 rc = ldap_int_poll( ld, s, opt_tv ); 399 400 osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0); 401 402 return rc; 403} 404 405#ifndef HAVE_INET_ATON 406int 407ldap_pvt_inet_aton( const char *host, struct in_addr *in) 408{ 409 unsigned long u = inet_addr( host ); 410 411#ifdef INADDR_NONE 412 if ( u == INADDR_NONE ) return 0; 413#endif 414 if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0; 415 416 in->s_addr = u; 417 return 1; 418} 419#endif 420 421 422int 423ldap_connect_to_host(LDAP *ld, Sockbuf *sb, 424 int proto, 425 const char *host, int port, 426 int async ) 427{ 428 int rc; 429 int socktype; 430 ber_socket_t s = AC_SOCKET_INVALID; 431 432#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 433 char serv[7]; 434 int err; 435 struct addrinfo hints, *res, *sai; 436#else 437 int i; 438 int use_hp = 0; 439 struct hostent *hp = NULL; 440 struct hostent he_buf; 441 struct in_addr in; 442 char *ha_buf=NULL; 443#endif 444 445 if( host == NULL ) host = "localhost"; 446 447 switch(proto) { 448 case LDAP_PROTO_TCP: socktype = SOCK_STREAM; 449 osip_debug( ld, 450 "ldap_connect_to_host: TCP %s:%d\n", 451 host, port, 0); 452 break; 453 case LDAP_PROTO_UDP: socktype = SOCK_DGRAM; 454 osip_debug( ld, 455 "ldap_connect_to_host: UDP %s:%d\n", 456 host, port, 0); 457 break; 458 default: 459 osip_debug( ld, "ldap_connect_to_host: unknown proto: %d\n", 460 proto, 0, 0 ); 461 return -1; 462 } 463 464#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 465 memset( &hints, '\0', sizeof(hints) ); 466#ifdef USE_AI_ATTRCONFIG /* FIXME: configure test needed */ 467 /* Use AI_ATTRCONFIG only on systems where its known to be needed. */ 468 hints.ai_flags = AI_ATTRCONFIG; 469#endif 470 hints.ai_family = ldap_int_inet4or6; 471 hints.ai_socktype = socktype; 472 snprintf(serv, sizeof serv, "%d", port ); 473 474#ifdef LDAP_R_COMPILE 475 /* most getaddrinfo(3) use non-threadsafe resolver libraries */ 476 ldap_pvt_thread_mutex_lock(&ldap_int_resolv_mutex); 477#endif 478 479 err = getaddrinfo( host, serv, &hints, &res ); 480 481#ifdef LDAP_R_COMPILE 482 ldap_pvt_thread_mutex_unlock(&ldap_int_resolv_mutex); 483#endif 484 485 if ( err != 0 ) { 486 osip_debug(ld, "ldap_connect_to_host: getaddrinfo failed: %s\n", 487 AC_GAI_STRERROR(err), 0, 0); 488 return -1; 489 } 490 rc = -1; 491 492 for( sai=res; sai != NULL; sai=sai->ai_next) { 493 if( sai->ai_addr == NULL ) { 494 osip_debug(ld, "ldap_connect_to_host: getaddrinfo " 495 "ai_addr is NULL?\n", 0, 0, 0); 496 continue; 497 } 498 499 /* we assume AF_x and PF_x are equal for all x */ 500 s = ldap_int_socket( ld, sai->ai_family, socktype ); 501 if ( s == AC_SOCKET_INVALID ) { 502 continue; 503 } 504 505 if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) { 506 ldap_pvt_close_socket(ld, s); 507 break; 508 } 509 510 switch (sai->ai_family) { 511#ifdef LDAP_PF_INET6 512 case AF_INET6: { 513 char addr[INET6_ADDRSTRLEN]; 514 inet_ntop( AF_INET6, 515 &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr, 516 addr, sizeof addr); 517 osip_debug(ld, "ldap_connect_to_host: Trying %s %s\n", 518 addr, serv, 0); 519 } break; 520#endif 521 case AF_INET: { 522 char addr[INET_ADDRSTRLEN]; 523 inet_ntop( AF_INET, 524 &((struct sockaddr_in *)sai->ai_addr)->sin_addr, 525 addr, sizeof addr); 526 osip_debug(ld, "ldap_connect_to_host: Trying %s:%s\n", 527 addr, serv, 0); 528 } break; 529 } 530 531 rc = ldap_pvt_connect( ld, s, 532 sai->ai_addr, sai->ai_addrlen, async ); 533 if ( rc == 0 || rc == -2 ) { 534 ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s ); 535 break; 536 } 537 ldap_pvt_close_socket(ld, s); 538 } 539 freeaddrinfo(res); 540 541#else 542 if (! inet_aton( host, &in ) ) { 543 int local_h_errno; 544 rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf, 545 &hp, &local_h_errno ); 546 547 if ( (rc < 0) || (hp == NULL) ) { 548#ifdef HAVE_WINSOCK 549 ldap_pvt_set_errno( WSAGetLastError() ); 550#else 551 /* not exactly right, but... */ 552 ldap_pvt_set_errno( EHOSTUNREACH ); 553#endif 554 if (ha_buf) LDAP_FREE(ha_buf); 555 return -1; 556 } 557 558 use_hp = 1; 559 } 560 561 rc = s = -1; 562 for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) { 563 struct sockaddr_in sin; 564 565 s = ldap_int_socket( ld, PF_INET, socktype ); 566 if ( s == AC_SOCKET_INVALID ) { 567 /* use_hp ? continue : break; */ 568 break; 569 } 570 571 if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) { 572 ldap_pvt_close_socket(ld, s); 573 break; 574 } 575 576 (void)memset((char *)&sin, '\0', sizeof sin); 577 sin.sin_family = AF_INET; 578 sin.sin_port = htons((unsigned short) port); 579 580 if( use_hp ) { 581 AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i], 582 sizeof(sin.sin_addr) ); 583 } else { 584 AC_MEMCPY( &sin.sin_addr, &in.s_addr, 585 sizeof(sin.sin_addr) ); 586 } 587 588#ifdef HAVE_INET_NTOA_B 589 { 590 /* for VxWorks */ 591 char address[INET_ADDR_LEN]; 592 inet_ntoa_b(sin.sin_address, address); 593 osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 594 address, port, 0); 595 } 596#else 597 osip_debug(ld, "ldap_connect_to_host: Trying %s:%d\n", 598 inet_ntoa(sin.sin_addr), port, 0); 599#endif 600 601 rc = ldap_pvt_connect(ld, s, 602 (struct sockaddr *)&sin, sizeof(sin), 603 async); 604 605 if ( (rc == 0) || (rc == -2) ) { 606 ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s ); 607 break; 608 } 609 610 ldap_pvt_close_socket(ld, s); 611 612 if (!use_hp) break; 613 } 614 if (ha_buf) LDAP_FREE(ha_buf); 615#endif 616 617 return rc; 618} 619 620#if defined( HAVE_CYRUS_SASL ) 621char * 622ldap_host_connected_to( Sockbuf *sb, const char *host ) 623{ 624 ber_socklen_t len; 625#ifdef LDAP_PF_INET6 626 struct sockaddr_storage sabuf; 627#else 628 struct sockaddr sabuf; 629#endif 630 struct sockaddr *sa = (struct sockaddr *) &sabuf; 631 ber_socket_t sd; 632 633 (void)memset( (char *)sa, '\0', sizeof sabuf ); 634 len = sizeof sabuf; 635 636 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 637 if ( getpeername( sd, sa, &len ) == -1 ) { 638 return( NULL ); 639 } 640 641 /* 642 * do a reverse lookup on the addr to get the official hostname. 643 * this is necessary for kerberos to work right, since the official 644 * hostname is used as the kerberos instance. 645 */ 646 647 switch (sa->sa_family) { 648#ifdef LDAP_PF_LOCAL 649 case AF_LOCAL: 650 return LDAP_STRDUP( ldap_int_hostname ); 651#endif 652#ifdef LDAP_PF_INET6 653 case AF_INET6: 654 { 655 struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT; 656 if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr, 657 &localhost, sizeof(localhost)) == 0 ) 658 { 659 return LDAP_STRDUP( ldap_int_hostname ); 660 } 661 } 662 break; 663#endif 664 case AF_INET: 665 { 666 struct in_addr localhost; 667 localhost.s_addr = htonl( INADDR_ANY ); 668 669 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, 670 &localhost, sizeof(localhost) ) == 0 ) 671 { 672 return LDAP_STRDUP( ldap_int_hostname ); 673 } 674 675#ifdef INADDR_LOOPBACK 676 localhost.s_addr = htonl( INADDR_LOOPBACK ); 677 678 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, 679 &localhost, sizeof(localhost) ) == 0 ) 680 { 681 return LDAP_STRDUP( ldap_int_hostname ); 682 } 683#endif 684 } 685 break; 686 687 default: 688 return( NULL ); 689 break; 690 } 691 692 { 693 char *herr; 694#ifdef NI_MAXHOST 695 char hbuf[NI_MAXHOST]; 696#elif defined( MAXHOSTNAMELEN 697 char hbuf[MAXHOSTNAMELEN]; 698#else 699 char hbuf[256]; 700#endif 701 hbuf[0] = 0; 702 703 if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0 704 && hbuf[0] ) 705 { 706 return LDAP_STRDUP( hbuf ); 707 } 708 } 709 710 return host ? LDAP_STRDUP( host ) : NULL; 711} 712#endif 713 714 715struct selectinfo { 716#ifdef HAVE_POLL 717 /* for UNIX poll(2) */ 718 int si_maxfd; 719 struct pollfd si_fds[FD_SETSIZE]; 720#else 721 /* for UNIX select(2) */ 722 fd_set si_readfds; 723 fd_set si_writefds; 724 fd_set si_use_readfds; 725 fd_set si_use_writefds; 726#endif 727}; 728 729void 730ldap_mark_select_write( LDAP *ld, Sockbuf *sb ) 731{ 732 struct selectinfo *sip; 733 ber_socket_t sd; 734 735 sip = (struct selectinfo *)ld->ld_selectinfo; 736 737 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 738 739#ifdef HAVE_POLL 740 /* for UNIX poll(2) */ 741 { 742 int empty=-1; 743 int i; 744 for(i=0; i < sip->si_maxfd; i++) { 745 if( sip->si_fds[i].fd == sd ) { 746 sip->si_fds[i].events |= POLL_WRITE; 747 return; 748 } 749 if( empty==-1 && sip->si_fds[i].fd == -1 ) { 750 empty=i; 751 } 752 } 753 754 if( empty == -1 ) { 755 if( sip->si_maxfd >= FD_SETSIZE ) { 756 /* FIXME */ 757 return; 758 } 759 empty = sip->si_maxfd++; 760 } 761 762 sip->si_fds[empty].fd = sd; 763 sip->si_fds[empty].events = POLL_WRITE; 764 } 765#else 766 /* for UNIX select(2) */ 767 if ( !FD_ISSET( sd, &sip->si_writefds )) { 768 FD_SET( sd, &sip->si_writefds ); 769 } 770#endif 771} 772 773 774void 775ldap_mark_select_read( LDAP *ld, Sockbuf *sb ) 776{ 777 struct selectinfo *sip; 778 ber_socket_t sd; 779 780 sip = (struct selectinfo *)ld->ld_selectinfo; 781 782 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 783 784#ifdef HAVE_POLL 785 /* for UNIX poll(2) */ 786 { 787 int empty=-1; 788 int i; 789 for(i=0; i < sip->si_maxfd; i++) { 790 if( sip->si_fds[i].fd == sd ) { 791 sip->si_fds[i].events |= POLL_READ; 792 return; 793 } 794 if( empty==-1 && sip->si_fds[i].fd == -1 ) { 795 empty=i; 796 } 797 } 798 799 if( empty == -1 ) { 800 if( sip->si_maxfd >= FD_SETSIZE ) { 801 /* FIXME */ 802 return; 803 } 804 empty = sip->si_maxfd++; 805 } 806 807 sip->si_fds[empty].fd = sd; 808 sip->si_fds[empty].events = POLL_READ; 809 } 810#else 811 /* for UNIX select(2) */ 812 if ( !FD_ISSET( sd, &sip->si_readfds )) { 813 FD_SET( sd, &sip->si_readfds ); 814 } 815#endif 816} 817 818 819void 820ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ) 821{ 822 struct selectinfo *sip; 823 ber_socket_t sd; 824 825 sip = (struct selectinfo *)ld->ld_selectinfo; 826 827 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 828 829#ifdef HAVE_POLL 830 /* for UNIX poll(2) */ 831 { 832 int i; 833 for(i=0; i < sip->si_maxfd; i++) { 834 if( sip->si_fds[i].fd == sd ) { 835 sip->si_fds[i].fd = -1; 836 } 837 } 838 } 839#else 840 /* for UNIX select(2) */ 841 FD_CLR( sd, &sip->si_writefds ); 842 FD_CLR( sd, &sip->si_readfds ); 843#endif 844} 845 846 847int 848ldap_is_write_ready( LDAP *ld, Sockbuf *sb ) 849{ 850 struct selectinfo *sip; 851 ber_socket_t sd; 852 853 sip = (struct selectinfo *)ld->ld_selectinfo; 854 855 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 856 857#ifdef HAVE_POLL 858 /* for UNIX poll(2) */ 859 { 860 int i; 861 for(i=0; i < sip->si_maxfd; i++) { 862 if( sip->si_fds[i].fd == sd ) { 863 return sip->si_fds[i].revents & POLL_WRITE; 864 } 865 } 866 867 return 0; 868 } 869#else 870 /* for UNIX select(2) */ 871 return( FD_ISSET( sd, &sip->si_use_writefds )); 872#endif 873} 874 875 876int 877ldap_is_read_ready( LDAP *ld, Sockbuf *sb ) 878{ 879 struct selectinfo *sip; 880 ber_socket_t sd; 881 882 sip = (struct selectinfo *)ld->ld_selectinfo; 883 884 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 885 886#ifdef HAVE_POLL 887 /* for UNIX poll(2) */ 888 { 889 int i; 890 for(i=0; i < sip->si_maxfd; i++) { 891 if( sip->si_fds[i].fd == sd ) { 892 return sip->si_fds[i].revents & POLL_READ; 893 } 894 } 895 896 return 0; 897 } 898#else 899 /* for UNIX select(2) */ 900 return( FD_ISSET( sd, &sip->si_use_readfds )); 901#endif 902} 903 904 905void * 906ldap_new_select_info( void ) 907{ 908 struct selectinfo *sip; 909 910 sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo )); 911 912 if ( sip == NULL ) return NULL; 913 914#ifdef HAVE_POLL 915 /* for UNIX poll(2) */ 916 /* sip->si_maxfd=0 */ 917#else 918 /* for UNIX select(2) */ 919 FD_ZERO( &sip->si_readfds ); 920 FD_ZERO( &sip->si_writefds ); 921#endif 922 923 return( (void *)sip ); 924} 925 926 927void 928ldap_free_select_info( void *sip ) 929{ 930 LDAP_FREE( sip ); 931} 932 933 934#ifndef HAVE_POLL 935int ldap_int_tblsize = 0; 936 937void 938ldap_int_ip_init( void ) 939{ 940#if defined( HAVE_SYSCONF ) 941 long tblsize = sysconf( _SC_OPEN_MAX ); 942 if( tblsize > INT_MAX ) tblsize = INT_MAX; 943 944#elif defined( HAVE_GETDTABLESIZE ) 945 int tblsize = getdtablesize(); 946#else 947 int tblsize = FD_SETSIZE; 948#endif /* !USE_SYSCONF */ 949 950#ifdef FD_SETSIZE 951 if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE; 952#endif /* FD_SETSIZE */ 953 954 ldap_int_tblsize = tblsize; 955} 956#endif 957 958 959int 960ldap_int_select( LDAP *ld, struct timeval *timeout ) 961{ 962 int rc; 963 struct selectinfo *sip; 964 965 Debug( LDAP_DEBUG_TRACE, "ldap_int_select\n", 0, 0, 0 ); 966 967#ifndef HAVE_POLL 968 if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); 969#endif 970 971 sip = (struct selectinfo *)ld->ld_selectinfo; 972 assert( sip != NULL ); 973 974#ifdef HAVE_POLL 975 { 976 int to = timeout ? TV2MILLISEC( timeout ) : INFTIM; 977 rc = poll( sip->si_fds, sip->si_maxfd, to ); 978 } 979#else 980 sip->si_use_readfds = sip->si_readfds; 981 sip->si_use_writefds = sip->si_writefds; 982 983 rc = select( ldap_int_tblsize, 984 &sip->si_use_readfds, &sip->si_use_writefds, 985 NULL, timeout ); 986#endif 987 988 return rc; 989} 990