X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Fliblber%2Fsockbuf.c;h=ae5c07c8c1e4c28e1fba4bf370de5b3a203b185f;hb=1cf91cd6dbf3b2a1a1eef569288d6405ac4ab5ca;hp=900ff04bdbdb18bfbfc327d1efbe7c259e809a68;hpb=879d3dbc5eb5cdbc45c12afca1bada8207039246;p=openldap diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index 900ff04bdb..ae5c07c8c1 100644 --- a/libraries/liblber/sockbuf.c +++ b/libraries/liblber/sockbuf.c @@ -1,6 +1,7 @@ /* sockbuf.c - i/o routines with support for adding i/o layers. */ +/* $OpenLDAP$ */ /* - * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ @@ -20,641 +21,317 @@ #include #endif /* HAVE_IO_H */ +#if defined( HAVE_FCNTL_H ) +#include +#endif + #if defined( HAVE_SYS_FILIO_H ) #include #elif defined( HAVE_SYS_IOCTL_H ) #include #endif -#undef LDAP_F_PRE -#define LDAP_F_PRE LDAP_F_EXPORT - #include "lber-int.h" -#ifdef LDAP_TEST -#undef TEST_PARTIAL_READ -#undef TEST_PARTIAL_WRITE +#ifndef LBER_MIN_BUFF_SIZE +#define LBER_MIN_BUFF_SIZE 4096 +#endif +#ifndef LBER_MAX_BUFF_SIZE +#define LBER_MAX_BUFF_SIZE 65536 +#endif +#ifndef LBER_DEFAULT_READAHEAD +#define LBER_DEFAULT_READAHEAD 16384 #endif -#define MAX_BUF_SIZE 65535 -#define MIN_BUF_SIZE 4096 +Sockbuf * +ber_sockbuf_alloc( void ) +{ + Sockbuf *sb; -#define sockbuf_io_write( sb, buf, len ) \ -((sb)->sb_io->sbi_write( (sb), (buf), (len) )) + ber_int_options.lbo_valid = LBER_INITIALIZED; -#define sockbuf_io_read( sb, buf, len ) \ -((sb)->sb_io->sbi_read( (sb), (buf), (len) )) + sb = LBER_CALLOC( 1, sizeof( Sockbuf ) ); -static ber_slen_t have_no_read( Sockbuf *sb, void *buf, ber_len_t len ); -static ber_slen_t have_no_write( Sockbuf *sb, void *buf, ber_len_t len ); -static int have_no_close( Sockbuf *sb ); + if( sb == NULL ) return NULL; -static Sockbuf_IO sb_IO_None= -{ - NULL, /* sbi_setup */ - NULL, /* sbi_release */ - have_no_read, /* sbi_read */ - have_no_write, /* sbi_write */ - have_no_close /* sbi_close */ -}; + ber_int_sb_init( sb ); + return sb; +} -static void -update_status( Sockbuf *sb ) +void +ber_sockbuf_free( Sockbuf *sb ) { assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - sb->sb_buf_ready = (sb->sb_buf.buf_ptr < sb->sb_buf.buf_end); -#ifdef USE_SASL - sb->sb_sec_ready = ((sb->sb_sec_buf_in.buf_end!=0) && - (sb->sb_sec_buf_in.buf_ptr >= - sb->sb_sec_buf_in.buf_end)); -#endif + ber_int_sb_close( sb ); + ber_int_sb_destroy( sb ); + LBER_FREE( sb ); } -#ifdef LDAP_DEBUG -static int -status_is_ok( Sockbuf *sb ) +/* Return values: -1: error, 0: no operation performed or the answer is false, + * 1: successful operation or the answer is true + */ +int +ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) { - int obr; -#ifdef USE_SASL - int osr; -#endif + Sockbuf_IO_Desc *p; + int ret = 0; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - obr = sb->sb_buf_ready; -#ifdef USE_SASL - osr = sb->sb_sec_ready; -#endif - - update_status(sb); - if (obr!=sb->sb_buf_ready) - return 0; - -#ifdef USE_SASL - if (osr!=sb->sb_sec_ready) - return 0; -#endif - - return 1; -} -#endif - -#ifdef USE_SASL -static ber_len_t -packet_length( Sockbuf *sb, const char *buf ) -{ - ber_len_t size; - - assert( buf != NULL ); - - size = (((ber_len_t)buf[0])<<24)| - (((ber_len_t)buf[1])<<16)| - (((ber_len_t)buf[2])<<8)| - (((ber_len_t)buf[3])); - - if ( size > MAX_BUF_SIZE ) { - /* somebody is trying to mess me up. */ - ber_log_printf( LDAP_DEBUG_SASL, sb->sb_debug, - "SASL: received packet length of %lu bytes\n", - (unsigned long) size ); - size = 16; /* this should lead to an error. */ + switch ( opt ) { + case LBER_SB_OPT_HAS_IO: + p = sb->sb_iod; + while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) { + p = p->sbiod_next; + } + + if ( p ) { + ret = 1; + } + break; + + case LBER_SB_OPT_GET_FD: + if ( arg != NULL ) { + *((int *)arg) = sb->sb_fd; + } + ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1); + break; + + case LBER_SB_OPT_SET_FD: + sb->sb_fd = *((int *)arg); + ret = 1; + break; + + case LBER_SB_OPT_SET_NONBLOCK: + ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL) + ? -1 : 1; + break; + + case LBER_SB_OPT_DRAIN: { + /* Drain the data source to enable possible errors (e.g. + * TLS) to be propagated to the upper layers + */ + char buf[LBER_MIN_BUFF_SIZE]; + + do { + ret = ber_int_sb_read( sb, buf, sizeof( buf ) ); + } while ( ret == sizeof( buf ) ); + + ret = 1; + } break; + + case LBER_SB_OPT_NEEDS_READ: + ret = ( sb->sb_trans_needs_read ? 1 : 0 ); + break; + + case LBER_SB_OPT_NEEDS_WRITE: + ret = ( sb->sb_trans_needs_write ? 1 : 0 ); + break; + + case LBER_SB_OPT_GET_MAX_INCOMING: + if ( arg != NULL ) { + *((ber_len_t *)arg) = sb->sb_max_incoming; + } + ret = 1; + break; + + case LBER_SB_OPT_SET_MAX_INCOMING: + sb->sb_max_incoming = *((ber_len_t *)arg); + ret = 1; + break; + + default: + ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, + opt, arg ); + break; } - - return size + 4; /* include the size !!! */ -} -#endif -static int -grow_buffer( Sockbuf_Buf * buf, ber_len_t minsize ) -{ - ber_len_t pw;; - - assert( buf != NULL ); - - for( pw=MIN_BUF_SIZE; pw MAX_BUF_SIZE) { - /* this could mean that somebody is trying to crash us. */ - return -1; - } - } - minsize = pw; - - if (buf->buf_sizebuf_base==NULL) || ((buf->buf_end==0) && (buf->buf_ptr==0))) { - /* empty buffer */ - if (buf->buf_base!=NULL) - LBER_FREE( buf->buf_base ); - assert( buf->buf_ptr==0 ); - assert( buf->buf_end==0 ); - buf->buf_base = LBER_MALLOC( minsize ); - if (buf->buf_base==NULL) - return -1; - } else { - char *nb; - nb = LBER_REALLOC( buf->buf_base, minsize ); - if (nb==NULL) - return -1; - buf->buf_base = nb; - } - buf->buf_size = minsize; - } - return 0; + return ret; } -#ifdef USE_SASL -static ber_slen_t -sockbuf_sec_release( Sockbuf *sb, char *buf, ber_len_t len ) +int +ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg ) { - /* when this is called: - * sb->sb_sec_buf_in.buf_base points to a packet. - * sb->sb_sec_buf_in.buf_ptr contains the total bytes read. - * sb->sb_sec_end.buf_end contains the packet length. - * - * sb->sb_buf.buf_ptr == sb->sb_buf.buf_end == 0; - */ - long rlen; - long total; - char *ptr; - char *end; - long size; + Sockbuf_IO_Desc *d, *p, **q; - assert( buf != NULL ); assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - - assert( sb->sb_sec ); - assert( sb->sb_sec->sbs_release ); - assert( sb->sb_sec_buf_in.sb_ptr >= sb->sb_sec_buf_in.sb_end ); - assert( sb->sb_buf.sb_ptr == 0 ); - assert( sb->sb_buf.sb_end == 0 ); - - assert( status_is_ok(sb) ); - - total = 0; + if ( sbio == NULL ) { + return -1; + } - ptr = sb->sb_sec_buf_in.buf_base; - end = ptr+ sb->sb_sec_buf_in.buf_ptr; - size = sb->sb_sec_buf_in.buf_end; + q = &sb->sb_iod; + p = *q; + while ( p && p->sbiod_level > layer ) { + q = &p->sbiod_next; + p = *q; + } - sb->sb_sec_ready = 1; + d = LBER_MALLOC( sizeof( *d ) ); + if ( d == NULL ) { + return -1; + } - for(;(ptr+size<=end);) { - for(;;) { - rlen = sb->sb_sec->sbs_release( sb, ptr, size, - buf, len, - sb->sb_buf.buf_base, - sb->sb_buf.buf_size ); - if (rlen==0) { - /* this means a security violation. */ - return total; /* total ? total : 0 */ - } - if (rlen<0) { - /* this means that the buffer isn't big enough. */ - if (grow_buffer( &(sb->sb_buf), -rlen )<0) - /* memory violation. */ - return total; /* total ? total : 0 */ - continue; - } - /* if (rlen>0) */ - break; - } - total+=rlen; - - /* move to the next packet... */ - ptr+=size; + d->sbiod_level = layer; + d->sbiod_sb = sb; + d->sbiod_io = sbio; + memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) ); + d->sbiod_next = p; + *q = d; - if (ptr+4<=end) - size = packet_length( sb, ptr ); - /* size is always at least 4, so the loop condition is always OK !!*/ - assert( size>=4 ); + if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) { + return -1; + } - if (rlensb_buf_ready = (sb->sb_buf.buf_end = rlen - len) ? 1 : 0; - break; - } - } - - if (ptr+size>end) - sb->sb_sec_ready = 0; - /* clean up the mess. */ - if (ptrsb_sec_buf_in.buf_base, ptr, end-ptr ); - sb->sb_sec_buf_in.buf_ptr = 0; - sb->sb_sec_buf_in.buf_end -= (ptr - sb->sb_sec_buf_in.buf_base); - } - assert( status_is_ok(sb) ); - return total; + return 0; } - -static long -sockbuf_sec_protect( Sockbuf *sb, char *buf, long len ) -{ - long ret; - long blen; - long total; - assert( buf != NULL ); +int +ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer ) +{ + Sockbuf_IO_Desc *p, **q; - assert( sb != NULL ); + assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); - - assert( sb->sb_sec_out.buf_end == 0 ); - assert( sb->sb_sec_out.buf_ptr == 0 ); - assert( sb->sb_sec ); - assert( sb->sb_sec->sbs_protect ); - - assert( status_is_ok(sb) ); + if ( sb->sb_iod == NULL ) { + return -1; + } - total = 0; - for(;(len);) { - for(;;) { - blen = len; - ret = sb->sb_sec->sbs_protect( sb, buf, &blen, - sb->sb_sec_out.buf_base+ - sb->sb_sec_out.buf_end, - sb->sb_sec_out.buf_size - - sb->sb_sec_out.buf_end ); - if (ret==0) - /* protection error ? */ - return total; - if (ret<0) { - if (grow_buffer( &(sb->sb_sec_out),-ret-sb->sb_sec_out.buf_end )<0) - /* memory error */ - return total; - continue; - } - /* else if (ret>0) */ - break; - } - sb->sb_sec_out.buf_end += ret; - len -= blen; - total += blen; - } - assert( status_is_ok(sb) ); - return total; -} -#endif - -static ber_len_t -sockbuf_copy_out( Sockbuf *sb, char **buf, ber_len_t len ) -{ - ber_len_t blen = (sb->sb_buf.buf_end - sb->sb_buf.buf_ptr ); - - assert( buf != NULL ); + q = &sb->sb_iod; + while ( *q != NULL ) { + p = *q; + if ( layer == p->sbiod_level && p->sbiod_io == sbio ) { + if ( p->sbiod_io->sbi_remove != NULL && + p->sbiod_io->sbi_remove( p ) < 0 ) + { + return -1; + } + *q = p->sbiod_next; + LBER_FREE( p ); + break; + } + q = &p->sbiod_next; + } - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - - if (blen) { - ber_len_t rlen = (blensb_buf.buf_base + sb->sb_buf.buf_ptr, rlen ); - sb->sb_buf.buf_ptr+=rlen; - *buf+=rlen; - len -= rlen; - if (sb->sb_buf.buf_ptr >= sb->sb_buf.buf_end) { - sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0; - sb->sb_buf_ready = 0; - } else { - sb->sb_buf_ready = 1; - } - } - assert( status_is_ok(sb) ); - return len; + return 0; } -Sockbuf *ber_sockbuf_alloc( void ) +void +ber_pvt_sb_buf_init( Sockbuf_Buf *buf ) { - Sockbuf *sb; - - ber_int_options.lbo_valid = LBER_INITIALIZED; - - sb = LBER_CALLOC(1, sizeof(Sockbuf)); - - if( sb == NULL ) return NULL; - - ber_pvt_sb_init( sb ); - return sb; + buf->buf_base = NULL; + buf->buf_ptr = 0; + buf->buf_end = 0; + buf->buf_size = 0; } -Sockbuf *ber_sockbuf_alloc_fd( ber_socket_t fd ) +void +ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf ) { - Sockbuf *sb = ber_sockbuf_alloc(); - - if( sb == NULL ) return NULL; - - ber_pvt_sb_set_desc( sb, fd ); - ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); - return sb; -} + assert( buf != NULL); -void ber_sockbuf_free( Sockbuf *sb ) -{ - assert(sb != NULL); - assert( SOCKBUF_VALID( sb ) ); - ber_pvt_sb_destroy( sb ); - LBER_FREE(sb); + if (buf->buf_base) { + LBER_FREE( buf->buf_base ); + } + ber_pvt_sb_buf_init( buf ); } -ber_slen_t -ber_pvt_sb_read( Sockbuf *sb, void *buf_arg, ber_len_t len ) +int +ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize ) { - char *buf; - ber_slen_t ret; - - assert( buf_arg != NULL ); - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - - /* slapd might have problems with this */ - assert( ber_pvt_sb_in_use( sb ) ); - -#ifdef TEST_PARTIAL_READ - if ((rand() & 3)==1) { /* 1 out of 4 */ - errno = EWOULDBLOCK; - return -1; - } - - if( len > 0 ) - len = (rand() % len)+1; -#endif + ber_len_t pw; + char *p; - buf = (char *) buf_arg; + assert( buf != NULL ); - if (sb->sb_buf.buf_ptr!=sb->sb_buf.buf_end) { - len = sockbuf_copy_out( sb, &buf, len ); - if (len==0) { - return (buf - (char *) buf_arg); - } - } + for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) { + if (pw > LBER_MAX_BUFF_SIZE) return -1; + } -#ifdef USE_SASL - if (sb->sb_sec) { - ber_slen_t max; - assert( sb->sb_sec->sbs_release ); - assert( sb->sb_sec_buf_in.buf_base ); - if (sb->sb_read_ahead) { - max = sb->sb_sec_buf_in.buf_size - sb->sb_sec_buf_in.buf_ptr; - } else { - max = sb->sb_sec_buf_in.buf_end - sb->sb_sec_buf_in.buf_ptr; - if (max<=0) { - /* special situation. This means that we need to read the first - * four bytes for the packet length. - */ - max += 4; - } - } - for(;;) { - /* read from stream into sb_sec_buf_in */ - for(;;) { - ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base + - sb->sb_sec_buf_in.buf_ptr, max ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret<=0) { - /* read error. return */ - goto do_return; - } - sb->sb_sec_buf_in.buf_ptr += ret; - - if (sb->sb_sec_buf_in.buf_ptr < sb->sb_sec_buf_in.buf_end) { - /* did not finish a packet. give up. */ - goto do_return; - } - - if (sb->sb_sec_buf_in.buf_end == 0) { - /* Were trying to read the first four bytes... */ - if (sb->sb_sec_buf_in.buf_ptr < 4) { - /* did not read enough for packet length. give up. */ - goto do_return; - } - /* calculate the packet length. */ - sb->sb_sec_buf_in.buf_end = - packet_length(sb, sb->sb_sec_buf_in.buf_base ); - if ((sb->sb_sec_buf_in.buf_end > sb->sb_sec_buf_in.buf_size) && - (grow_buffer( &(sb->sb_sec_buf_in), sb->sb_sec_buf_in.buf_end)<0)) { - /* buffer has to be to big. exit with error. */ - ret = -1; - goto do_return; - } - if (sb->sb_sec_buf_in.buf_ptr >= sb->sb_sec_buf_in.buf_end) { - /* finished packet. decode it. */ - goto decode_packet; - } - /* did not finish packet yet. try again ? */ - if (sb->sb_read_ahead) { - /* we were trying to read the max anyway. forget it */ - goto do_return; - } - } -decode_packet: - /* we read enough for at least 1 packet */ - ret = sockbuf_sec_release( sb, buf, len ); - if (ret<=0) { - /* something went wrong... */ - goto do_return; - } - buf+=ret; - len-=ret; - /* we are finished !!! */ - if ((len==0) || (ret!=max)) - goto do_return; - } - } else { -#endif - if (sb->sb_read_ahead) { - ber_slen_t max; - max = sb->sb_buf.buf_size - sb->sb_buf.buf_end; - if (max> (ber_slen_t) len) { - for(;;) { - ret = sockbuf_io_read( sb, - sb->sb_buf.buf_base + - sb->sb_buf.buf_end, - max ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret<=0) { - /* some error occured */ - goto do_return; - } - sb->sb_buf.buf_end += ret; - /* move out the data... */ - len = sockbuf_copy_out( sb, &buf, len ); - goto do_return; - } - } - /* no read_ahead, just try to put the data in the buf. */ - for(;;) { - ret = sockbuf_io_read( sb, buf, len ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } - if (ret>0) { - buf+=ret; - len-=ret; - } - /* we might as well return, since there is nothing to do... */ -#ifdef USE_SASL - } -#endif -do_return: - assert( status_is_ok(sb) ); - if ((ret<=0) && (buf==buf_arg)) { - /* there was an error. */ - return ret; - } - return (buf - ((char *) buf_arg)); + if ( buf->buf_size < pw ) { + p = LBER_REALLOC( buf->buf_base, pw ); + if ( p == NULL ) return -1; + buf->buf_base = p; + buf->buf_size = pw; + } + return 0; } -#ifdef USE_SASL -long sockbuf_do_write( Sockbuf *sb ) +ber_len_t +ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len ) { - long to_go; - ber_slen_t ret; - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + ber_len_t max; - to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr; - assert( to_go > 0 ); - /* there is something left of the last time... */ - for(;;) { - ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+ - sb->sb_sec_out.buf_ptr, to_go ); -#ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; + assert( buf != NULL ); + assert( sbb != NULL ); +#if 0 + assert( sbb->buf_size > 0 ); #endif - break; + + max = sbb->buf_end - sbb->buf_ptr; + max = ( max < len) ? max : len; + if ( max ) { + AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max ); + sbb->buf_ptr += max; + if ( sbb->buf_ptr >= sbb->buf_end ) { + sbb->buf_ptr = sbb->buf_end = 0; + } } - if (ret<=0) /* error */ - return ret; - sb->sb_sec_out.buf_ptr += ret; - if (retsbiod_sb ) ); - len_arg = (rand() % len_arg)+1; - len = len_arg; -#endif + to_go = buf_out->buf_end - buf_out->buf_ptr; + assert( to_go > 0 ); -#ifdef USE_SASL - if (sb->sb_sec) { - assert( sb->sb_sec_prev_len <= len ); - if (sb->sb_sec_prev_len) { - ret = sockbuf_do_write( sb ); - if (ret<=0) - return ret; - /* finished. */ - len -= sb->sb_sec_prev_len; - sb->sb_sec_prev_len = 0; - sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0; - } - /* now protect the next packet. */ - ret = sockbuf_sec_protect( sb, buf, len ); - if (ret<=0) - return ret; - ret = sockbuf_do_write( sb ); - if (ret<=0) { - sb->sb_sec_prev_len = len; - return ret; - } - return len_arg; - } else { -#endif - for(;;) { - ret = sockbuf_io_write( sb, buf, len ); + for(;;) { + ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base + + buf_out->buf_ptr, to_go ); #ifdef EINTR - if ((ret<0) && (errno==EINTR)) - continue; -#endif - break; - } -#ifdef USE_SASL - } + if ((ret<0) && (errno==EINTR)) continue; #endif + break; + } - return ret; -} - -int ber_pvt_sb_close( Sockbuf *sb ) -{ - int ret; - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io ); - assert( sb->sb_io->sbi_close ); - assert( status_is_ok(sb) ); - assert( ber_pvt_sb_in_use( sb ) ); + if ( ret <= 0 ) return ret; - ret = sb->sb_io->sbi_close( sb ); - ber_pvt_sb_set_desc( sb, -1 ); + buf_out->buf_ptr += ret; + if (buf_out->buf_ptr == buf_out->buf_end) { + buf_out->buf_end = buf_out->buf_ptr = 0; + } - return ret; -} + if ( (ber_len_t)ret < to_go ) { + /* not enough data, so pretend no data was sent. */ + return -1; + } -int ber_pvt_sb_set_readahead( Sockbuf *sb, int rh ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - sb->sb_read_ahead = (rh!=0); - return 0; + return ret; } -int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) +int +ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) { #if HAVE_FCNTL - int flags = fcntl(ber_pvt_sb_get_desc(sb), F_GETFL); + int flags = fcntl( sd, F_GETFL); if( nb ) { flags |= O_NONBLOCK; } else { flags &= ~O_NONBLOCK; } - return fcntl( ber_pvt_sb_get_desc(sb), F_SETFL, flags ); + return fcntl( sd, F_SETFL, flags ); #elif defined( FIONBIO ) ioctl_t status = nb ? 1 : 0; @@ -662,201 +339,105 @@ int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) #endif } -#define USE_NONBLOCK -#ifdef USE_NONBLOCK -int ber_pvt_sb_set_nonblock( Sockbuf *sb, int nb ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( status_is_ok(sb) ); - if (nb) { - sb->sb_non_block = 1; -#if 0 - sb->sb_read_ahead = 1; -#endif - } else { - sb->sb_non_block = 0; -#if 0 - sb->sb_read_ahead = 0; -#endif - } - if (ber_pvt_sb_in_use(sb)) { - return ber_pvt_socket_set_nonblock( - ber_pvt_sb_get_desc(sb), nb ); - } - return 0; -} -#endif - -#define sockbuf_buf_init( bb ) do { \ - Sockbuf_Buf *sbb = (bb); \ - sbb->buf_base = NULL; \ - sbb->buf_ptr = 0; \ - sbb->buf_end = 0; \ - sbb->buf_size = 0; \ - } while(0) - -static int -sockbuf_buf_destroy( Sockbuf_Buf *buf ) -{ - assert( buf != NULL); - - if (buf->buf_base) - LBER_FREE( buf->buf_base ); - sockbuf_buf_init( buf ); - return 0; -} - -int ber_pvt_sb_init( Sockbuf *sb ) +int +ber_int_sb_init( Sockbuf *sb ) { assert( sb != NULL); - ber_int_options.lbo_valid = LBER_INITIALIZED; - - sb->sb_valid=LBER_VALID_SOCKBUF; - sb->sb_options = 0; - sb->sb_debug = 0; - sb->sb_trans_ready = 0; - sb->sb_buf_ready = 0; -#ifdef USE_SASL - sb->sb_sec_ready = 0; -#endif - sb->sb_read_ahead = 1; /* test */ - sb->sb_non_block = 0; - sb->sb_trans_needs_read = 0; - sb->sb_trans_needs_write = 0; - sb->sb_fd = -1; - sb->sb_iodata = NULL; - sb->sb_io = &sb_IO_None; - sb->sb_sd = -1; -#ifdef DEADWOOD - sb->sb_max_incoming = 0; -#endif - sockbuf_buf_init( &(sb->sb_buf) ); -#ifdef USE_SASL - sockbuf_buf_init( &(sb->sb_sec_buf_in) ); - sockbuf_buf_init( &(sb->sb_sec_buf_out) ); - sb->sb_sdata = NULL; - sb->sb_sec = NULL; - sb->sb_sec_prev_len = 0; -#endif + sb->sb_valid=LBER_VALID_SOCKBUF; + sb->sb_options = 0; + sb->sb_debug = ber_int_debug; + sb->sb_fd = AC_SOCKET_INVALID; + sb->sb_iod = NULL; + sb->sb_trans_needs_read = 0; + sb->sb_trans_needs_write = 0; - assert( SOCKBUF_VALID( sb ) ); - return 0; + assert( SOCKBUF_VALID( sb ) ); + return 0; } -int ber_pvt_sb_destroy( Sockbuf *sb ) +int +ber_int_sb_close( Sockbuf *sb ) { - assert( sb != NULL); - assert( SOCKBUF_VALID(sb) ); -#ifdef USE_SASL - ber_pvt_sb_clear_sec(sb); - sockbuf_buf_destroy( &(sb->sb_sec_buf_in) ); - sockbuf_buf_destroy( &(sb->sb_sec_buf_out) ); -#endif - ber_pvt_sb_clear_io(sb); - sockbuf_buf_destroy( &(sb->sb_buf) ); - return ber_pvt_sb_init( sb ); -} + Sockbuf_IO_Desc *p; -#ifdef USE_SASL -int ber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg ) -{ - int len; assert( sb != NULL); - assert( SOCKBUF_VALID( *sb ) ); - if ((sb->sb_sec) || (sec==NULL)) - return -1; - - sb->sb_sec = sec; - if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) { - return -1; - } + p = sb->sb_iod; + while ( p ) { + if ( p->sbiod_io->sbi_close && + p->sbiod_io->sbi_close( p ) < 0 ) + { + return -1; + } + p = p->sbiod_next; + } - len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr; + sb->sb_fd = AC_SOCKET_INVALID; - if (len>0) { - /* move this to the security layer. */ - if (grow_buffer( &(sb->sb_sec_buf_in), len )<0) - return -1; - memcpy( sb->sb_sec_buf_in.buf_base, - sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len ); - sb->sb_sec_buf_in.buf_ptr = len; - sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb, sb->sb_sec_buf_in ) : 0; - sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0; - } - update_status( sb ); - return 0; + return 0; } -int ber_pvt_sb_clear_sec( Sockbuf *sb ) +int +ber_int_sb_destroy( Sockbuf *sb ) { + Sockbuf_IO_Desc *p; + assert( sb != NULL); assert( SOCKBUF_VALID( sb ) ); - - if (sb->sb_buf.buf_ptr!=0) - return -1; - if (sb->sb_sec==NULL) - return -1; - if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) - return -1; - - sb->sb_sec = NULL; - if (sb->sb_sec_buf_in.buf_ptr!=0) { - if (grow_buffer( &(sb->sb_buf), - sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0) - return -1; - memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end, - sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr ); - sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr; - sb->sb_buf_ready = 1; - } - sockbuf_buf_destroy( &(sb->sb_sec_buf_in) ); - assert( sb->sb_sec_buf.buf_end==0 ); - sockbuf_buf_destroy( &(sb->sb_sec_buf_out) ); - - sb->sb_sec_ready = 0; - return 0; + while ( sb->sb_iod ) { + p = sb->sb_iod->sbiod_next; + ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io, + sb->sb_iod->sbiod_level ); + sb->sb_iod = p; + } + + return ber_int_sb_init( sb ); } -#endif -int ber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg ) +ber_slen_t +ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len ) { + ber_slen_t ret; + + assert( buf != NULL ); assert( sb != NULL); + assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &sb_IO_None ); - if (trans==NULL) - return -1; - - sb->sb_io = trans; - - if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0)) - return -1; - - return 0; + for (;;) { + ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len ); + +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; +#endif + break; + } + + return ret; } -int ber_pvt_sb_clear_io( Sockbuf *sb ) +ber_slen_t +ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) { + ber_slen_t ret; + + assert( buf != NULL ); assert( sb != NULL); + assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); - if (sb->sb_io==&sb_IO_None) - return -1; - - if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0)) - return -1; + for (;;) { + ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); - sb->sb_io = &sb_IO_None; - - sb->sb_trans_ready = 0; - sb->sb_trans_needs_read = 0; - sb->sb_trans_needs_write = 0; +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; +#endif + break; + } - return 0; + return ret; } /* @@ -864,16 +445,16 @@ int ber_pvt_sb_clear_io( Sockbuf *sb ) */ static ber_slen_t -stream_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ - return tcpread( ber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, + return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, len, NULL ); #elif defined( HAVE_PCNFS ) || \ @@ -887,42 +468,50 @@ stream_read( Sockbuf *sb, void *buf, ber_len_t len ) /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ - { - int rc; - rc = recv( ber_pvt_sb_get_desc(sb), buf, len, 0 ); + { + int rc; + + rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); + #ifdef HAVE_WINSOCK - if ( rc < 0 ) errno = WSAGetLastError(); + if ( rc < 0 ) { + int err; + + err = WSAGetLastError(); + errno = err; + } #endif - return rc; - } + + return rc; + } + #elif defined( HAVE_NCSA ) /* * NCSA Telnet TCP/IP stack (under DOS) */ - return nread( ber_pvt_sb_get_desc(sb), buf, len ); + return nread( sbiod->sbiod_sb->sb_fd, buf, len ); #else - return read( ber_pvt_sb_get_desc(sb), buf, len ); + return read( sbiod->sbiod_sb->sb_fd, buf, len ); #endif } static ber_slen_t -stream_write( Sockbuf *sb, void *buf, ber_len_t len ) +sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ #define MAX_WRITE 65535 - return tcpwrite( ber_pvt_sb_get_desc(sb), - (unsigned char *)(buf), - (lensbiod_sb->sb_fd, (unsigned char *)buf, + (lensbiod_sb->sb_fd, buf, len, 0 ); - { - int rc; - rc = send( ber_pvt_sb_get_desc(sb), buf, len, 0 ); #ifdef HAVE_WINSOCK - if ( rc < 0 ) errno = WSAGetLastError(); + if ( rc < 0 ) { + int err; + err = WSAGetLastError(); + errno = err; + } #endif - return rc; - } + return rc; + } #elif defined(HAVE_NCSA) - return netwrite( ber_pvt_sb_get_desc(sb), buf, len ); + return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); #elif defined(VMS) /* * VMS -- each write must be 64K or smaller */ #define MAX_WRITE 65535 - return write( ber_pvt_sb_get_desc(sb), buf, - (lensbiod_sb->sb_fd, buf, + (lensbiod_sb->sb_fd, buf, len ); #endif } static int -stream_close( Sockbuf *sb ) +sb_stream_close( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); - tcp_close( ber_pvt_sb_get_desc( sb ) ); + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; } -Sockbuf_IO ber_pvt_sb_io_tcp= -{ - NULL, /* sbi_setup */ - NULL, /* sbi_release */ - stream_read, /* sbi_read */ - stream_write, /* sbi_write */ - stream_close, /* sbi_close */ +/* The argument is a pointer to the socket descriptor */ +static int +sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { + assert( sbiod != NULL ); + + if ( arg != NULL ) { + sbiod->sbiod_sb->sb_fd = *((int *)arg); + } + return 0; +} + +static int +sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { + /* This is an end IO descriptor */ + return 0; +} + +Sockbuf_IO ber_sockbuf_io_tcp = { + sb_stream_setup, /* sbi_setup */ + NULL, /* sbi_remove */ + sb_stream_ctrl, /* sbi_ctrl */ + sb_stream_read, /* sbi_read */ + sb_stream_write, /* sbi_write */ + sb_stream_close /* sbi_close */ }; + /* - * Support for UDP (CLDAP) + * Support for readahead (UDP needs it) */ -struct dgram_data +static int +sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { - struct sockaddr dst; - struct sockaddr src; -}; + Sockbuf_Buf *p; -static int -dgram_setup( Sockbuf *sb, void *arg ) -{ - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); - sb->sb_iodata = LBER_MALLOC( sizeof( struct dgram_data ) ); - if (sb->sb_iodata==NULL) - return -1; - sb->sb_read_ahead = 1; /* important since udp is packet based. */ - return 0; + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) return -1; + + ber_pvt_sb_buf_init( p ); + + if ( arg == NULL ) { + ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD ); + } else { + ber_pvt_sb_grow_buffer( p, *((int *)arg) ); + } + + sbiod->sbiod_pvt = p; + return 0; } -static int -dgram_release( Sockbuf *sb ) +static int +sb_rdahead_remove( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL); - assert( SOCKBUF_VALID( sb ) ); + Sockbuf_Buf *p; - LBER_FREE( sb->sb_iodata ); - return 0; + assert( sbiod != NULL ); + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + if ( p->buf_ptr != p->buf_end ) return -1; + + ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + + return 0; } static ber_slen_t -dgram_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { -#ifdef LDAP_CONNECTIONLESS - ber_slen_t rc; - socklen_t addrlen; - struct dgram_data *dd; - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( buf != NULL ); + Sockbuf_Buf *p; + ber_slen_t bufptr = 0, ret, max; - dd = (struct dgram_data *)(sb->sb_iodata); - - addrlen = sizeof( struct sockaddr ); - rc=recvfrom( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen ); - - if ( sb->sb_debug ) { - ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug, - "dgram_read udp_read %ld bytes\n", - (long) rc ); - if ( rc > 0 ) - ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug, - buf, rc ); - } - return rc; -# else /* LDAP_CONNECTIONLESS */ - return -1; -# endif /* LDAP_CONNECTIONLESS */ + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + assert( sbiod->sbiod_next != NULL ); + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + assert( p->buf_size > 0 ); + + /* Are there anything left in the buffer? */ + ret = ber_pvt_sb_copy_out( p, buf, len ); + bufptr += ret; + len -= ret; + + if ( len == 0 ) return bufptr; + + max = p->buf_size - p->buf_end; + ret = 0; + while ( max > 0 ) { + ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end, + max ); +#ifdef EINTR + if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; +#endif + break; + } + + if ( ret < 0 ) { + return ( bufptr ? bufptr : ret ); + } + + p->buf_end += ret; + bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len ); + return bufptr; } -static ber_slen_t -dgram_write( Sockbuf *sb, void *buf, ber_len_t len ) +static ber_slen_t +sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { -#ifdef LDAP_CONNECTIONLESS - ber_slen_t rc; - struct dgram_data *dd; - - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( buf != NULL ); + assert( sbiod != NULL ); + assert( sbiod->sbiod_next != NULL ); - dd = (struct dgram_data *)(sb->sb_iodata); - - rc=sendto( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst), - sizeof( struct sockaddr ) ); - - if ( rc <= 0 ) - return( -1 ); - - /* fake error if write was not atomic */ - if (rc < len) { -# ifdef EMSGSIZE - errno = EMSGSIZE; -# endif - return( -1 ); - } - return rc; -#else - return -1; -#endif + return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); } -static int -dgram_close( Sockbuf *sb ) +static int +sb_rdahead_close( Sockbuf_IO_Desc *sbiod ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL ); - tcp_close( ber_pvt_sb_get_desc(sb) ); + /* Just erase the buffer */ + ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt); return 0; } -Sockbuf_IO ber_pvt_sb_io_udp= +static int +sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { - dgram_setup, /* sbi_setup */ - dgram_release, /* sbi_release */ - dgram_read, /* sbi_read */ - dgram_write, /* sbi_write */ - dgram_close, /* sbi_close */ + Sockbuf_Buf *p; + + p = (Sockbuf_Buf *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_DATA_READY ) { + if ( p->buf_ptr != p->buf_end ) { + return 1; + } + + } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) { + if ( p->buf_size >= *((ber_len_t *)arg) ) { + return 0; + } + return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ? + -1 : 1 ); + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +Sockbuf_IO ber_sockbuf_io_readahead = { + sb_rdahead_setup, /* sbi_setup */ + sb_rdahead_remove, /* sbi_remove */ + sb_rdahead_ctrl, /* sbi_ctrl */ + sb_rdahead_read, /* sbi_read */ + sb_rdahead_write, /* sbi_write */ + sb_rdahead_close /* sbi_close */ }; -int ber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr ) +/* + * Support for simple file IO + */ + +static ber_slen_t +sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - struct dgram_data *dd; - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &ber_pvt_sb_io_udp ); - dd = (struct dgram_data *) (sb->sb_iodata); - memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) ); - return 0; + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + return read( sbiod->sbiod_sb->sb_fd, buf, len ); } -void *ber_pvt_sb_udp_get_src( Sockbuf *sb ) +static ber_slen_t +sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - struct dgram_data *dd; + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); - assert( sb->sb_io == &ber_pvt_sb_io_udp ); - dd = (struct dgram_data *) (sb->sb_iodata); - return &(dd->src); + return write( sbiod->sbiod_sb->sb_fd, buf, len ); +} + +static int +sb_fd_close( Sockbuf_IO_Desc *sbiod ) +{ + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + close( sbiod->sbiod_sb->sb_fd ); + return 0; } +/* The argument is a pointer to the file descriptor */ +static int +sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { + assert( sbiod != NULL ); + + if ( arg != NULL ) + sbiod->sbiod_sb->sb_fd = *((int *)arg); + return 0; +} + +static int +sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) { + /* This is an end IO descriptor */ + return 0; +} + +Sockbuf_IO ber_sockbuf_io_fd = { + sb_fd_setup, /* sbi_setup */ + NULL, /* sbi_remove */ + sb_fd_ctrl, /* sbi_ctrl */ + sb_fd_read, /* sbi_read */ + sb_fd_write, /* sbi_write */ + sb_fd_close /* sbi_close */ +}; + /* - * debug routines. - * - * BUGS: - * These routines should really call abort, but at the moment that would - * break the servers. + * Debugging layer */ +static int +sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + assert( sbiod != NULL ); + + if ( arg == NULL ) arg = "sockbuf_"; + + sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 ); + if ( sbiod->sbiod_pvt == NULL ) return -1; + + strcpy( (char *)sbiod->sbiod_pvt, (char *)arg ); + return 0; +} + +static int +sb_debug_remove( Sockbuf_IO_Desc *sbiod ) +{ + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static int +sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +static ber_slen_t +sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + ber_slen_t ret; + + ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len ); + if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) + { + int err = errno; + if ( ret < 0 ) { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt, + (long)len, STRERROR( errno ) ); + } else { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt, + (long)len, (long)ret ); + ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + (const char *)buf, ret ); + } + errno = err; + } + return ret; +} + static ber_slen_t -have_no_read( Sockbuf *sb, void *buf, ber_len_t len ) +sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + ber_slen_t ret; + + ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ); + if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) + { + int err = errno; + if ( ret < 0 ) { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%swrite: want=%ld error=%s\n", + (char *)sbiod->sbiod_pvt, (long)len, + STRERROR( errno ) ); + errno = err; + } else { + ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + "%swrite: want=%ld, written=%ld\n", + (char *)sbiod->sbiod_pvt, (long)len, (long)ret ); + ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug, + (const char *)buf, ret ); + } + errno = err; + } + + return ret; +} + +Sockbuf_IO ber_sockbuf_io_debug = { + sb_debug_setup, /* sbi_setup */ + sb_debug_remove, /* sbi_remove */ + sb_debug_ctrl, /* sbi_ctrl */ + sb_debug_read, /* sbi_read */ + sb_debug_write, /* sbi_write */ + NULL /* sbi_close */ +}; + +#ifdef LDAP_CONNECTIONLESS + +/* + * Support for UDP (CLDAP) + * + * All I/O at this level must be atomic. For ease of use, the sb_readahead + * must be used above this module. All data reads and writes are prefixed + * with a sockaddr containing the address of the remote entity. Upper levels + * must read and write this sockaddr before doing the usual ber_printf/scanf + * operations on LDAP messages. + */ + +static int +sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + assert( sbiod != NULL); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); - ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug, - "warning: reading from uninitialized sockbuf\n"); - errno = EBADF; - return -1; + if ( arg != NULL ) + sbiod->sbiod_sb->sb_fd = *((int *)arg); + return 0; } static ber_slen_t -have_no_write( Sockbuf *sb, void *buf, ber_len_t len ) +sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); + ber_slen_t rc; + socklen_t addrlen; + struct sockaddr *src; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + assert( buf != NULL ); + + addrlen = sizeof( struct sockaddr ); + src = buf; + buf += addrlen; + rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, + &addrlen ); - ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug, - "warning: writing to uninitialized sockbuf\n"); - errno = EBADF; - return -1; + return rc > 0 ? rc+sizeof(struct sockaddr) : rc; +} + +static ber_slen_t +sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) +{ + ber_slen_t rc; + struct sockaddr *dst; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + assert( buf != NULL ); + + dst = buf; + buf += sizeof( struct sockaddr ); + len -= sizeof( struct sockaddr ); + + rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, + sizeof( struct sockaddr ) ); + + if ( rc < 0 ) + return -1; + + /* fake error if write was not atomic */ + if (rc < len) { +# ifdef EMSGSIZE + errno = EMSGSIZE; +# endif + return -1; + } + rc = len + sizeof(struct sockaddr); + return rc; } static int -have_no_close( Sockbuf *sb ) -{ - assert( sb != NULL ); - assert( SOCKBUF_VALID( sb ) ); +sb_dgram_close( Sockbuf_IO_Desc *sbiod ) +{ + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + tcp_close( sbiod->sbiod_sb->sb_fd ); + return 0; +} - assert( 0 ); - return -1; +static int +sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + /* This is an end IO descriptor */ + return 0; } + +Sockbuf_IO ber_sockbuf_io_udp = +{ + sb_dgram_setup, /* sbi_setup */ + NULL, /* sbi_remove */ + sb_dgram_ctrl, /* sbi_ctrl */ + sb_dgram_read, /* sbi_read */ + sb_dgram_write, /* sbi_write */ + sb_dgram_close /* sbi_close */ +}; + +#endif /* LDAP_CONNECTIONLESS */