sockbuf.c revision 1.1
1/* sockbuf.c - i/o routines with support for adding i/o layers. */ 2/* $OpenLDAP: pkg/ldap/libraries/liblber/sockbuf.c,v 1.65.2.4 2008/02/11 23:26:41 kurt Exp $ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include "portable.h" 18 19#include <stdio.h> 20 21#include <ac/stdlib.h> 22 23#include <ac/ctype.h> 24#include <ac/errno.h> 25#include <ac/socket.h> 26#include <ac/string.h> 27#include <ac/unistd.h> 28 29#ifdef HAVE_IO_H 30#include <io.h> 31#endif /* HAVE_IO_H */ 32 33#if defined( HAVE_FCNTL_H ) 34#include <fcntl.h> 35#endif 36 37#if defined( HAVE_SYS_FILIO_H ) 38#include <sys/filio.h> 39#elif defined( HAVE_SYS_IOCTL_H ) 40#include <sys/ioctl.h> 41#endif 42 43#include "lber-int.h" 44 45#ifndef LBER_MIN_BUFF_SIZE 46#define LBER_MIN_BUFF_SIZE 4096 47#endif 48#ifndef LBER_MAX_BUFF_SIZE 49#define LBER_MAX_BUFF_SIZE (65536*256) 50#endif 51#ifndef LBER_DEFAULT_READAHEAD 52#define LBER_DEFAULT_READAHEAD 16384 53#endif 54 55Sockbuf * 56ber_sockbuf_alloc( void ) 57{ 58 Sockbuf *sb; 59 60 sb = LBER_CALLOC( 1, sizeof( Sockbuf ) ); 61 62 if( sb == NULL ) return NULL; 63 64 ber_int_sb_init( sb ); 65 return sb; 66} 67 68void 69ber_sockbuf_free( Sockbuf *sb ) 70{ 71 assert( sb != NULL ); 72 assert( SOCKBUF_VALID( sb ) ); 73 74 ber_int_sb_close( sb ); 75 ber_int_sb_destroy( sb ); 76 LBER_FREE( sb ); 77} 78 79/* Return values: -1: error, 0: no operation performed or the answer is false, 80 * 1: successful operation or the answer is true 81 */ 82int 83ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) 84{ 85 Sockbuf_IO_Desc *p; 86 int ret = 0; 87 88 assert( sb != NULL ); 89 assert( SOCKBUF_VALID( sb ) ); 90 91 switch ( opt ) { 92 case LBER_SB_OPT_HAS_IO: 93 p = sb->sb_iod; 94 while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) { 95 p = p->sbiod_next; 96 } 97 98 if ( p ) { 99 ret = 1; 100 } 101 break; 102 103 case LBER_SB_OPT_GET_FD: 104 if ( arg != NULL ) { 105 *((ber_socket_t *)arg) = sb->sb_fd; 106 } 107 ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1); 108 break; 109 110 case LBER_SB_OPT_SET_FD: 111 sb->sb_fd = *((ber_socket_t *)arg); 112 ret = 1; 113 break; 114 115 case LBER_SB_OPT_SET_NONBLOCK: 116 ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL) 117 ? -1 : 1; 118 break; 119 120 case LBER_SB_OPT_DRAIN: { 121 /* Drain the data source to enable possible errors (e.g. 122 * TLS) to be propagated to the upper layers 123 */ 124 char buf[LBER_MIN_BUFF_SIZE]; 125 126 do { 127 ret = ber_int_sb_read( sb, buf, sizeof( buf ) ); 128 } while ( ret == sizeof( buf ) ); 129 130 ret = 1; 131 } break; 132 133 case LBER_SB_OPT_NEEDS_READ: 134 ret = ( sb->sb_trans_needs_read ? 1 : 0 ); 135 break; 136 137 case LBER_SB_OPT_NEEDS_WRITE: 138 ret = ( sb->sb_trans_needs_write ? 1 : 0 ); 139 break; 140 141 case LBER_SB_OPT_GET_MAX_INCOMING: 142 if ( arg != NULL ) { 143 *((ber_len_t *)arg) = sb->sb_max_incoming; 144 } 145 ret = 1; 146 break; 147 148 case LBER_SB_OPT_SET_MAX_INCOMING: 149 sb->sb_max_incoming = *((ber_len_t *)arg); 150 ret = 1; 151 break; 152 153 case LBER_SB_OPT_UNGET_BUF: 154#ifdef LDAP_PF_LOCAL_SENDMSG 155 sb->sb_ungetlen = ((struct berval *)arg)->bv_len; 156 if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) { 157 AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val, 158 sb->sb_ungetlen ); 159 ret = 1; 160 } else { 161 sb->sb_ungetlen = 0; 162 ret = -1; 163 } 164#endif 165 break; 166 167 default: 168 ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg ); 169 break; 170 } 171 172 return ret; 173} 174 175int 176ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg ) 177{ 178 Sockbuf_IO_Desc *d, *p, **q; 179 180 assert( sb != NULL ); 181 assert( SOCKBUF_VALID( sb ) ); 182 183 if ( sbio == NULL ) { 184 return -1; 185 } 186 187 q = &sb->sb_iod; 188 p = *q; 189 while ( p && p->sbiod_level > layer ) { 190 q = &p->sbiod_next; 191 p = *q; 192 } 193 194 d = LBER_MALLOC( sizeof( *d ) ); 195 if ( d == NULL ) { 196 return -1; 197 } 198 199 d->sbiod_level = layer; 200 d->sbiod_sb = sb; 201 d->sbiod_io = sbio; 202 memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) ); 203 d->sbiod_next = p; 204 *q = d; 205 206 if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) { 207 return -1; 208 } 209 210 return 0; 211} 212 213int 214ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer ) 215{ 216 Sockbuf_IO_Desc *p, **q; 217 218 assert( sb != NULL ); 219 assert( SOCKBUF_VALID( sb ) ); 220 221 if ( sb->sb_iod == NULL ) { 222 return -1; 223 } 224 225 q = &sb->sb_iod; 226 while ( *q != NULL ) { 227 p = *q; 228 if ( layer == p->sbiod_level && p->sbiod_io == sbio ) { 229 if ( p->sbiod_io->sbi_remove != NULL && 230 p->sbiod_io->sbi_remove( p ) < 0 ) 231 { 232 return -1; 233 } 234 *q = p->sbiod_next; 235 LBER_FREE( p ); 236 break; 237 } 238 q = &p->sbiod_next; 239 } 240 241 return 0; 242} 243 244void 245ber_pvt_sb_buf_init( Sockbuf_Buf *buf ) 246{ 247 buf->buf_base = NULL; 248 buf->buf_ptr = 0; 249 buf->buf_end = 0; 250 buf->buf_size = 0; 251} 252 253void 254ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf ) 255{ 256 assert( buf != NULL); 257 258 if (buf->buf_base) { 259 LBER_FREE( buf->buf_base ); 260 } 261 ber_pvt_sb_buf_init( buf ); 262} 263 264int 265ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize ) 266{ 267 ber_len_t pw; 268 char *p; 269 270 assert( buf != NULL ); 271 272 for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) { 273 if (pw > LBER_MAX_BUFF_SIZE) return -1; 274 } 275 276 if ( buf->buf_size < pw ) { 277 p = LBER_REALLOC( buf->buf_base, pw ); 278 if ( p == NULL ) return -1; 279 buf->buf_base = p; 280 buf->buf_size = pw; 281 } 282 return 0; 283} 284 285ber_len_t 286ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len ) 287{ 288 ber_len_t max; 289 290 assert( buf != NULL ); 291 assert( sbb != NULL ); 292#if 0 293 assert( sbb->buf_size > 0 ); 294#endif 295 296 max = sbb->buf_end - sbb->buf_ptr; 297 max = ( max < len) ? max : len; 298 if ( max ) { 299 AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max ); 300 sbb->buf_ptr += max; 301 if ( sbb->buf_ptr >= sbb->buf_end ) { 302 sbb->buf_ptr = sbb->buf_end = 0; 303 } 304 } 305 return max; 306} 307 308ber_slen_t 309ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out ) 310{ 311 ber_len_t to_go; 312 ber_slen_t ret; 313 314 assert( sbiod != NULL ); 315 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 316 317 to_go = buf_out->buf_end - buf_out->buf_ptr; 318 assert( to_go > 0 ); 319 320 for(;;) { 321 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base + 322 buf_out->buf_ptr, to_go ); 323#ifdef EINTR 324 if ((ret<0) && (errno==EINTR)) continue; 325#endif 326 break; 327 } 328 329 if ( ret <= 0 ) return ret; 330 331 buf_out->buf_ptr += ret; 332 if (buf_out->buf_ptr == buf_out->buf_end) { 333 buf_out->buf_end = buf_out->buf_ptr = 0; 334 } 335 336 return ret; 337} 338 339int 340ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) 341{ 342#ifdef HAVE_FCNTL 343 int flags = fcntl( sd, F_GETFL); 344 if( nb ) { 345 flags |= O_NONBLOCK; 346 } else { 347 flags &= ~O_NONBLOCK; 348 } 349 return fcntl( sd, F_SETFL, flags ); 350 351#elif defined( FIONBIO ) 352 ioctl_t status = nb ? 1 : 0; 353 return ioctl( sd, FIONBIO, &status ); 354#endif 355} 356 357int 358ber_int_sb_init( Sockbuf *sb ) 359{ 360 assert( sb != NULL); 361 362 sb->sb_valid=LBER_VALID_SOCKBUF; 363 sb->sb_options = 0; 364 sb->sb_debug = ber_int_debug; 365 sb->sb_fd = AC_SOCKET_INVALID; 366 sb->sb_iod = NULL; 367 sb->sb_trans_needs_read = 0; 368 sb->sb_trans_needs_write = 0; 369 370 assert( SOCKBUF_VALID( sb ) ); 371 return 0; 372} 373 374int 375ber_int_sb_close( Sockbuf *sb ) 376{ 377 Sockbuf_IO_Desc *p; 378 379 assert( sb != NULL); 380 381 p = sb->sb_iod; 382 while ( p ) { 383 if ( p->sbiod_io->sbi_close && p->sbiod_io->sbi_close( p ) < 0 ) { 384 return -1; 385 } 386 p = p->sbiod_next; 387 } 388 389 sb->sb_fd = AC_SOCKET_INVALID; 390 391 return 0; 392} 393 394int 395ber_int_sb_destroy( Sockbuf *sb ) 396{ 397 Sockbuf_IO_Desc *p; 398 399 assert( sb != NULL); 400 assert( SOCKBUF_VALID( sb ) ); 401 402 while ( sb->sb_iod ) { 403 p = sb->sb_iod->sbiod_next; 404 ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io, 405 sb->sb_iod->sbiod_level ); 406 sb->sb_iod = p; 407 } 408 409 return ber_int_sb_init( sb ); 410} 411 412ber_slen_t 413ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len ) 414{ 415 ber_slen_t ret; 416 417 assert( buf != NULL ); 418 assert( sb != NULL); 419 assert( sb->sb_iod != NULL ); 420 assert( SOCKBUF_VALID( sb ) ); 421 422 for (;;) { 423 ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len ); 424 425#ifdef EINTR 426 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; 427#endif 428 break; 429 } 430 431 return ret; 432} 433 434ber_slen_t 435ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) 436{ 437 ber_slen_t ret; 438 439 assert( buf != NULL ); 440 assert( sb != NULL); 441 assert( sb->sb_iod != NULL ); 442 assert( SOCKBUF_VALID( sb ) ); 443 444 for (;;) { 445 ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); 446 447#ifdef EINTR 448 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; 449#endif 450 break; 451 } 452 453 return ret; 454} 455 456/* 457 * Support for TCP 458 */ 459 460static ber_slen_t 461sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 462{ 463 assert( sbiod != NULL); 464 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 465 466#if defined(MACOS) 467/* 468 * MacTCP/OpenTransport 469 */ 470 return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, 471 len, NULL ); 472 473#elif defined( HAVE_PCNFS ) || \ 474 defined( HAVE_WINSOCK ) || defined ( __BEOS__ ) 475/* 476 * PCNFS (under DOS) 477 */ 478/* 479 * Windows Socket API (under DOS/Windows 3.x) 480 */ 481/* 482 * 32-bit Windows Socket API (under Windows NT or Windows 95) 483 */ 484 return recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); 485 486#elif defined( HAVE_NCSA ) 487/* 488 * NCSA Telnet TCP/IP stack (under DOS) 489 */ 490 return nread( sbiod->sbiod_sb->sb_fd, buf, len ); 491 492#else 493 return read( sbiod->sbiod_sb->sb_fd, buf, len ); 494#endif 495} 496 497static ber_slen_t 498sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 499{ 500 assert( sbiod != NULL); 501 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 502 503#if defined(MACOS) 504/* 505 * MacTCP/OpenTransport 506 */ 507#define MAX_WRITE 65535 508 return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf, 509 (len<MAX_WRITE) ? len : MAX_WRITE ); 510 511#elif defined( HAVE_PCNFS) \ 512 || defined( HAVE_WINSOCK) || defined ( __BEOS__ ) 513/* 514 * PCNFS (under DOS) 515 */ 516/* 517 * Windows Socket API (under DOS/Windows 3.x) 518 */ 519/* 520 * 32-bit Windows Socket API (under Windows NT or Windows 95) 521 */ 522 return send( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); 523 524#elif defined(HAVE_NCSA) 525 return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); 526 527#elif defined(VMS) 528/* 529 * VMS -- each write must be 64K or smaller 530 */ 531#define MAX_WRITE 65535 532 return write( sbiod->sbiod_sb->sb_fd, buf, 533 (len<MAX_WRITE) ? len : MAX_WRITE); 534#else 535 return write( sbiod->sbiod_sb->sb_fd, buf, len ); 536#endif 537} 538 539static int 540sb_stream_close( Sockbuf_IO_Desc *sbiod ) 541{ 542 assert( sbiod != NULL ); 543 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 544 tcp_close( sbiod->sbiod_sb->sb_fd ); 545 return 0; 546} 547 548/* The argument is a pointer to the socket descriptor */ 549static int 550sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { 551 assert( sbiod != NULL ); 552 553 if ( arg != NULL ) { 554 sbiod->sbiod_sb->sb_fd = *((int *)arg); 555 } 556 return 0; 557} 558 559static int 560sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { 561 /* This is an end IO descriptor */ 562 return 0; 563} 564 565Sockbuf_IO ber_sockbuf_io_tcp = { 566 sb_stream_setup, /* sbi_setup */ 567 NULL, /* sbi_remove */ 568 sb_stream_ctrl, /* sbi_ctrl */ 569 sb_stream_read, /* sbi_read */ 570 sb_stream_write, /* sbi_write */ 571 sb_stream_close /* sbi_close */ 572}; 573 574 575/* 576 * Support for readahead (UDP needs it) 577 */ 578 579static int 580sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 581{ 582 Sockbuf_Buf *p; 583 584 assert( sbiod != NULL ); 585 586 p = LBER_MALLOC( sizeof( *p ) ); 587 if ( p == NULL ) return -1; 588 589 ber_pvt_sb_buf_init( p ); 590 591 if ( arg == NULL ) { 592 ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD ); 593 } else { 594 ber_pvt_sb_grow_buffer( p, *((int *)arg) ); 595 } 596 597 sbiod->sbiod_pvt = p; 598 return 0; 599} 600 601static int 602sb_rdahead_remove( Sockbuf_IO_Desc *sbiod ) 603{ 604 Sockbuf_Buf *p; 605 606 assert( sbiod != NULL ); 607 608 p = (Sockbuf_Buf *)sbiod->sbiod_pvt; 609 610 if ( p->buf_ptr != p->buf_end ) return -1; 611 612 ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) ); 613 LBER_FREE( sbiod->sbiod_pvt ); 614 sbiod->sbiod_pvt = NULL; 615 616 return 0; 617} 618 619static ber_slen_t 620sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 621{ 622 Sockbuf_Buf *p; 623 ber_slen_t bufptr = 0, ret, max; 624 625 assert( sbiod != NULL ); 626 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 627 assert( sbiod->sbiod_next != NULL ); 628 629 p = (Sockbuf_Buf *)sbiod->sbiod_pvt; 630 631 assert( p->buf_size > 0 ); 632 633 /* Are there anything left in the buffer? */ 634 ret = ber_pvt_sb_copy_out( p, buf, len ); 635 bufptr += ret; 636 len -= ret; 637 638 if ( len == 0 ) return bufptr; 639 640 max = p->buf_size - p->buf_end; 641 ret = 0; 642 while ( max > 0 ) { 643 ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end, 644 max ); 645#ifdef EINTR 646 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; 647#endif 648 break; 649 } 650 651 if ( ret < 0 ) { 652 return ( bufptr ? bufptr : ret ); 653 } 654 655 p->buf_end += ret; 656 bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len ); 657 return bufptr; 658} 659 660static ber_slen_t 661sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 662{ 663 assert( sbiod != NULL ); 664 assert( sbiod->sbiod_next != NULL ); 665 666 return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); 667} 668 669static int 670sb_rdahead_close( Sockbuf_IO_Desc *sbiod ) 671{ 672 assert( sbiod != NULL ); 673 674 /* Just erase the buffer */ 675 ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt); 676 return 0; 677} 678 679static int 680sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 681{ 682 Sockbuf_Buf *p; 683 684 p = (Sockbuf_Buf *)sbiod->sbiod_pvt; 685 686 if ( opt == LBER_SB_OPT_DATA_READY ) { 687 if ( p->buf_ptr != p->buf_end ) { 688 return 1; 689 } 690 691 } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) { 692 if ( p->buf_size >= *((ber_len_t *)arg) ) { 693 return 0; 694 } 695 return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ? 696 -1 : 1 ); 697 } 698 699 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); 700} 701 702Sockbuf_IO ber_sockbuf_io_readahead = { 703 sb_rdahead_setup, /* sbi_setup */ 704 sb_rdahead_remove, /* sbi_remove */ 705 sb_rdahead_ctrl, /* sbi_ctrl */ 706 sb_rdahead_read, /* sbi_read */ 707 sb_rdahead_write, /* sbi_write */ 708 sb_rdahead_close /* sbi_close */ 709}; 710 711/* 712 * Support for simple file IO 713 */ 714 715static ber_slen_t 716sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 717{ 718 assert( sbiod != NULL); 719 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 720 721#ifdef LDAP_PF_LOCAL_SENDMSG 722 if ( sbiod->sbiod_sb->sb_ungetlen ) { 723 ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; 724 if ( blen > len ) 725 blen = len; 726 AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); 727 buf = (char *) buf + blen; 728 len -= blen; 729 sbiod->sbiod_sb->sb_ungetlen -= blen; 730 if ( sbiod->sbiod_sb->sb_ungetlen ) { 731 AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, 732 sbiod->sbiod_sb->sb_ungetbuf+blen, 733 sbiod->sbiod_sb->sb_ungetlen ); 734 } 735 if ( len == 0 ) 736 return blen; 737 } 738#endif 739 return read( sbiod->sbiod_sb->sb_fd, buf, len ); 740} 741 742static ber_slen_t 743sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 744{ 745 assert( sbiod != NULL); 746 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 747 748 return write( sbiod->sbiod_sb->sb_fd, buf, len ); 749} 750 751static int 752sb_fd_close( Sockbuf_IO_Desc *sbiod ) 753{ 754 assert( sbiod != NULL ); 755 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 756 757 close( sbiod->sbiod_sb->sb_fd ); 758 return 0; 759} 760 761/* The argument is a pointer to the file descriptor */ 762static int 763sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { 764 assert( sbiod != NULL ); 765 766 if ( arg != NULL ) 767 sbiod->sbiod_sb->sb_fd = *((int *)arg); 768 return 0; 769} 770 771static int 772sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { 773 /* This is an end IO descriptor */ 774 return 0; 775} 776 777Sockbuf_IO ber_sockbuf_io_fd = { 778 sb_fd_setup, /* sbi_setup */ 779 NULL, /* sbi_remove */ 780 sb_fd_ctrl, /* sbi_ctrl */ 781 sb_fd_read, /* sbi_read */ 782 sb_fd_write, /* sbi_write */ 783 sb_fd_close /* sbi_close */ 784}; 785 786/* 787 * Debugging layer 788 */ 789 790static int 791sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 792{ 793 assert( sbiod != NULL ); 794 795 if ( arg == NULL ) arg = "sockbuf_"; 796 797 sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 ); 798 if ( sbiod->sbiod_pvt == NULL ) return -1; 799 800 strcpy( (char *)sbiod->sbiod_pvt, (char *)arg ); 801 return 0; 802} 803 804static int 805sb_debug_remove( Sockbuf_IO_Desc *sbiod ) 806{ 807 assert( sbiod != NULL ); 808 assert( sbiod->sbiod_pvt != NULL ); 809 810 LBER_FREE( sbiod->sbiod_pvt ); 811 sbiod->sbiod_pvt = NULL; 812 return 0; 813} 814 815static int 816sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 817{ 818 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); 819} 820 821static ber_slen_t 822sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 823{ 824 ber_slen_t ret; 825 char ebuf[128]; 826 827 ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len ); 828 if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) { 829 int err = sock_errno(); 830 if ( ret < 0 ) { 831 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 832 "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt, 833 (long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) ); 834 } else { 835 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 836 "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt, 837 (long)len, (long)ret ); 838 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 839 (const char *)buf, ret ); 840 } 841 sock_errset(err); 842 } 843 return ret; 844} 845 846static ber_slen_t 847sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 848{ 849 ber_slen_t ret; 850 char ebuf[128]; 851 852 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); 853 if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) { 854 int err = sock_errno(); 855 if ( ret < 0 ) { 856 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 857 "%swrite: want=%ld error=%s\n", 858 (char *)sbiod->sbiod_pvt, (long)len, 859 AC_STRERROR_R( err, ebuf, sizeof ebuf ) ); 860 } else { 861 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 862 "%swrite: want=%ld, written=%ld\n", 863 (char *)sbiod->sbiod_pvt, (long)len, (long)ret ); 864 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, 865 (const char *)buf, ret ); 866 } 867 sock_errset(err); 868 } 869 870 return ret; 871} 872 873Sockbuf_IO ber_sockbuf_io_debug = { 874 sb_debug_setup, /* sbi_setup */ 875 sb_debug_remove, /* sbi_remove */ 876 sb_debug_ctrl, /* sbi_ctrl */ 877 sb_debug_read, /* sbi_read */ 878 sb_debug_write, /* sbi_write */ 879 NULL /* sbi_close */ 880}; 881 882#ifdef LDAP_CONNECTIONLESS 883 884/* 885 * Support for UDP (CLDAP) 886 * 887 * All I/O at this level must be atomic. For ease of use, the sb_readahead 888 * must be used above this module. All data reads and writes are prefixed 889 * with a sockaddr containing the address of the remote entity. Upper levels 890 * must read and write this sockaddr before doing the usual ber_printf/scanf 891 * operations on LDAP messages. 892 */ 893 894static int 895sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 896{ 897 assert( sbiod != NULL); 898 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 899 900 if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg); 901 return 0; 902} 903 904static ber_slen_t 905sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 906{ 907 ber_slen_t rc; 908 ber_socklen_t addrlen; 909 struct sockaddr *src; 910 911 assert( sbiod != NULL ); 912 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 913 assert( buf != NULL ); 914 915 addrlen = sizeof( struct sockaddr ); 916 src = buf; 917 buf = (char *) buf + addrlen; 918 len -= addrlen; 919 rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen ); 920 921 return rc > 0 ? rc+sizeof(struct sockaddr) : rc; 922} 923 924static ber_slen_t 925sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) 926{ 927 ber_slen_t rc; 928 struct sockaddr *dst; 929 930 assert( sbiod != NULL ); 931 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 932 assert( buf != NULL ); 933 934 dst = buf; 935 buf = (char *) buf + sizeof( struct sockaddr ); 936 len -= sizeof( struct sockaddr ); 937 938 rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, 939 sizeof( struct sockaddr ) ); 940 941 if ( rc < 0 ) return -1; 942 943 /* fake error if write was not atomic */ 944 if (rc < len) { 945# ifdef EMSGSIZE 946 errno = EMSGSIZE; 947# endif 948 return -1; 949 } 950 rc = len + sizeof(struct sockaddr); 951 return rc; 952} 953 954static int 955sb_dgram_close( Sockbuf_IO_Desc *sbiod ) 956{ 957 assert( sbiod != NULL ); 958 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 959 960 tcp_close( sbiod->sbiod_sb->sb_fd ); 961 return 0; 962} 963 964static int 965sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 966{ 967 /* This is an end IO descriptor */ 968 return 0; 969} 970 971Sockbuf_IO ber_sockbuf_io_udp = 972{ 973 sb_dgram_setup, /* sbi_setup */ 974 NULL, /* sbi_remove */ 975 sb_dgram_ctrl, /* sbi_ctrl */ 976 sb_dgram_read, /* sbi_read */ 977 sb_dgram_write, /* sbi_write */ 978 sb_dgram_close /* sbi_close */ 979}; 980 981#endif /* LDAP_CONNECTIONLESS */ 982