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 44 int ldap_int_inet4or6 = AF_UNSPEC; 45 # else 46 int ldap_int_inet4or6 = AF_INET; 47 # endif 48 #endif 49 50 #ifdef LDAP_DEBUG 51 52 #define osip_debug(ld,fmt,arg1,arg2,arg3) \ 53 do { \ 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 63 static void 64 ldap_pvt_set_errno(int err) 65 { 66 sock_errset(err); 67 } 68 69 int 70 ldap_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 94 static int 95 ldap_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 101 static int 102 ldap_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 108 static ber_socket_t 109 ldap_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 116 static int 117 ldap_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 123 static int 124 ldap_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 */ 169 static int 170 ldap_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 */ 218 int 219 ldap_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 351 static int 352 ldap_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 406 int 407 ldap_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 422 int 423 ldap_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 ) 621 char * 622 ldap_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 715 struct 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 729 void 730 ldap_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 774 void 775 ldap_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 819 void 820 ldap_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 847 int 848 ldap_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 876 int 877 ldap_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 905 void * 906 ldap_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 927 void 928 ldap_free_select_info( void *sip ) 929 { 930 LDAP_FREE( sip ); 931 } 932 933 934 #ifndef HAVE_POLL 935 int ldap_int_tblsize = 0; 936 937 void 938 ldap_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 959 int 960 ldap_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