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