]> git.sur5r.net Git - openldap/commitdiff
ITS#537: lber io rewrite from Gambor Gombas.
authorKurt Zeilenga <kurt@openldap.org>
Thu, 1 Jun 2000 20:59:21 +0000 (20:59 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Thu, 1 Jun 2000 20:59:21 +0000 (20:59 +0000)
Copyright 2000 Gábor Gombás. All rights reserved.
This is free software. You may redistribute and use it under the same
terms as OpenLDAP itself.

27 files changed:
include/lber.h
include/lber_pvt.h
libraries/liblber/dtest.c
libraries/liblber/etest.c
libraries/liblber/io.c
libraries/liblber/lber-int.h
libraries/liblber/sockbuf.c
libraries/libldap/abandon.c
libraries/libldap/cldap.c
libraries/libldap/kbind.c
libraries/libldap/ldap-int.h
libraries/libldap/open.c
libraries/libldap/options.c
libraries/libldap/os-ip.c
libraries/libldap/os-local.c
libraries/libldap/request.c
libraries/libldap/result.c
libraries/libldap/sasl.c
libraries/libldap/test.c
libraries/libldap/tls.c
libraries/libldap/unbind.c
servers/ldapd/main.c
servers/ldapd/request.c
servers/ldapd/result.c
servers/ldapd/search.c
servers/slapd/connection.c
servers/slapd/result.c

index 515b45b19b929fc82c0205f4866cbe5424460b51..fb49db32b2b0af90c83b97a26f441bb9ab8253e0 100644 (file)
@@ -123,11 +123,26 @@ typedef struct lber_memory_fns {
        BER_MEMFREE_FN bmf_free;
 } BerMemoryFunctions;
 
-/* LBER Sockbuf options */ 
-#define LBER_TO_FILE           0x01    /* to a file referenced by sb_fd   */
-#define LBER_TO_FILE_ONLY      0x02    /* only write to file, not network */
-#define LBER_MAX_INCOMING_SIZE 0x04    /* impose limit on incoming stuff  */
-#define LBER_NO_READ_AHEAD     0x08    /* read only as much as requested  */
+/* LBER Sockbuf_IO options */ 
+#define LBER_SB_OPT_GET_FD             1
+#define LBER_SB_OPT_SET_FD             2
+#define LBER_SB_OPT_HAS_IO             3
+#define LBER_SB_OPT_SET_NONBLOCK       4
+#define LBER_SB_OPT_UDP_GET_SRC                5
+#define LBER_SB_OPT_UDP_SET_DST                6
+#define LBER_SB_OPT_GET_SSL            7
+#define LBER_SB_OPT_DATA_READY         8
+#define LBER_SB_OPT_SET_READAHEAD      9
+#define LBER_SB_OPT_DRAIN              10
+#define LBER_SB_OPT_NEEDS_READ         11
+#define LBER_SB_OPT_NEEDS_WRITE                12
+/* Largest option used by the library */
+#define LBER_SB_OPT_OPT_MAX            12
+
+/* LBER IO operations stacking levels */
+#define LBER_SBIOD_LEVEL_PROVIDER      10
+#define LBER_SBIOD_LEVEL_TRANSPORT     20
+#define LBER_SBIOD_LEVEL_APPLICATION   30
 
 /* get/set options for Sockbuf */
 #define LBER_OPT_SOCKBUF_DESC          0x1000
@@ -145,6 +160,43 @@ typedef struct berelement BerElement;
 typedef struct sockbuf Sockbuf;
 typedef struct seqorset Seqorset;
 
+typedef struct sockbuf_io Sockbuf_IO;
+
+/* Structure for LBER IO operarion descriptor */
+typedef struct sockbuf_io_desc {
+       int                     sbiod_level;
+       Sockbuf                 *sbiod_sb;
+       Sockbuf_IO              *sbiod_io;
+       void                    *sbiod_pvt;
+       struct sockbuf_io_desc  *sbiod_next;
+} Sockbuf_IO_Desc;
+
+/* Structure for LBER IO operation functions */
+struct sockbuf_io {
+       int (*sbi_setup)( Sockbuf_IO_Desc *sbiod, void *arg );
+       int (*sbi_remove)( Sockbuf_IO_Desc *sbiod );
+       int (*sbi_ctrl)( Sockbuf_IO_Desc *sbiod, int opt, void *arg);
+       
+       ber_slen_t (*sbi_read)( Sockbuf_IO_Desc *sbiod, void *buf,
+               ber_len_t len );
+       ber_slen_t (*sbi_write)( Sockbuf_IO_Desc *sbiod, void *buf,
+               ber_len_t len );
+       
+       int (*sbi_close)( Sockbuf_IO_Desc *sbiod );
+};
+
+/* Helper macros for LBER IO functions */
+#define LBER_SBIOD_READ_NEXT( sbiod, buf, len ) \
+       ( (sbiod)->sbiod_next->sbiod_io->sbi_read( (sbiod)->sbiod_next, \
+               buf, len ) )
+#define LBER_SBIOD_WRITE_NEXT( sbiod, buf, len ) \
+       ( (sbiod)->sbiod_next->sbiod_io->sbi_write( (sbiod)->sbiod_next, \
+               buf, len ) )
+#define LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ) \
+       ( (sbiod)->sbiod_next ? \
+               ( (sbiod)->sbiod_next->sbiod_io->sbi_ctrl( \
+               (sbiod)->sbiod_next, opt, arg ) ) : 0 )
+
 /* structure for returning a sequence of octet strings + length */
 typedef struct berval {
        ber_len_t       bv_len;
@@ -428,16 +480,38 @@ ber_set_option LDAP_P((
  * LBER sockbuf.c
  */
 
-LIBLBER_F( Sockbuf * )
-ber_sockbuf_alloc( void );
-
 LIBLBER_F( Sockbuf *  )
-ber_sockbuf_alloc_fd(
-       ber_socket_t fd );
+ber_sockbuf_alloc LDAP_P((
+       void ));
 
 LIBLBER_F( void )
-ber_sockbuf_free(
-       Sockbuf *sb );
+ber_sockbuf_free LDAP_P((
+       Sockbuf *sb ));
+
+LIBLBER_F( int )
+ber_sockbuf_add_io LDAP_P((
+       Sockbuf *sb,
+       Sockbuf_IO *sbio,
+       int layer,
+       void *arg ));
+
+LIBLBER_F( int )
+ber_sockbuf_remove_io LDAP_P((
+       Sockbuf *sb,
+       Sockbuf_IO *sbio,
+       int layer ));
+
+LIBLBER_F( int )
+ber_sockbuf_ctrl LDAP_P((
+       Sockbuf *sb,
+       int opt,
+       void *arg ));
+
+LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_tcp;
+LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_udp;
+LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_readahead;
+LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_fd;
+LIBLBER_F( Sockbuf_IO ) ber_sockbuf_io_debug;
 
 /*
  * LBER memory.c
index 2a57ba11c642146fe49cabee5bf330587eccc2d5..e314205f4781fb096aff0f1516ea97357b3f0b0b 100644 (file)
 
 LDAP_BEGIN_DECL
 
+typedef struct sockbuf_buf {
+       ber_len_t               buf_size;
+       ber_len_t               buf_ptr;
+       ber_len_t               buf_end;
+       char                    *buf_base;
+} Sockbuf_Buf;
+
 /*
  * bprint.c
  */
@@ -32,6 +39,27 @@ ber_pvt_log_printf LDAP_P((
        const char *fmt,
        ... )) LDAP_GCCATTR((format(printf, 3, 4)));
 
+/*
+ * sockbuf.c
+ */
+LIBLBER_F( ber_slen_t )
+ber_pvt_sb_do_write LDAP_P(( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out ));
+
+LIBLBER_F( void )
+ber_pvt_sb_buf_init LDAP_P(( Sockbuf_Buf *buf ));
+
+LIBLBER_F( void )
+ber_pvt_sb_buf_destroy LDAP_P(( Sockbuf_Buf *buf ));
+
+LIBLBER_F( int )
+ber_pvt_sb_grow_buffer LDAP_P(( Sockbuf_Buf *buf, ber_len_t minsize ));
+
+LIBLBER_F( ber_len_t )
+ber_pvt_sb_copy_out LDAP_P(( Sockbuf_Buf *sbb, char *buf, ber_len_t len ));
+
+LIBLBER_F( int )
+ber_pvt_socket_set_nonblock LDAP_P(( ber_socket_t sd, int nb ));
+
 LDAP_END_DECL
 
 #endif
index 144445ece92cc9d5a9eec1b1a177cfb23c418b20..633d42ed7edaaf8ffa3652fbc46af920dee91132 100644 (file)
@@ -47,6 +47,7 @@ main( int argc, char **argv )
 
        BerElement      *ber;
        Sockbuf         *sb;
+       int             fd;
 
        /* enable debugging */
        int ival = -1;
@@ -62,7 +63,10 @@ main( int argc, char **argv )
        cshow( stdout );
 #endif
 
-       sb = ber_sockbuf_alloc_fd( fileno(stdin) );
+       sb = ber_sockbuf_alloc();
+       fd = fileno( stdin );
+       ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER,
+               (void *)&fd );
 
        if( (ber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
                perror( "ber_alloc_t" );
index 0dcf7d71117c780ad42e990dcac3183cf2cf54fb..01c10e99071c2a7ef43d51e90d817b82afc28d2d 100644 (file)
@@ -75,7 +75,9 @@ main( int argc, char **argv )
        fd = fileno(stdout);
 #endif
 
-       sb = ber_sockbuf_alloc_fd( fd );
+       sb = ber_sockbuf_alloc();
+       ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd, LBER_SBIOD_LEVEL_PROVIDER,
+               (void *)&fd );
 
        if( sb == NULL ) {
                perror( "ber_sockbuf_alloc_fd" );
index a31d23daf52e79766b44a6cd80c05066e14eda48..859b70c13726b03a809acf1f8b8d3e07e1445ed5 100644 (file)
@@ -64,7 +64,7 @@ BerRead(
        assert( SOCKBUF_VALID( sb ) );
 
        while ( len > 0 ) {
-               if ( (c = ber_pvt_sb_read( sb, buf, len )) <= 0 ) {
+               if ( (c = ber_int_sb_read( sb, buf, len )) <= 0 ) {
                        if ( nread > 0 )
                                break;
                        return( c );
@@ -232,26 +232,15 @@ ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
        if ( sb->sb_debug ) {
                ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
                        "ber_flush: %ld bytes to sd %ld%s\n", towrite,
-                   (long) sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
-                   : "" );
+                   (long) sb->sb_fd, ber->ber_rwptr != ber->ber_buf ?
+                   " (re-flush)" : "" );
                ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
                        ber->ber_rwptr, towrite );
        }
 
-#if HAVE_WRITE
-       if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) {
-               rc = write( sb->sb_fd, ber->ber_rwptr, towrite );
-               if ( sb->sb_options & LBER_TO_FILE_ONLY ) {
-                       if ( freeit )
-                               ber_free( ber, 1 );
-                       return( (int)rc );
-               }
-       }
-#endif
-       
        nwritten = 0;
        do {
-               rc = ber_pvt_sb_write( sb, ber->ber_rwptr, towrite );
+               rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite );
                if (rc<=0) {
                        return -1;
                }
@@ -446,7 +435,7 @@ get_tag( Sockbuf *sb )
        assert( sb != NULL );
        assert( SOCKBUF_VALID( sb ) );
 
-       if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
+       if ( ber_int_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
                return( LBER_DEFAULT );
 
        if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
@@ -455,7 +444,7 @@ get_tag( Sockbuf *sb )
        tagp = (char *) &tag;
        tagp[0] = xbyte;
        for ( i = 1; i < sizeof(ber_tag_t); i++ ) {
-               if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
+               if ( ber_int_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
                        return( LBER_DEFAULT );
 
                tagp[i] = xbyte;
@@ -522,7 +511,7 @@ ber_get_next(
        
        if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) {
                if (ber->ber_rwptr == (char *) &ber->ber_tag) {
-                       if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
+                       if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0)
                                return LBER_DEFAULT;
                        if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK)
                                != LBER_BIG_TAG_MASK) {
@@ -534,7 +523,7 @@ ber_get_next(
                }
                do {
                        /* reading the tag... */
-                       if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
+                       if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0)
                                return LBER_DEFAULT;
                        if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) {
                                ber->ber_tag>>=sizeof(ber->ber_tag) -
@@ -550,7 +539,7 @@ ber_get_next(
 get_lenbyte:
        if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
                unsigned char c;
-               if (ber_pvt_sb_read( sb, (char *) &c, 1)<=0)
+               if (ber_int_sb_read( sb, (char *) &c, 1)<=0)
                        return LBER_DEFAULT;
                if (c & 0x80U) {
                        int len = c & 0x7fU;
@@ -611,7 +600,7 @@ fill_buffer:
                to_go = ber->ber_end - ber->ber_rwptr;
                assert( to_go > 0 );
                
-               res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
+               res = ber_int_sb_read( sb, ber->ber_rwptr, to_go );
                if (res<=0)
                        return LBER_DEFAULT;
                ber->ber_rwptr+=res;
index 10b8b2cbd7410cc2d83edfee79ad5e2ed710aafd..70d10c044778d6a3f0c5334ac56c7d9cf4b0fd9d 100644 (file)
@@ -28,15 +28,15 @@ LIBLBER_F (BER_ERRNO_FN) ber_int_errno_fn;
 
 struct lber_options {
        short lbo_valid;
+       unsigned short          lbo_options;
+       int                     lbo_debug;
+};
+
 #define LBER_UNINITIALIZED             0x0
 #define LBER_INITIALIZED               0x1
 #define LBER_VALID_BERELEMENT  0x2
 #define LBER_VALID_SOCKBUF             0x3
 
-       unsigned short lbo_options;
-       int lbo_debug;
-};
-
 LIBLBER_F (struct lber_options) ber_int_options;
 #define ber_int_debug ber_int_options.lbo_debug
 
@@ -62,106 +62,21 @@ struct berelement {
 };
 #define BER_VALID(ber) ((ber)->ber_valid==LBER_VALID_BERELEMENT)
 
-
 #define ber_pvt_ber_bytes(ber)         ((ber)->ber_ptr - (ber)->ber_buf)
 #define ber_pvt_ber_remaining(ber)     ((ber)->ber_end - (ber)->ber_ptr)
 
-struct sockbuf;
-
-struct sockbuf_io {
-       int     (*sbi_setup)( struct sockbuf * sb, void *arg );
-       int     (*sbi_remove)( struct sockbuf *sb );
-       
-       ber_slen_t      (*sbi_read)( struct sockbuf *sb, void *buf, ber_len_t len );
-       ber_slen_t      (*sbi_write)( struct sockbuf *sb, void *buf, ber_len_t len );
-       int     (*sbi_close)( struct sockbuf *sb );
-};
-
-struct sockbuf_sec {
-       int     (*sbs_setup)( struct sockbuf * sb, void *arg );
-       int     (*sbs_remove)( struct sockbuf *sb );
-   
-       long    (*sbs_protect)( struct sockbuf *sb, char *in, long *ilen,
-                               char *out, long olen );
-       long    (*sbs_release)( struct sockbuf *sb, char *in, long ilen,
-                              char *out0, long olen0, char *out1, long olen1 );
-};
-
-struct sockbuf_buf {
-       ber_len_t       buf_size;
-       ber_len_t       buf_ptr;
-       ber_len_t       buf_end;
-       char    *buf_base;
-};
-
-typedef struct sockbuf_io Sockbuf_IO;
-typedef struct sockbuf_sec Sockbuf_Sec;
-typedef struct sockbuf_buf Sockbuf_Buf;
-
-LIBLBER_F( Sockbuf_IO ) ber_pvt_sb_io_tcp;
-LIBLBER_F( Sockbuf_IO ) ber_pvt_sb_io_udp;
-
-
 struct sockbuf {
        struct lber_options sb_opts;
+       Sockbuf_IO_Desc         *sb_iod;                /* I/O functions */
 #define        sb_valid                sb_opts.lbo_valid
 #define        sb_options              sb_opts.lbo_options
 #define        sb_debug                sb_opts.lbo_debug
-
-       int             sb_non_block:1; 
-       int             sb_read_ahead:1;
-   
-       int             sb_buf_ready:1;
-       int             sb_trans_ready:1;
-       int             sb_sec_ready:1;
-      
-       /* these bits indicate if the transport layer 
-        * needs to read or write 
-        */
+       ber_socket_t            sb_fd;
        int             sb_trans_needs_read:1;
        int             sb_trans_needs_write:1;
-
-       int             sb_fd;
-   
-       void            *sb_iodata;     /* transport-layer data pointer */
-       Sockbuf_IO      *sb_io;         /* I/O functions */
-   
-#ifdef LDAP_SASL
-       void            *sb_sdata;      /* security-layer data pointer */
-       Sockbuf_Sec     *sb_sec;
-#endif 
-
-       ber_socket_t    sb_sd;
-
-#ifdef DEADWOOD
-       long            sb_max_incoming;
-#endif
-       Sockbuf_Buf     sb_buf;
-#ifdef LDAP_SASL   
-       Sockbuf_Buf     sb_sec_buf_in;
-       Sockbuf_Buf     sb_sec_buf_out;
-       ber_len_t       sb_sec_prev_len;
-#endif   
 };
-#define SOCKBUF_VALID(ber)     ((sb)->sb_valid==LBER_VALID_SOCKBUF)
 
-/* these should be internal ie: ber_int_* */
-#define        ber_pvt_sb_get_desc( sb ) ((sb)->sb_sd)
-#define ber_pvt_sb_set_desc( sb, val ) ((sb)->sb_sd =(val))
-
-#define ber_pvt_sb_in_use( sb ) ((sb)->sb_sd != AC_SOCKET_INVALID)
-
-#ifdef USE_SASL
-#define ber_pvt_sb_data_ready( sb ) \
-(((sb)->sb_buf_ready) || ((sb)->sb_trans_ready) || ((sb)->sb_sec_ready))
-#else
-#define ber_pvt_sb_data_ready( sb ) \
-(((sb)->sb_buf_ready) || ((sb)->sb_trans_ready))
-#endif
-#define ber_pvt_sb_needs_read( sb ) \
-((sb)->sb_trans_needs_read)
-#define ber_pvt_sb_needs_write( sb ) \
-((sb)->sb_trans_needs_write)
+#define SOCKBUF_VALID( sb )    ( (sb)->sb_valid == LBER_VALID_SOCKBUF )
 
 #define READBUFSIZ     8192
 
@@ -245,51 +160,20 @@ LIBLBER_F (BerMemoryFunctions *)  ber_int_memory_fns;
 
 /* sockbuf.c */
 
-/* these should be ber_int*() functions */
-
-LIBLBER_F( int )
-ber_pvt_sb_init LDAP_P(( Sockbuf *sb ));
-
 LIBLBER_F(     int )
-ber_pvt_sb_destroy LDAP_P(( Sockbuf *sb ));
+ber_int_sb_init LDAP_P(( Sockbuf *sb ));
 
-#ifdef USE_SASL
 LIBLBER_F( int )
-ber_pvt_sb_set_sec LDAP_P(( Sockbuf *sb, Sockbuf_Sec *sec, void *arg ));
-
-LIBLBER_F( int )
-ber_pvt_sb_clear_sec LDAP_P(( Sockbuf *sb ));
-#endif
+ber_int_sb_close LDAP_P(( Sockbuf *sb ));
 
 LIBLBER_F(     int )
-ber_pvt_sb_set_io LDAP_P(( Sockbuf *sb, Sockbuf_IO *layer, void *arg ));
-
-LIBLBER_F(     int )
-ber_pvt_sb_clear_io LDAP_P(( Sockbuf *sb ));
-
-LIBLBER_F(     int )
-ber_pvt_sb_close LDAP_P((Sockbuf *sb ));
-
-LIBLBER_F( int )
-ber_pvt_sb_set_nonblock LDAP_P(( Sockbuf *sb, int nb ));
-
-LIBLBER_F( int )
-ber_pvt_sb_set_readahead LDAP_P(( Sockbuf *sb, int rh ));
+ber_int_sb_destroy LDAP_P(( Sockbuf *sb ));
 
 LIBLBER_F( ber_slen_t )
-ber_pvt_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
+ber_int_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
 
 LIBLBER_F( ber_slen_t )
-ber_pvt_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
-
-LIBLBER_F(     int )
-ber_pvt_sb_udp_set_dst LDAP_P((Sockbuf *sb, void *addr ));
-
-LIBLBER_F(     void * )
-ber_pvt_sb_udp_get_src LDAP_P((Sockbuf *sb ));
-
-LIBLBER_F( int )
-ber_pvt_socket_set_nonblock LDAP_P(( ber_socket_t sd, int nb ));
+ber_int_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
 
 LDAP_END_DECL
 
index 2b9bb8799a4cba647ec07956b296c81223f6a974..5cdda86ad93c7a8363a6d7b0cc2f219702debad5 100644 (file)
 
 #include "lber-int.h"
 
-#ifdef LDAP_TEST
-#undef TEST_PARTIAL_READ
-#undef TEST_PARTIAL_WRITE
-#endif
-
-#define MAX_BUF_SIZE   65535
-#define MIN_BUF_SIZE   4096
-
-#define sockbuf_io_write( sb, buf, len ) \
-((sb)->sb_io->sbi_write( (sb), (buf), (len) ))
+#define MIN_BUFF_SIZE          4096
+#define MAX_BUFF_SIZE          65536
+#define DEFAULT_READAHEAD      16384
 
-#define sockbuf_io_read( sb, buf, len ) \
-((sb)->sb_io->sbi_read( (sb), (buf), (len) ))
+Sockbuf *
+ber_sockbuf_alloc( void )
+{
+       Sockbuf                 *sb;
 
-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 );
+       ber_int_options.lbo_valid = LBER_INITIALIZED;
 
-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 */
-};
+       sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
 
-static void
-update_status( Sockbuf *sb )
-{
-       assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
+       if( sb == NULL )
+               return NULL;
 
-   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_init( sb );
+       return sb;
 }
 
-#ifdef LDAP_DEBUG
-static int 
-status_is_ok( Sockbuf *sb )
+void
+ber_sockbuf_free( Sockbuf *sb )
 {
-       int obr;
-#ifdef USE_SASL
-       int osr;
-#endif
-
        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;
+       ber_int_sb_close( sb );
+       ber_int_sb_destroy( sb );
+       LBER_FREE( sb );
 }
-#endif
 
-#ifdef USE_SASL
-static ber_len_t
-packet_length( Sockbuf *sb, const char *buf )
+/* 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 )
 {
-   ber_len_t size;
+       Sockbuf_IO_Desc         *p;
+       int                     ret = 0;
+       char                    buf[4096];
 
-   assert( buf != NULL );
+       assert( sb != 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,
+                               (int)arg ) ? -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
+                        */
+                       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;
+               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<minsize; pw<<=1 ) {
-      if (pw > MAX_BUF_SIZE) {
-        /* this could mean that somebody is trying to crash us. */
-        return -1;
-      }
-   }
-   minsize = pw;
-
-   if (buf->buf_size<minsize) {
-      if ((buf->buf_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 (rlen<len) {
-        len-=rlen;
-        buf+=rlen;
-      } else {
-        sb->sb_buf_ready = (sb->sb_buf.buf_end = rlen - len) ? 1 : 0;
-        break;
-      }
+       return 0;
    }
    
-   if (ptr+size>end)
-     sb->sb_sec_ready = 0;
-   /* clean up the mess. */
-   if (ptr<end) {
-      /* copy back to beginning of buffer. */
-      SAFEMEMCPY( sb->sb_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;
-}
-
-static long
-sockbuf_sec_protect( Sockbuf *sb, char *buf, long len )
+int
+ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
 {
-   long ret;
-   long blen;
-   long total;
-   
-   assert( buf != NULL );
+       Sockbuf_IO_Desc         *p, **q;
 
    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) );
-   
-   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) */
+       if ( sb->sb_iod == NULL )
+               return -1;
+   
+       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;
-      }
-      sb->sb_sec_out.buf_end += ret;
-      len -= blen;
-      total += blen;
    }
-   assert( status_is_ok(sb) );
-   return total;
+               q = &p->sbiod_next;
 }
-#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 );
-
-   assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
-   assert( status_is_ok(sb) );
-
-   if (blen) {
-      ber_len_t rlen = (blen<len) ? blen : len;
-      memcpy( *buf, sb->sb_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;
+       ber_len_t               pw;
+       char                    *p;
    
-   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 ) );
+       assert( buf != NULL );
 
-#ifdef TEST_PARTIAL_READ
-   if ((rand() & 3)==1) { /* 1 out of 4 */
-      errno = EWOULDBLOCK;
+       for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
+               if (pw > MAX_BUFF_SIZE)
       return -1;
    }
 
-   if( len > 0 )
-          len = (rand() % len)+1;
-#endif   
-   
-   buf = (char *) buf_arg;
-
-   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);
-      }
+       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;
    }
-
-#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));
+       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;
+       ber_len_t               max;
 
-   assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
-
-   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;
-#endif
-      break;
+       assert( buf != NULL );
+       assert( sbb != NULL );
+       assert( sbb->buf_size > 0 );
+
+       max = sbb->buf_end - sbb->buf_ptr;
+       max = ( max < len) ? max : len;
+       if ( max ) {
+               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 (ret<to_go) /* not enough data, so pretend no data was sent. */
-     return -1;
-   return ret;
+       return max;
 }
-#endif
 
-ber_slen_t ber_pvt_sb_write( Sockbuf *sb, void *buf, ber_len_t len_arg )
+ber_slen_t
+ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
 {
+       ber_len_t               to_go;
    ber_slen_t ret;
-   ber_len_t len = len_arg;
 
-       assert( buf != 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_WRITE
-   if ((rand() & 3)==1) { /* 1 out of 4 */
-      errno = EWOULDBLOCK;
-      return -1;
-   }
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_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 );
+               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      
-   }
-#endif
 
+       if ( ret <= 0 )
    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 ) );
    
-   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;
+       if ( ret < to_go )
+               /* not enough data, so pretend no data was sent. */
+               return -1;
    return ret;
 }
 
-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;
-}
-
-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);
-       if( nb ) {
+       int flags = fcntl( sd, F_GETFL);
+       if( nb )
                flags |= O_NONBLOCK;
-       } else {
+       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;
@@ -660,201 +296,100 @@ 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_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;
-   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 
    
    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)) {
+       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;
 }
 
-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;
-
-   sb->sb_io = &sb_IO_None;
-   
-   sb->sb_trans_ready = 0;
-   sb->sb_trans_needs_read = 0;
-   sb->sb_trans_needs_write = 0;
-
-   return 0;
+       for (;;) {
+               ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
+#ifdef EINTR   
+               if ( ( ret < 0 ) && ( errno == EINTR ) )
+                       continue;
+#endif
+               break;
+}
+       return ret;
 }
 
 /*
@@ -862,16 +397,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,7 +422,8 @@ stream_read( Sockbuf *sb, void *buf, ber_len_t len )
  */
    {
    int rc;
-   rc = recv( ber_pvt_sb_get_desc(sb), buf, len, 0 );
+
+               rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 
 #ifdef HAVE_WINSOCK
    if ( rc < 0 )
@@ -905,26 +441,25 @@ stream_read( Sockbuf *sb, void *buf, ber_len_t len )
 /*
  * 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), 
+       return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
                    (len<MAX_WRITE)? len : MAX_WRITE );
 
 #elif defined( HAVE_PCNFS) \
@@ -941,11 +476,13 @@ stream_write( Sockbuf *sb, void *buf, ber_len_t len )
 
    {
    int rc;
-   rc = send( ber_pvt_sb_get_desc(sb), buf, len, 0 );
+       
+               rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 #ifdef HAVE_WINSOCK
    if ( rc < 0 )
    {
      int err;
+               
      err = WSAGetLastError();
      errno = err;
    }
@@ -954,36 +491,53 @@ stream_write( Sockbuf *sb, void *buf, ber_len_t len )
    }
 
 #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, 
+       return write( sbiod->sbiod_sb->sb_fd, buf,
                 (len<MAX_WRITE)? len : MAX_WRITE);
 #else
-   return write( ber_pvt_sb_get_desc(sb), buf, len );
+       return write( sbiod->sbiod_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=
+/* 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 =
 {
-       NULL,   /* sbi_setup */
-       NULL,   /* sbi_release */
-       stream_read,    /* sbi_read */
-       stream_write,   /* sbi_write */
-       stream_close,   /* sbi_close */
+       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 */
 };
 
 /*
@@ -997,53 +551,52 @@ struct dgram_data
 };
 
 static int 
-dgram_setup( Sockbuf *sb, void *arg )
+sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 {
-       assert( sb != NULL);
-       assert( SOCKBUF_VALID( sb ) );
+       struct dgram_data       *p;
+
+       assert( sbiod != NULL);
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
-   sb->sb_iodata = LBER_MALLOC( sizeof( struct dgram_data ) );
-   if (sb->sb_iodata==NULL)
+       p = LBER_MALLOC( sizeof( *p ) );
+       if ( p == NULL )
      return -1;
-   sb->sb_read_ahead = 1; /* important since udp is packet based. */
+       memset( p, 0, sizeof( *p ) );
+       sbiod->sbiod_pvt = (void *)p;
+       if ( arg != NULL )
+               sbiod->sbiod_sb->sb_fd = *((int *)arg);
    return 0;
 }
 
 static int 
-dgram_release( Sockbuf *sb )
+sb_dgram_release( Sockbuf_IO_Desc *sbiod )
 {
-       assert( sb != NULL);
-       assert( SOCKBUF_VALID( sb ) );
+       assert( sbiod != NULL);
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
-   LBER_FREE( sb->sb_iodata );
+       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_dgram_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;
+       struct dgram_data       *p;
    
-       assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
        assert( buf != NULL );
 
-   dd = (struct dgram_data *)(sb->sb_iodata);
+       p = (struct dgram_data *)sbiod->sbiod_pvt;
    
    addrlen = sizeof( struct sockaddr );
-   rc=recvfrom( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
+       rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->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;
@@ -1051,30 +604,30 @@ dgram_read( Sockbuf *sb, void *buf, ber_len_t len )
 }
 
 static ber_slen_t 
-dgram_write( Sockbuf *sb, void *buf, ber_len_t len )
+sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
 {
 #ifdef LDAP_CONNECTIONLESS
    ber_slen_t rc;
-   struct dgram_data *dd;
+       struct dgram_data       *p;
    
-       assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
        assert( buf != NULL );
 
-   dd = (struct dgram_data *)(sb->sb_iodata);
+       p = (struct dgram_data *)sbiod->sbiod_pvt;
    
-   rc=sendto( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
+       rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->dst,
             sizeof( struct sockaddr ) );
 
    if ( rc <= 0 )
-       return( -1 );
+               return -1;
    
    /* fake error if write was not atomic */
    if (rc < len) {
 # ifdef EMSGSIZE
       errno = EMSGSIZE;
 # endif
-      return( -1 );
+               return -1;
    }
    return rc;
 #else
@@ -1083,84 +636,325 @@ dgram_write( Sockbuf *sb, void *buf, ber_len_t len )
 }
 
 static int 
-dgram_close( Sockbuf *sb )
+sb_dgram_close( Sockbuf_IO_Desc *sbiod )
 {
-       assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
-       tcp_close( ber_pvt_sb_get_desc(sb) );
+       tcp_close( sbiod->sbiod_sb->sb_fd );
        return 0;
 }
 
-Sockbuf_IO ber_pvt_sb_io_udp=
+static int
+sb_dgram_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 */
+       struct dgram_data       *p;
+
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       p = (struct dgram_data *)sbiod->sbiod_pvt;
+
+       if ( opt == LBER_SB_OPT_UDP_SET_DST ) {
+               memcpy( &p->dst, arg, sizeof( struct sockaddr ) );
+               return 1;
+       }
+       else if ( opt == LBER_SB_OPT_UDP_GET_SRC ) {
+               *(( struct sockaddr **)arg) = &p->src;
+               return 1;
+       }
+       /* This is an end IO descriptor */
+       return 0;
+}
+
+Sockbuf_IO ber_sockbuf_io_udp =
+{
+       sb_dgram_setup,         /* sbi_setup */
+       sb_dgram_release,       /* sbi_release */
+       sb_dgram_ctrl,          /* sbi_ctrl */
+       sb_dgram_read,          /* sbi_read */
+       sb_dgram_write,         /* sbi_write */
+       sb_dgram_close          /* sbi_close */
 };
 
-int ber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
+/*
+ * Support for readahead (UDP needs it)
+ */
+
+static int
+sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 {
-   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 ) );
+       Sockbuf_Buf             *p;
+
+       assert( sbiod != NULL );
+
+       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, DEFAULT_READAHEAD );
+       else
+               ber_pvt_sb_grow_buffer( p, *((int *)arg) );
+       sbiod->sbiod_pvt = p;
    return 0;
 }
 
-void *ber_pvt_sb_udp_get_src( Sockbuf *sb )
+static int
+sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
 {
-   struct dgram_data *dd;
+       Sockbuf_Buf             *p;
 
-       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);
+       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
+sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
+{
+       Sockbuf_Buf             *p;
+       ber_slen_t              bufptr = 0, ret, max;
+
+       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, buf + bufptr, len );
+       return bufptr;
+}
+
+static ber_slen_t
+sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
+{
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_next != NULL );
+
+       return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
+}
+
+static int
+sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
+{
+       assert( sbiod != NULL );
+
+       /* Just erase the buffer */
+       ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
+       return 0;
+}
+
+static int
+sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+       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 */
+};
+
 /*
- * debug routines.
- * 
- * BUGS:
- * These routines should really call abort, but at the moment that would
- * break the servers.
+ * Support for simple file IO
  */
 
 static ber_slen_t
-have_no_read( Sockbuf *sb, void *buf, ber_len_t len )
+sb_fd_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 ) );
 
-   ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
-                  "warning: reading from uninitialized sockbuf\n");
-   errno =  EBADF;
-   return -1;
+       return read( sbiod->sbiod_sb->sb_fd, buf, len );
 }
 
 static ber_slen_t
-have_no_write( Sockbuf *sb, void *buf, ber_len_t len )
+sb_fd_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 ) );
 
-   ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
-                  "warning: writing to uninitialized sockbuf\n");
-   errno =  EBADF;
-   return -1;
+       return write( sbiod->sbiod_sb->sb_fd, buf, len );
 }
 
 static int 
-have_no_close( Sockbuf *sb )
+sb_fd_close( Sockbuf_IO_Desc *sbiod )
 {   
-       assert( sb != NULL );
-       assert( SOCKBUF_VALID( sb ) );
+       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 */
+};
+
+/*
+ * Debugging layer
+ */
 
-   assert( 0 );
+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 ( 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 );
+       }
+       return ret;
+}
+
+static ber_slen_t
+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 ( 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 ) );
+       }
+       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 );
+       }
+       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 */
+};
+
index b2b24b2f58bbad038b03e4afc6d7ccd2aa124c08..3ce621f7aa3685d11dc1149512b56d40897cec89 100644 (file)
@@ -180,7 +180,7 @@ do_abandon(
                                if ( lr != NULL ) {
                                        sb = lr->lr_conn->lconn_sb;
                                } else {
-                                       sb = &ld->ld_sb;
+                                       sb = ld->ld_sb;
                                }
 
                                if ( ber_flush( sb, ber, 1 ) != 0 ) {
index 0b03b2ad8d72c47906ee3fa82410b0f7ae171631..9a4eac20ff5e32927480ed186b98239c0bb32f30 100644 (file)
@@ -94,10 +94,20 @@ cldap_open( LDAP_CONST char *host, int port )
     ld->ld_cldapnaddr = 0;
     ld->ld_cldapaddrs = NULL;
 
-    if (ber_pvt_sb_set_io( &(ld->ld_sb), &ber_pvt_sb_io_udp, NULL )<0) {
+    if ( ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_udp,
+           LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ) < 0 ) {
        ldap_ld_free(ld, 1, NULL, NULL );
+       tcp_close( s );
        return NULL;
     }
+    if ( ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_readahead,
+           LBER_SBIOD_LEVEL_PROVIDER, NULL ) < 0 ) {
+       ldap_ld_free( ld, 1, NULL, NULL );
+       return NULL;
+    }
+#ifdef LDAP_DEBUG
+    ber_sockbuf_add_io( ld->ld_sb, &ber_sockbuf_io_debug, INT_MAX, NULL );
+#endif
        
     ld->ld_version = LDAP_VERSION2;
 
@@ -168,7 +178,8 @@ cldap_open( LDAP_CONST char *host, int port )
        DO_RETURN( NULL );
     }
 
-    ber_pvt_sb_udp_set_dst( &ld->ld_sb, ld->ld_cldapaddrs[0] );
+    ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST,
+       ld->ld_cldapaddrs[0] );
 
     cldap_setretryinfo( ld, 0, 0 );
 
@@ -229,8 +240,8 @@ cldap_search_s( LDAP *ld,
                --ld->ld_msgid; /* use same id as before */
        }
            
-       ber_pvt_sb_udp_set_dst( &(ld->ld_sb), 
-                       ld->ld_cldapaddrs[ cri.cri_useaddr ] );
+       ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST,
+           (void *)ld->ld_cldapaddrs[cri.cri_useaddr] );
 
        Debug( LDAP_DEBUG_TRACE, "cldap_search_s try %d (to %s)\n",
            cri.cri_try, inet_ntoa( ((struct sockaddr_in *)
@@ -287,7 +298,6 @@ static int
 cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
        struct cldap_retinfo *crip, const char *base )
 {
-    Sockbuf            *sb = &ld->ld_sb;
     BerElement         ber;
     char               *logdn;
     int                        ret, fromaddr, i;
@@ -365,7 +375,7 @@ cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
             * got a result: determine which server it came from
             * decode into ldap message chain
             */
-           src = (struct sockaddr_in *) ber_pvt_sb_udp_get_src( sb );
+           ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_GET_SRC, (void *)&src );
                
            for ( fromaddr = 0; fromaddr < ld->ld_cldapnaddr; ++fromaddr ) {
                    if ( memcmp( &((struct sockaddr_in *)
@@ -401,7 +411,8 @@ cldap_result( LDAP *ld, int msgid, LDAPMessage **res,
            if ( i == fromaddr ) {
                continue;
            }
-           ber_pvt_sb_udp_set_dst( sb, ld->ld_cldapaddrs[i] );
+           ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_UDP_SET_DST,
+               (void *)ld->ld_cldapaddrs[i] );
 
            Debug( LDAP_DEBUG_TRACE, "cldap_result abandoning id %d (to %s)\n",
                msgid, inet_ntoa( ((struct sockaddr_in *)
index 54982ae1a079f41f4badf6231cd022e495d6c2f0..3f6f20cdd1280063e89570666b650cd1a39e581f 100644 (file)
@@ -273,7 +273,7 @@ ldap_get_kerberosv4_credentials(
                return( NULL );
        }
 
-       if( ! ber_pvt_sb_in_use( &ld->ld_sb ) ) {
+       if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
                /* not connected yet */
                int rc = ldap_open_defconn( ld );
 
index df499916be17a62f8f4b56bcb7eb8b90e2e1546f..216a9b44e1406170761597d646da9f508c0d69e1 100644 (file)
 #include "../liblber/lber-int.h"
 
 #define ldap_debug     (ldap_int_global_options.ldo_debug)
+
+#include "ldap_log.h"
+
 #undef Debug
 #define Debug( level, fmt, arg1, arg2, arg3 ) \
        ldap_log_printf( NULL, (level), (fmt), (arg1), (arg2), (arg3) )
 
-#include "ldap_log.h"
-
 #include "ldap.h"
 
 #include "ldap_pvt.h"
@@ -230,7 +231,7 @@ typedef struct ldapreqinfo {
  */
 
 struct ldap {
-       Sockbuf         ld_sb;          /* socket descriptor & buffer */
+       Sockbuf         *ld_sb;         /* socket descriptor & buffer */
 
        struct ldapoptions ld_options;
 
@@ -391,8 +392,6 @@ LIBLDAP_F (int) ldap_int_tblsize;
 LIBLDAP_F (int) ldap_int_timeval_dup( struct timeval **dest, const struct timeval *tm );
 LIBLDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host, unsigned long address, int port, int async );
 
-LIBLDAP_F (void) ldap_close_connection( Sockbuf *sb );
-
 #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
 LIBLDAP_F (char *) ldap_host_connected_to( Sockbuf *sb );
 #endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */
index 955733482f3b09ed237bc295214e8d70be253e48..afccb261d7ccfc1d95bba7c8946415c38fe89812 100644 (file)
@@ -161,7 +161,13 @@ ldap_create( LDAP **ldp )
 #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
 
-       ber_pvt_sb_init( &(ld->ld_sb) );
+       ld->ld_sb = ber_sockbuf_alloc( );
+       if ( ld->ld_sb == NULL ) {
+               ldap_free_urllist( ld->ld_options.ldo_defludp );
+               LDAP_FREE( (char*) ld );
+               WSACleanup( );
+               return LDAP_NO_MEMORY;
+       }
 
        *ldp = ld;
        return LDAP_SUCCESS;
@@ -283,24 +289,41 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv,
 
        switch ( srv->lud_protocol ) {
                case LDAP_PROTO_TCP:
+                       rc = ldap_connect_to_host( ld, sb, srv->lud_host,
+                               addr, port, async );
+                       if ( rc == -1 )
+                               return rc;
+                       ber_sockbuf_add_io( sb, &ber_sockbuf_io_tcp,
+                               LBER_SBIOD_LEVEL_PROVIDER, NULL );
+                       break;
                case LDAP_PROTO_UDP:
-                       rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async );
+                       rc = ldap_connect_to_host( ld, sb, srv->lud_host,
+                               addr, port, async );
+                       if ( rc == -1 )
+                               return rc;
+                       ber_sockbuf_add_io( sb, &ber_sockbuf_io_udp,
+                               LBER_SBIOD_LEVEL_PROVIDER, NULL );
                        break;
 #ifdef LDAP_PF_LOCAL
                case LDAP_PROTO_LOCAL:
-                       rc = ldap_connect_to_path( ld, sb, srv->lud_host, async );
+                       rc = ldap_connect_to_path( ld, sb, srv->lud_host,
+                               async );
+                       if ( rc == -1 )
+                               return rc;
+                       ber_sockbuf_add_io( sb, &ber_sockbuf_io_fd,
+                               LBER_SBIOD_LEVEL_PROVIDER, NULL );
                        break;
 #endif /* LDAP_PF_LOCAL */
                default:
-                       rc = -1;
+                       return -1;
                        break;
        }
 
-       if ( rc == -1 ) {
-               return( rc );
-       }
-   
-       ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
+       ber_sockbuf_add_io( sb, &ber_sockbuf_io_readahead,
+               LBER_SBIOD_LEVEL_PROVIDER, NULL );
+#ifdef LDAP_DEBUG
+       ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, INT_MAX, NULL );
+#endif
 
 #ifdef HAVE_TLS
        if (ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
index 47e77e624732b8a8aaec1a1570e38c4aa7c5a834..56b39c20f487399ec0094e66ef2b4f3d8027777a 100644 (file)
@@ -151,12 +151,12 @@ ldap_get_option(
                } break;
 
        case LDAP_OPT_DESC:
-               if(ld == NULL) {
+               if( ld == NULL || ld->ld_sb == NULL ) {
                        /* bad param */
                        break;
                } 
 
-               * (ber_socket_t *) outvalue = ber_pvt_sb_get_desc( &(ld->ld_sb) );
+               ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, outvalue );
                return LDAP_OPT_SUCCESS;
 
        case LDAP_OPT_TIMEOUT:
index 1033d62c526632c69f4372e62a8ca8ce38f60f20..f150eb4ff6c0043a6239b4aeb8eb102dc0bbc9f3 100644 (file)
@@ -337,7 +337,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, const char *host,
                rc = ldap_pvt_connect(ld, s, &sin, async);
    
                if ( (rc == 0) || (rc == -2) ) {
-                       ber_pvt_sb_set_desc( sb, s );
+                       ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
                        break;
                }
 
@@ -350,13 +350,6 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, const char *host,
        return rc;
 }
 
-void
-ldap_close_connection( Sockbuf *sb )
-{
-       ber_pvt_sb_close( sb );
-}
-
-
 #if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND ) || defined( HAVE_TLS ) || defined( HAVE_CYRUS_SASL )
 char *
 ldap_host_connected_to( Sockbuf *sb )
@@ -369,12 +362,14 @@ ldap_host_connected_to( Sockbuf *sb )
        struct hostent          he_buf;
         int                    local_h_errno;
        char                    *ha_buf=NULL;
+       ber_socket_t            sd;
 #define DO_RETURN(x) if (ha_buf) LDAP_FREE(ha_buf); return (x);
    
        (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
        len = sizeof( sin );
 
-       if ( getpeername( ber_pvt_sb_get_desc(sb), (struct sockaddr *)&sin, &len ) == -1 ) {
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       if ( getpeername( sd, (struct sockaddr *)&sin, &len ) == -1 ) {
                return( NULL );
        }
 
@@ -414,11 +409,13 @@ void
 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
 {
        struct selectinfo       *sip;
+       ber_socket_t            sd;
 
        sip = (struct selectinfo *)ld->ld_selectinfo;
        
-       if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_writefds )) {
-               FD_SET( (u_int) sb->sb_sd, &sip->si_writefds );
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       if ( !FD_ISSET( sd, &sip->si_writefds )) {
+               FD_SET( sd, &sip->si_writefds );
        }
 }
 
@@ -427,11 +424,13 @@ void
 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
 {
        struct selectinfo       *sip;
+       ber_socket_t            sd;
 
        sip = (struct selectinfo *)ld->ld_selectinfo;
 
-       if ( !FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_readfds )) {
-               FD_SET( (u_int) sb->sb_sd, &sip->si_readfds );
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       if ( !FD_ISSET( sd, &sip->si_readfds )) {
+               FD_SET( sd, &sip->si_readfds );
        }
 }
 
@@ -440,11 +439,13 @@ void
 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
 {
        struct selectinfo       *sip;
+       ber_socket_t            sd;
 
        sip = (struct selectinfo *)ld->ld_selectinfo;
 
-       FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_writefds );
-       FD_CLR( (u_int) ber_pvt_sb_get_desc(sb), &sip->si_readfds );
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       FD_CLR( sd, &sip->si_writefds );
+       FD_CLR( sd, &sip->si_readfds );
 }
 
 
@@ -452,10 +453,12 @@ int
 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
 {
        struct selectinfo       *sip;
+       ber_socket_t            sd;
 
        sip = (struct selectinfo *)ld->ld_selectinfo;
 
-       return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_writefds ));
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       return( FD_ISSET( sd, &sip->si_use_writefds ));
 }
 
 
@@ -463,10 +466,12 @@ int
 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
 {
        struct selectinfo       *sip;
+       ber_socket_t            sd;
 
        sip = (struct selectinfo *)ld->ld_selectinfo;
 
-       return( FD_ISSET( ber_pvt_sb_get_desc(sb), &sip->si_use_readfds ));
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
+       return( FD_ISSET( sd, &sip->si_use_readfds ));
 }
 
 
index baae3da352fb89e668c9479b424f8bd0fdee782a..67da7e0328a09a834d3216cbacb63cffa8594c05 100644 (file)
@@ -208,7 +208,7 @@ ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async)
        rc = ldap_pvt_connect(ld, s, &server, async);
 
        if (rc == 0) {
-               ber_pvt_sb_set_desc( sb, s );
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, (void *)&s );
        } else {
                ldap_pvt_close_socket(ld, s);
        }
index 87d6c84bfac115832d66c01372a85cbf99bb7e60..bb6c9df78dc71ceefec03e8f60cf6d531dfd9344 100644 (file)
@@ -100,7 +100,7 @@ ldap_send_initial_request(
 
        Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
 
-       if ( ! ber_pvt_sb_in_use(&ld->ld_sb ) ) {
+       if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
                /* not connected yet */
                int rc = ldap_open_defconn( ld );
 
@@ -293,7 +293,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb,
                return( NULL );
        }
 
-       lc->lconn_sb = ( use_ldsb ) ? &ld->ld_sb : sb;
+       lc->lconn_sb = ( use_ldsb ) ? ld->ld_sb : sb;
 
        if ( connect ) {
                for ( srv = srvlist; srv != NULL; srv = srv->lud_next ) {
@@ -433,10 +433,6 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
                        }
                }
 
-               /* force closure */
-               ldap_close_connection( lc->lconn_sb );
-               ber_pvt_sb_destroy( lc->lconn_sb );
-
                if( lc->lconn_ber != NULL ) {
                        ber_free( lc->lconn_ber, 1 );
                }
@@ -458,7 +454,7 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
                if ( lc->lconn_krbinstance != NULL ) {
                        LDAP_FREE( lc->lconn_krbinstance );
                }
-               if ( lc->lconn_sb != &ld->ld_sb ) {
+               if ( lc->lconn_sb != ld->ld_sb ) {
                        ber_sockbuf_free( lc->lconn_sb );
                }
                if( lc->lconn_rebind_queue != NULL) {
@@ -493,7 +489,7 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
                            ( lc->lconn_server->lud_host == NULL ) ? "(null)"
                            : lc->lconn_server->lud_host,
                            lc->lconn_server->lud_port, ( lc->lconn_sb ==
-                           &ld->ld_sb ) ? "  (default)" : "" );
+                           ld->ld_sb ) ? "  (default)" : "" );
                }
                fprintf( stderr, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
                    ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
index 3ceb1fa70d46335347dc4326640a62eecef99ec7..475effc9d5c062caa9b4e015e625a0eb752f01c3 100644 (file)
@@ -218,7 +218,8 @@ wait4msg(
                }
 #endif /* LDAP_DEBUG */
                for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
-                       if ( ber_pvt_sb_data_ready(lc->lconn_sb) ) {
+                       if ( ber_sockbuf_ctrl( lc->lconn_sb,
+                                       LBER_SB_OPT_DATA_READY, NULL ) ) {
                                rc = try_read1msg( ld, msgid, all, lc->lconn_sb,
                                    lc, result );
                                break;
@@ -888,14 +889,16 @@ cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
        int     rc;
        ber_tag_t       tag;
        ber_len_t       len;
+       ber_socket_t    sd;
 
-       if ( ! ber_pvt_sb_data_ready(&ld->ld_sb) ) {
+       ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
+       if ( sd != AC_SOCKET_INVALID ) {
                /* restored from ldap_select1() in result.c version 1.24 */
                fd_set  readfds;
                if ( ldap_int_tblsize == 0 )
                        ldap_int_ip_init();
                FD_ZERO( &readfds );
-               FD_SET( ber_pvt_sb_get_desc(&ld->ld_sb), &readfds );
+               FD_SET( sd, &readfds );
                rc = select( ldap_int_tblsize, &readfds, 0, 0, timeout );
 
                if ( rc == -1 || rc == 0 ) {
@@ -906,7 +909,7 @@ cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
        }
 
        /* get the next message */
-       if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
+       if ( (tag = ber_get_next( ld->ld_sb, &len, ber ))
            != LDAP_TAG_MESSAGE ) {
                ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
                    LDAP_LOCAL_ERROR);
index 00656001d9cbec9f2bb8331e2984d07f3bb89eb0..e162b04a5389db52da14aee698485d26b9c82b47 100644 (file)
@@ -32,6 +32,7 @@
 #include <ac/socket.h>
 #include <ac/string.h>
 #include <ac/time.h>
+#include <ac/errno.h>
 
 #include "ldap-int.h"
 
@@ -349,22 +350,8 @@ ldap_parse_sasl_bind_result(
 * Various Cyrus SASL related stuff.
 */
 
-static int sasl_setup( Sockbuf *sb, void *arg );
-static int sasl_remove( Sockbuf *sb );
-static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
-static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
-static int sasl_close( Sockbuf *sb );
-
-static Sockbuf_IO sasl_io=
-{
-sasl_setup,
-sasl_remove,
-sasl_read,
-sasl_write,
-sasl_close
-}; 
-
-#define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
+#define MAX_BUFF_SIZE  65536
+#define MIN_BUFF_SIZE  4096
 
 static char *
 array2str( char **a )
@@ -424,79 +411,259 @@ int ldap_pvt_sasl_init( void )
        return -1;
 }
 
-int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
+/*
+ * SASL encryption support for LBER Sockbufs
+ */
+
+struct sb_sasl_data {
+       sasl_conn_t             *sasl_context;
+       Sockbuf_Buf             sec_buf_in;
+       Sockbuf_Buf             buf_in;
+       Sockbuf_Buf             buf_out;
+};
+
+static int
+sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 {
-       /* don't install the stuff unless security has been negotiated */
+       struct sb_sasl_data     *p;
 
-       if ( !HAS_SASL( sb ) ) {
-               ber_pvt_sb_clear_io( sb );
-               ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
+       assert( sbiod != NULL );
+
+       p = LBER_MALLOC( sizeof( *p ) );
+       if ( p == NULL )
+               return -1;
+       p->sasl_context = (sasl_conn_t *)arg;
+       ber_pvt_sb_buf_init( &p->sec_buf_in );
+       ber_pvt_sb_buf_init( &p->buf_in );
+       ber_pvt_sb_buf_init( &p->buf_out );
+       if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, MIN_BUFF_SIZE ) < 0 ) {
+               errno = ENOMEM;
+               return -1;
        }
 
+       sbiod->sbiod_pvt = p;
+
        return 0;
 }
 
-static int sasl_setup( Sockbuf *sb, void *arg )
+static int
+sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
 {
-       sb->sb_iodata = arg;
+       struct sb_sasl_data     *p;
+
+       assert( sbiod != NULL );
+       
+       p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
+       ber_pvt_sb_buf_destroy( &p->sec_buf_in );
+       ber_pvt_sb_buf_destroy( &p->buf_in );
+       ber_pvt_sb_buf_destroy( &p->buf_out );
+       LBER_FREE( p );
+       sbiod->sbiod_pvt = NULL;
        return 0;
 }
 
-static int sasl_remove( Sockbuf *sb )
+static ber_len_t
+sb_sasl_pkt_length( const char *buf, int debuglevel )
 {
-       return 0;
+       ber_len_t               size;
+       long                    tmp;
+
+       assert( buf != NULL );
+
+       tmp = *((long *)buf);
+       size = ntohl( tmp );
+   
+       if ( size > MAX_BUFF_SIZE ) {
+               /* somebody is trying to mess me up. */
+               ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
+                       "sb_sasl_pkt_length: received illegal packet length "
+                       "of %lu bytes\n", (unsigned long)size );      
+               size = 16; /* this should lead to an error. */
+}
+
+       return size + 4; /* include the size !!! */
 }
 
-static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
+/* Drop a processed packet from the input buffer */
+static void
+sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
 {
-       char *recv_tok;
-       unsigned recv_tok_len;
-       sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
+       ber_slen_t                      len;
+
+       len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
+       if ( len > 0 )
+               memmove( sec_buf_in->buf_base, sec_buf_in->buf_base +
+                       sec_buf_in->buf_end, len );
+   
+       if ( len >= 4 ) {
+               sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base,
+                       debuglevel);
+       }
+       else {
+               sec_buf_in->buf_end = 0;
+       }
+       sec_buf_in->buf_ptr = len;
+}
 
-       if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
-               return -1;
+static ber_slen_t
+sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+       struct sb_sasl_data     *p;
+       ber_slen_t              ret, bufptr;
+   
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
+
+       /* Are there anything left in the buffer? */
+       ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
+       bufptr = ret;
+       len -= ret;
+
+       if ( len == 0 )
+               return bufptr;
+
+       ber_pvt_sb_buf_destroy( &p->buf_in );
+
+       /* Read the length of the packet */
+       while ( p->sec_buf_in.buf_ptr < 4 ) {
+               ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base,
+                       4 - p->sec_buf_in.buf_ptr );
+#ifdef EINTR
+               if ( ( ret < 0 ) && ( errno == EINTR ) )
+                       continue;
+#endif
+               if ( ret <= 0 )
+                       return ret;
+
+               p->sec_buf_in.buf_ptr += ret;
        }
 
-       if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
+       /* The new packet always starts at p->sec_buf_in.buf_base */
+       ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base,
+               sbiod->sbiod_sb->sb_debug );
+
+       /* Grow the packet buffer if neccessary */
+       if ( ( p->sec_buf_in.buf_size < ret ) && 
+                       ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) {
+               errno = ENOMEM;
                return -1;
        }
-
-       if ( recv_tok_len > buflen ) {
-               LDAP_FREE( recv_tok );
+       p->sec_buf_in.buf_end = ret;
+
+       /* Did we read the whole encrypted packet? */
+       while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
+               /* No, we have got only a part of it */
+               ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
+
+               ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
+                       p->sec_buf_in.buf_ptr, ret );
+#ifdef EINTR
+               if ( ( ret < 0 ) && ( errno == EINTR ) )
+                       continue;
+#endif
+               if ( ret <= 0 )
+                       return ret;
+
+               p->sec_buf_in.buf_ptr += ret;
+       }
+
+       /* Decode the packet */
+       ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
+               p->sec_buf_in.buf_end, &p->buf_in.buf_base,
+               (unsigned *)&p->buf_in.buf_end );
+       if ( ret != SASL_OK ) {
+               ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
+                       "sb_sasl_read: failed to decode packet: %s\n",
+                       sasl_errstring( ret, NULL, NULL ) );
+               sb_sasl_drop_packet( &p->sec_buf_in,
+                       sbiod->sbiod_sb->sb_debug );
+               errno = EIO;
                return -1;
        }
+       
+       /* Drop the packet from the input buffer */
+       sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
 
-       memcpy( buf, recv_tok, recv_tok_len );  
+       p->buf_in.buf_size = p->buf_in.buf_end;
 
-       LDAP_FREE( recv_tok );
+       bufptr += ber_pvt_sb_copy_out( &p->buf_in, buf + bufptr, len );
 
-       return recv_tok_len;
+       return bufptr;
 }
 
-static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
+static ber_slen_t
+sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 {
-       char *wrapped_tok;
-       unsigned wrapped_tok_len;
-       sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
+       struct sb_sasl_data     *p;
+       int                     ret;
 
-       if ( sasl_encode( conn, (const char *)buf, len,
-               &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
-               return -1;
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
+
+       /* Are there anything left in the buffer? */
+       if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
+               ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
+               if ( ret <= 0 )
+                       return ret;
        }
 
-       if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
-               LDAP_FREE( wrapped_tok );
+       /* now encode the next packet. */
+       ber_pvt_sb_buf_destroy( &p->buf_out );
+       ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base,
+               (unsigned *)&p->buf_out.buf_size );
+       if ( ret != SASL_OK ) {
+               ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
+                       "sb_sasl_write: failed to encode packet: %s\n",
+                       sasl_errstring( ret, NULL, NULL ) );
                return -1;
        }
+       p->buf_out.buf_end = p->buf_out.buf_size;
 
-       LDAP_FREE( wrapped_tok );
-
+       ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
+       if ( ret <= 0 )
+               return ret;
        return len;
 }
 
-static int sasl_close( Sockbuf *sb )
+static int
+sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
 {
-       return (ber_pvt_sb_io_tcp.sbi_close)( sb );
+       struct sb_sasl_data     *p;
+
+       p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
+
+       if ( opt == LBER_SB_OPT_DATA_READY ) {
+               if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
+                       return 1;
+       }
+       
+       return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
+}
+
+Sockbuf_IO ldap_pvt_sockbuf_io_sasl =
+{
+       sb_sasl_setup,          /* sbi_setup */
+       sb_sasl_remove,         /* sbi_remove */
+       sb_sasl_ctrl,           /* sbi_ctrl */
+       sb_sasl_read,           /* sbi_read */
+       sb_sasl_write,          /* sbi_write */
+       NULL                    /* sbi_close */
+};
+
+int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
+{
+       /* don't install the stuff unless security has been negotiated */
+
+       if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
+                       &ldap_pvt_sockbuf_io_sasl ) )
+               ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
+                       LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
+
+       return LDAP_SUCCESS;
 }
 
 static int
@@ -598,11 +765,16 @@ ldap_pvt_sasl_bind(
        LDAPControl             **cctrls )
 {
        const char *mech;
-       int     saslrc, rc, ssf = 0;
+       int                     saslrc, rc;
+       sasl_ssf_t              *ssf = NULL;
        unsigned credlen;
        struct berval ccred, *scred;
        char *host;
        sasl_interact_t *client_interact = NULL;
+       struct sockaddr_in      sin;
+       socklen_t               len;
+       sasl_security_properties_t      secprops;
+       ber_socket_t            sd;
 
        Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
 
@@ -612,15 +784,18 @@ ldap_pvt_sasl_bind(
                return ld->ld_errno;
        }
 
-       if( ! ber_pvt_sb_in_use( &ld->ld_sb ) ) {
+       ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
+
+       if ( sd == AC_SOCKET_INVALID ) {
                /* not connected yet */
                int rc = ldap_open_defconn( ld );
   
                if( rc < 0 ) return ld->ld_errno;
+               ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
        }   
 
        /* XXX this doesn't work with PF_LOCAL hosts */
-       host = ldap_host_connected_to( &ld->ld_sb );
+       host = ldap_host_connected_to( ld->ld_sb );
 
        if ( host == NULL ) {
                ld->ld_errno = LDAP_UNAVAILABLE;
@@ -631,16 +806,42 @@ ldap_pvt_sasl_bind(
                sasl_dispose( &ld->ld_sasl_context );
        }
 
-       saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
+       saslrc = sasl_client_new( "ldap", host, callbacks, SASL_SECURITY_LAYER,
+               &ld->ld_sasl_context );
 
        LDAP_FREE( host );
 
        if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
-               ld->ld_errno = sasl_err2ldap( rc );
+               ld->ld_errno = sasl_err2ldap( saslrc );
                sasl_dispose( &ld->ld_sasl_context );
                return ld->ld_errno;
        }
 
+       len = sizeof( sin );
+       if ( getpeername( sd, (struct sockaddr *)&sin, &len ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "SASL: can't query remote IP.\n",
+                       0, 0, 0 );
+               ld->ld_errno = LDAP_OPERATIONS_ERROR;
+               return ld->ld_errno;
+       }
+       sasl_setprop( ld->ld_sasl_context, SASL_IP_REMOTE, &sin );
+
+       len = sizeof( sin );
+       if ( getsockname( sd, (struct sockaddr *)&sin, &len ) == -1 ) {
+               Debug( LDAP_DEBUG_ANY, "SASL: can't query local IP.\n",
+                       0, 0, 0 );
+               ld->ld_errno = LDAP_OPERATIONS_ERROR;
+               return ld->ld_errno;
+       }
+       sasl_setprop( ld->ld_sasl_context, SASL_IP_LOCAL, &sin );
+
+       memset( &secprops, 0, sizeof( secprops ) );
+       secprops.min_ssf = ld->ld_options.ldo_sasl_minssf;
+       secprops.max_ssf = ld->ld_options.ldo_sasl_maxssf;
+       secprops.security_flags = SASL_SECURITY_LAYER;
+       secprops.maxbufsize = 65536;
+       sasl_setprop( ld->ld_sasl_context, SASL_SEC_PROPS, &secprops );
+
        ccred.bv_val = NULL;
        ccred.bv_len = 0;
 
@@ -702,8 +903,8 @@ ldap_pvt_sasl_bind(
        assert ( rc == LDAP_SUCCESS );
 
        if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
-               == SASL_OK && ssf ) {
-               ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
+               == SASL_OK && ssf && *ssf ) {
+               ldap_pvt_sasl_install( ld->ld_sb, ld->ld_sasl_context );
        }
 
        return rc;
index f32fe6954bd3308f407e5a1befcc4cb54b7755af..cdcadc9fb2a801dae3c03cbee7cfe641fb0f3970 100644 (file)
@@ -235,6 +235,9 @@ bind_prompt( LDAP *ld, LDAP_CONST char *url, int request, ber_int_t msgid)
        char *dnp;
        int     authmethod;
 
+       printf("rebind for request=%d msgid=%ld url=%s\n",
+               request, (long) msgid, url );
+
 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
                getline( dn, sizeof(dn), stdin,
                    "re-bind method (0->simple, 1->krbv41, 2->krbv42, 3->krbv41&2)? " );
@@ -321,12 +324,12 @@ main( int argc, char **argv )
 
                case 't':       /* copy ber's to given file */
                        copyfname = strdup( optarg );
-                       copyoptions = LBER_TO_FILE;
+/*                     copyoptions = LBER_TO_FILE; */
                        break;
 
                case 'T':       /* only output ber's to given file */
                        copyfname = strdup( optarg );
-                       copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY);
+/*                     copyoptions = (LBER_TO_FILE | LBER_TO_FILE_ONLY); */
                        break;
 
                default:
@@ -362,12 +365,12 @@ main( int argc, char **argv )
        }
 
        if ( copyfname != NULL ) {
-               if ( (ld->ld_sb.sb_fd = open( copyfname, O_WRONLY | O_CREAT,
+               if ( ( ld->ld_sb->sb_fd = open( copyfname, O_WRONLY | O_CREAT,
                    0600 ))  == -1 ) {
                        perror( copyfname );
                        exit ( EXIT_FAILURE );
                }
-               ld->ld_sb.sb_options = copyoptions;
+               ld->ld_sb->sb_options = copyoptions;
        }
 
        bound = 0;
index 32a773cfca55c5e5e33dc2c87e001eff0df6957c..ff72666090ee294e78c0b76b54dcde2388197994 100644 (file)
@@ -41,24 +41,11 @@ static char *tls_opt_cacertdir = NULL;
 static int  tls_opt_require_cert = 0;
 static char *tls_opt_ciphersuite = NULL;
 
-#define HAS_TLS( sb ) ((sb)->sb_io==&tls_io)
+#define HAS_TLS( sb )  ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
+                               (void *)&ldap_pvt_sockbuf_io_tls )
 
-static int tls_setup( Sockbuf *sb, void *arg );
-static int tls_remove( Sockbuf *sb );
-static ber_slen_t tls_read( Sockbuf *sb, void *buf, ber_len_t len );
-static ber_slen_t tls_write( Sockbuf *sb, void *buf, ber_len_t len );
-static int tls_close( Sockbuf *sb );
 static void tls_report_error( void );
 
-static Sockbuf_IO tls_io=
-{
-   tls_setup,
-   tls_remove,
-   tls_read,
-   tls_write,
-   tls_close
-};
-
 static void tls_info_cb( SSL *ssl, int where, int ret );
 static int tls_verify_cb( int ok, X509_STORE_CTX *ctx );
 static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length );
@@ -243,9 +230,8 @@ get_ca_list( char * bundle, char * dir )
 }
 
 static SSL *
-alloc_handle( Sockbuf *sb, void *ctx_arg )
+alloc_handle( void *ctx_arg )
 {
-       int     err;
        SSL_CTX *ctx;
        SSL     *ssl;
 
@@ -266,8 +252,6 @@ alloc_handle( Sockbuf *sb, void *ctx_arg )
        if ( tls_opt_trace ) {
                SSL_set_info_callback( ssl, tls_info_cb );
        }
-       sb->sb_iodata = ssl;
-       SSL_set_fd( ssl, ber_pvt_sb_get_desc( sb ) );
        return ssl;
 }
 
@@ -293,6 +277,252 @@ update_flags( Sockbuf *sb, SSL * ssl, int rc )
        return 0;
 }
 
+/*
+ * TLS support for LBER Sockbufs
+ */
+
+struct tls_data {
+       SSL                     *ssl;
+       Sockbuf_IO_Desc         *sbiod;
+};
+
+extern BIO_METHOD ldap_pvt_sb_bio_method;
+
+static int
+sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg )
+{
+       struct tls_data         *p;
+       BIO                     *bio;
+
+       assert( sbiod != NULL );
+
+       p = LBER_MALLOC( sizeof( *p ) );
+       if ( p == NULL )
+               return -1;
+       
+       p->ssl = (SSL *)arg;
+       p->sbiod = sbiod;
+       bio = BIO_new( &ldap_pvt_sb_bio_method );
+       bio->ptr = (void *)p;
+       SSL_set_bio( p->ssl, bio, bio );
+       sbiod->sbiod_pvt = p;
+       return 0;
+}
+
+static int
+sb_tls_remove( Sockbuf_IO_Desc *sbiod )
+{
+       struct tls_data         *p;
+       
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+       SSL_free( p->ssl );
+       LBER_FREE( sbiod->sbiod_pvt );
+       sbiod->sbiod_pvt = NULL;
+       return 0;
+}
+
+static int
+sb_tls_close( Sockbuf_IO_Desc *sbiod )
+{
+       struct tls_data         *p;
+       
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+       SSL_shutdown( p->ssl );
+       return 0;
+}
+
+static int
+sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+       struct tls_data         *p;
+       
+       assert( sbiod != NULL );
+       assert( sbiod->sbiod_pvt != NULL );
+
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+       
+       if ( opt == LBER_SB_OPT_GET_SSL ) {
+               *((SSL **)arg) = p->ssl;
+               return 1;
+       }
+       
+       return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
+}
+
+static ber_slen_t
+sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+       struct tls_data         *p;
+       ber_slen_t              ret;
+       int                     err;
+
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       ret = SSL_read( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+       errno = WSAGetLastError();
+#endif
+       err = SSL_get_error( p->ssl, ret );
+       if (err == SSL_ERROR_WANT_READ ) {
+               sbiod->sbiod_sb->sb_trans_needs_read = 1;
+#ifdef WIN32
+               errno = EWOULDBLOCK;
+#endif
+       }
+       else
+               sbiod->sbiod_sb->sb_trans_needs_read = 0;
+       return ret;
+}
+
+static ber_slen_t
+sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+       struct tls_data         *p;
+       ber_slen_t              ret;
+       int                     err;
+
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       p = (struct tls_data *)sbiod->sbiod_pvt;
+
+       ret = SSL_write( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+       errno = WSAGetLastError();
+#endif
+       err = SSL_get_error( p->ssl, ret );
+       if (err == SSL_ERROR_WANT_WRITE ) {
+               sbiod->sbiod_sb->sb_trans_needs_write = 1;
+#ifdef WIN32
+               errno = EWOULDBLOCK;
+#endif
+       }
+       else
+               sbiod->sbiod_sb->sb_trans_needs_write = 0;
+       return ret;
+}
+
+Sockbuf_IO ldap_pvt_sockbuf_io_tls =
+{
+       sb_tls_setup,           /* sbi_setup */
+       sb_tls_remove,          /* sbi_remove */
+       sb_tls_ctrl,            /* sbi_ctrl */
+       sb_tls_read,            /* sbi_read */
+       sb_tls_write,           /* sbi_write */
+       sb_tls_close            /* sbi_close */
+};
+
+static int
+sb_tls_bio_create( BIO *b ) {
+       b->init = 1;
+       b->num = 0;
+       b->ptr = NULL;
+       b->flags = 0;
+       return 1;
+}
+
+static int
+sb_tls_bio_destroy( BIO *b )
+{
+       if ( b == NULL )
+               return 0;
+
+       b->ptr = NULL;          /* sb_tls_remove() will free it */
+       b->init = 0;
+       b->flags = 0;
+       return 1;
+}
+
+static int
+sb_tls_bio_read( BIO *b, char *buf, int len )
+{
+       struct tls_data         *p;
+       int                     ret;
+               
+       if ( buf == NULL || len <= 0 )
+               return 0;
+
+       p = (struct tls_data *)b->ptr;
+
+       if ( p == NULL || p->sbiod == NULL )
+               return 0;
+
+       ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
+
+       BIO_clear_retry_flags( b );
+       if ( ret < 0 && errno == EWOULDBLOCK )
+               BIO_set_retry_read( b );
+
+       return ret;
+}
+
+static int
+sb_tls_bio_write( BIO *b, char *buf, int len )
+{
+       struct tls_data         *p;
+       int                     ret;
+       
+       if ( buf == NULL || len <= 0 )
+               return 0;
+       
+       p = (struct tls_data *)b->ptr;
+
+       if ( p == NULL || p->sbiod == NULL )
+               return 0;
+
+       ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, buf, len );
+
+       BIO_clear_retry_flags( b );
+       if ( ret < 0 && errno == EWOULDBLOCK )
+               BIO_set_retry_write( b );
+
+       return ret;
+}
+
+static long
+sb_tls_bio_ctrl( BIO *b, int cmd, long num, char *ptr )
+{
+       if ( cmd == BIO_CTRL_FLUSH ) {
+               /* The OpenSSL library needs this */
+               return 1;
+       }
+       return 0;
+}
+
+static int
+sb_tls_bio_gets( BIO *b, char *buf, int len )
+{
+       return -1;
+}
+
+static int
+sb_tls_bio_puts( BIO *b, char *str )
+{
+       return sb_tls_bio_write( b, str, strlen( str ) );
+}
+       
+BIO_METHOD ldap_pvt_sb_bio_method =
+{
+       ( 100 | 0x400 ),                /* it's a source/sink BIO */
+       "sockbuf glue",
+       sb_tls_bio_write,
+       sb_tls_bio_read,
+       sb_tls_bio_puts,
+       sb_tls_bio_gets,
+       sb_tls_bio_ctrl,
+       sb_tls_bio_create,
+       sb_tls_bio_destroy
+};
+
 /*
  * Call this to do a TLS connect on a sockbuf. ctx_arg can be
  * a SSL_CTX * or NULL, in which case the default ctx is used.
@@ -313,13 +543,17 @@ ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg )
        SSL     *ssl;
 
        if ( HAS_TLS( sb ) ) {
-               ssl = (SSL *) sb->sb_iodata;
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
        } else {
-               ssl = alloc_handle( sb, ctx_arg );
+               ssl = alloc_handle( ctx_arg );
                if ( ssl == NULL )
                        return -1;
-               ber_pvt_sb_clear_io( sb );
-               ber_pvt_sb_set_io( sb, &tls_io, (void *)ssl );
+#ifdef LDAP_DEBUG
+               ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
+                       LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
+#endif
+               ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_tls,
+                       LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
        }
 
        err = SSL_connect( ssl );
@@ -335,8 +569,12 @@ ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg )
                        ld->ld_error = ldap_strdup(ERR_error_string(err, buf));
                }
                Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0);
-               ber_pvt_sb_clear_io( sb );
-               ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
+               ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_tls,
+                       LBER_SBIOD_LEVEL_TRANSPORT );
+#ifdef LDAP_DEBUG
+               ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
+                       LBER_SBIOD_LEVEL_TRANSPORT );
+#endif
                return -1;
        }
        return 0;
@@ -353,13 +591,17 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
        SSL     *ssl;
 
        if ( HAS_TLS( sb ) ) {
-               ssl = (SSL *) sb->sb_iodata;
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
        } else {
-               ssl = alloc_handle( sb, ctx_arg );
+               ssl = alloc_handle( ctx_arg );
                if ( ssl == NULL )
                        return -1;
-               ber_pvt_sb_clear_io( sb );
-               ber_pvt_sb_set_io( sb, &tls_io, (void *)ssl );
+#ifdef LDAP_DEBUG
+               ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
+                       LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
+#endif
+               ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_tls,
+                       LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
        }
 
        err = SSL_accept( ssl );
@@ -372,8 +614,12 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
                        return 1;
                Debug( LDAP_DEBUG_ANY,"TLS: can't accept.\n",0,0,0 );
                tls_report_error();
-               ber_pvt_sb_clear_io( sb );
-               ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
+               ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_tls,
+                       LBER_SBIOD_LEVEL_TRANSPORT );
+#ifdef LDAP_DEBUG
+               ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
+                       LBER_SBIOD_LEVEL_TRANSPORT );
+#endif
                return -1;
        }
        return 0;
@@ -390,16 +636,19 @@ ldap_pvt_tls_inplace ( Sockbuf *sb )
 void *
 ldap_pvt_tls_sb_handle( Sockbuf *sb )
 {
-       if (HAS_TLS( sb ))
-               return sb->sb_iodata;
-       else
+       void                    *p;
+       
+       if (HAS_TLS( sb )) {
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
+               return p;
+       }
                return NULL;
 }
 
 void *
 ldap_pvt_tls_get_handle( LDAP *ld )
 {
-       return ldap_pvt_tls_sb_handle(&ld->ld_sb);
+       return ldap_pvt_tls_sb_handle( ld->ld_sb );
 }
 
 const char *
@@ -568,60 +817,6 @@ ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
        return LDAP_SUCCESS;
 }
 
-
-static int
-tls_setup( Sockbuf *sb, void *arg )
-{
-       sb->sb_iodata = arg;
-       return 0;
-}
-
-static int
-tls_remove( Sockbuf *sb )
-{
-       SSL_free( (SSL *) sb->sb_iodata );
-       return 0;
-}
-
-static ber_slen_t
-tls_write( Sockbuf *sb, void *buf, ber_len_t sz )
-{
-       int ret = SSL_write( (SSL *)sb->sb_iodata, buf, sz );
-
-#ifdef HAVE_WINSOCK
-       errno = WSAGetLastError();
-#endif
-       update_flags(sb, (SSL *)sb->sb_iodata, ret );
-#ifdef WIN32
-       if (sb->sb_trans_needs_write)
-               errno = EWOULDBLOCK;
-#endif
-       return ret;
-}
-
-static ber_slen_t
-tls_read( Sockbuf *sb, void *buf, ber_len_t sz )
-{
-       int ret = SSL_read( (SSL *)sb->sb_iodata, buf, sz );
-
-#ifdef HAVE_WINSOCK
-       errno = WSAGetLastError();
-#endif
-       update_flags(sb, (SSL *)sb->sb_iodata, ret );
-#ifdef WIN32
-       if (sb->sb_trans_needs_read)
-               errno = EWOULDBLOCK;
-#endif
-       return ret;
-}
-
-static int
-tls_close( Sockbuf *sb )
-{
-       tcp_close( ber_pvt_sb_get_desc( sb ) );
-       return 0;
-}
-
 /* Derived from openssl/apps/s_cb.c */
 static void
 tls_info_cb( SSL *ssl, int where, int ret )
index e858d6e34317713e1499e93c6f683a24310697dc..7fd116f76048f781cfb36f115ceb949a71a0d2f9 100644 (file)
@@ -145,7 +145,7 @@ ldap_ld_free(
        }
 #endif 
 
-       ber_pvt_sb_destroy( &(ld->ld_sb) );   
+       ber_sockbuf_free( ld->ld_sb );   
    
        LDAP_FREE( (char *) ld );
    
index 7e86443755d8ddf252e0234a274640bf2be55299..8d1d2659c418b2809b6a32d0cb1ae2106e2df9f0 100644 (file)
@@ -38,7 +38,6 @@
 #include <quipu/ds_error.h>
 
 #include "lber.h"
-#include "../../libraries/liblber/lber-int.h"  /* get struct sockbuf */
 #include "ldap.h"
 #include "common.h"
 #include "lutil.h"             /* Get lutil_detach() */
@@ -492,7 +491,7 @@ do_queries(
        fd_set          readfds;
        int             rc;
        struct timeval  timeout;
-       Sockbuf         sb;
+       Sockbuf         *sb;
 #ifdef LDAP_CONNECTIONLESS
        struct sockaddr saddr, faddr;
        struct sockaddr *saddrlist[ 1 ];
@@ -515,10 +514,9 @@ do_queries(
                conn_init();
        }
 
-       ber_pvt_sb_init( &sb );
-       ber_pvt_sb_set_desc( &sb, clientsock );
-       ber_pvt_sb_set_io( &sb, (udp) ? &ber_pvt_sb_io_udp :
-                                       &ber_pvt_sb_io_tcp, NULL );
+       sb = ber_sockbuf_alloc( );
+       ber_sockbuf_add_io( sb, (udp) ? &ber_sockbuf_io_udp :
+               &ber_sockbuf_io_tcp, (void *)&clientsock );
        timeout.tv_sec = idletime;
        timeout.tv_usec = 0;
        for ( ;; ) {
@@ -547,7 +545,7 @@ do_queries(
                 * already waiting for us on the client sock.
                 */
 
-               if ( ! ber_pvt_sb_data_ready( &sb ) ) {
+               if ( ! ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
                        if ( (rc = select( dtblsize, &readfds, 0, 0,
                            udp ? 0 : &timeout )) < 1 ) {
 #ifdef LDAP_DEBUG
@@ -573,9 +571,9 @@ do_queries(
                        }
                }
 
-               if ( ber_pvt_sb_data_ready( &sb ) ||
+               if ( ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ) ||
                    FD_ISSET( clientsock, &readfds ) ) {
-                       client_request( &sb, conns, udp );
+                       client_request( sb, conns, udp );
                } else {
                        if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
                                Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
@@ -583,7 +581,7 @@ do_queries(
                                continue;
                        }
 
-                       dsa_response( dsaconn, &sb );
+                       dsa_response( dsaconn, sb );
                }
        }
        /* NOT REACHED */
index 95598ff28a9bae3bba6fe2451f5f2fe06f05e500..8f27d30430cad701aab28be20a38600d5d736818 100644 (file)
@@ -28,7 +28,6 @@
 #include <quipu/dua.h>
 
 #include "lber.h"
-#include "../../libraries/liblber/lber-int.h"  /* get struct berelement */
 #include "ldap.h"
 #include "common.h"
 
@@ -89,7 +88,8 @@ client_request(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( udp && dosyslog ) {
-               sai = (struct sockaddr_in *)ber_pvt_sb_udp_get_src( &clientsb );
+               ber_sockbuf_ctrl( clientsb, LBER_SB_OPT_UDP_GET_SRC,
+                       (void *)&sai );
                syslog( LOG_INFO, "UDP request from unknown (%s)",
                        inet_ntoa( sai->sin_addr ) );
        }
@@ -193,7 +193,7 @@ client_request(
                free( ber.ber_buf );
                return;
        }
-       sai = (struct sockaddr_in *) ber_pvt_sb_udp_get_src( &clientsb );
+       ber_sockbuf_ctrl( clientsb, LBER_SB_OPT_UDP_GET_SRC, (void *)&sai );
    
        if ( get_cldap_msg( msgid, tag,
            (struct sockaddr *)sai ) != NULL ) {
index 29ebd3e1bb2a9ba7b08d6fa580dcd774bddc3b65..d7a8e1445a77130cf09964a94e65cd93952d49ed 100644 (file)
@@ -24,7 +24,6 @@
 #include <quipu/dua.h>
 
 #include "lber.h"
-#include "../../libraries/liblber/lber-int.h"  /* get struct berelement */
 #include "ldap.h"
 #include "common.h"
 
@@ -281,7 +280,8 @@ send_ldap_msgresult(
 {
 #ifdef LDAP_CONNECTIONLESS
        if ( m->m_cldap ) {
-               ber_pvt_sb_udp_set_dst( &sb, &m->m_clientaddr );
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&m->m_clientaddr );
 
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
@@ -306,7 +306,7 @@ send_ldap_result(
        int             rc;
 #ifdef LDAP_CONNECTIONLESS
        int             cldap;
-       cldap = ( sb->sb_io == &ber_pvt_sb_io_udp );
+       cldap = ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, &ber_sockbuf_io_udp );
 #endif
 
        Debug( LDAP_DEBUG_TRACE, "send_ldap_result\n", 0, 0, 0 );
index 4ad1a3de8c301303c291818f1a4f2125b4e0f993..8ff3c194f64e6ac23f8cebb10d1cd4414fb6e492 100644 (file)
@@ -26,7 +26,6 @@
 #include <quipu/dua.h>
 
 #include "lber.h"
-#include "../../libraries/liblber/lber-int.h"  /* get struct berelement */
 #include "ldap.h"
 #include "common.h"
 
@@ -701,7 +700,8 @@ search_result(
                            LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
                        return;
                }
-               ber_pvt_sb_udp_set_dst( sb, &m->m_clientaddr );
+               ber_sockbuf_ctrl( sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&m->m_clientaddr );
 
                if ( ber_flush( sb, ber, 1 ) != 0 ) {
                    send_ldap_msgresult( sb, SEARCHRESTAG, m, 
index a2231eb5ed38bcc81ce5e702ebd891bec9124f3c..9a3b4feb564594fbabbdaa5f8c8a983216f17e1a 100644 (file)
@@ -16,9 +16,6 @@
 
 #include "slap.h"
 
-/* we need LBER internals */
-#include "../../libraries/liblber/lber-int.h"
-
 /* protected by connections_mutex */
 static ldap_pvt_thread_mutex_t connections_mutex;
 static Connection *connections = NULL;
@@ -213,9 +210,12 @@ static Connection* connection_get( ber_socket_t s )
 #else
        c = NULL;
        {
-               ber_socket_t i;
+               ber_socket_t i, sd;
 
                for(i=0; i<dtblsize; i++) {
+                       ber_sockbuf_ctrl( connections[i].c_sb,
+                               LBER_SB_OPT_GET_FD, &sd );
+
                        if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
                                assert( connections[i].c_conn_state == SLAP_C_INVALID );
                                assert( connections[i].c_sb == 0 );
@@ -224,7 +224,7 @@ static Connection* connection_get( ber_socket_t s )
 
                        if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
                                assert( connections[i].c_conn_state == SLAP_C_INVALID );
-                               assert( !ber_pvt_sb_in_use( connections[i].c_sb ) );
+                               assert( sd == AC_SOCKET_INVALID );
                                continue;
                        }
 
@@ -232,7 +232,7 @@ static Connection* connection_get( ber_socket_t s )
                         * so don't assert details here.
                         */
 
-                       if( ber_pvt_sb_get_desc( connections[i].c_sb ) == s ) {
+                       if( sd == s ) {
                                c = &connections[i];
                                break;
                        }
@@ -241,13 +241,16 @@ static Connection* connection_get( ber_socket_t s )
 #endif
 
        if( c != NULL ) {
+               ber_socket_t    sd;
+
                ldap_pvt_thread_mutex_lock( &c->c_mutex );
 
+               ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
                if( c->c_struct_state != SLAP_C_USED ) {
                        /* connection must have been closed due to resched */
 
                        assert( c->c_conn_state == SLAP_C_INVALID );
-                       assert( !ber_pvt_sb_in_use( c->c_sb ) );
+                       assert( sd == AC_SOCKET_INVALID );
 
                        Debug( LDAP_DEBUG_TRACE,
                                "connection_get(%d): connection not used\n",
@@ -265,7 +268,7 @@ static Connection* connection_get( ber_socket_t s )
 
                assert( c->c_struct_state == SLAP_C_USED );
                assert( c->c_conn_state != SLAP_C_INVALID );
-               assert( ber_pvt_sb_in_use( c->c_sb ) );
+               assert( sd != AC_SOCKET_INVALID );
 
        c->c_activitytime = slap_get_time();
        }
@@ -323,6 +326,10 @@ long connection_init(
                c = NULL;
 
         for( i=0; i < dtblsize; i++) {
+           ber_socket_t        sd;
+
+           ber_sockbuf_ctrl( connections[i].c_sb, LBER_SB_OPT_GET_FD, &sd );
+           
             if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) {
                 assert( connections[i].c_sb == 0 );
                 c = &connections[i];
@@ -330,14 +337,14 @@ long connection_init(
             }
 
             if( connections[i].c_struct_state == SLAP_C_UNUSED ) {
-                assert( !ber_pvt_sb_in_use( connections[i].c_sb ));
+                assert( sd == AC_SOCKET_INVALID );
                 c = &connections[i];
                 break;
             }
 
             assert( connections[i].c_struct_state == SLAP_C_USED );
             assert( connections[i].c_conn_state != SLAP_C_INVALID );
-            assert( ber_pvt_sb_in_use( connections[i].c_sb ));
+            assert( sd != AC_SOCKET_INVALID );
         }
 
         if( c == NULL ) {
@@ -418,10 +425,14 @@ long connection_init(
 
     c->c_activitytime = c->c_starttime = slap_get_time();
 
-    ber_pvt_sb_set_desc( c->c_sb, s );
-    ber_pvt_sb_set_io( c->c_sb, &ber_pvt_sb_io_tcp, NULL );
-
-    if( ber_pvt_sb_set_nonblock( c->c_sb, 1 ) < 0 ) {
+    ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp, LBER_SBIOD_LEVEL_PROVIDER,
+       (void *)&s );
+    ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead,
+       LBER_SBIOD_LEVEL_PROVIDER, NULL );
+#ifdef LDAP_DEBUG
+    ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, INT_MAX, NULL );
+#endif
+    if( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_NONBLOCK, (void *)1 ) < 0 ) {
         Debug( LDAP_DEBUG_ANY,
             "connection_init(%d, %s): set nonblocking failed\n",
             s, c->c_peer_name,0 );
@@ -454,6 +465,7 @@ static void
 connection_destroy( Connection *c )
 {
        /* note: connections_mutex should be locked by caller */
+    ber_socket_t       sd;
 
     assert( connections != NULL );
     assert( c != NULL );
@@ -527,18 +539,17 @@ connection_destroy( Connection *c )
                c->c_currentber = NULL;
        }
 
-       if ( ber_pvt_sb_in_use(c->c_sb) ) {
-               int sd = ber_pvt_sb_get_desc(c->c_sb);
-
+       ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
+       if ( sd != AC_SOCKET_INVALID ) {
                slapd_remove( sd, 0 );
-               ber_pvt_sb_close( c->c_sb );
 
                Statslog( LDAP_DEBUG_STATS,
                    "conn=%ld fd=%d closed\n",
                        c->c_connid, sd, 0, 0, 0 );
        }
 
-       ber_pvt_sb_destroy( c->c_sb );
+       ber_sockbuf_free( c->c_sb );
+       c->c_sb = ber_sockbuf_alloc( );
 
     c->c_conn_state = SLAP_C_INVALID;
     c->c_struct_state = SLAP_C_UNUSED;
@@ -590,27 +601,32 @@ void connection_closing( Connection *c )
        /* c_mutex must be locked by caller */
 
        if( c->c_conn_state != SLAP_C_CLOSING ) {
+               ber_socket_t    sd;
+
+               ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
                Debug( LDAP_DEBUG_TRACE,
                        "connection_closing: readying conn=%ld sd=%d for close\n",
-                       c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
+                       c->c_connid, sd, 0 );
 
                /* update state to closing */
                c->c_conn_state = SLAP_C_CLOSING;
 
                /* don't listen on this port anymore */
-               slapd_clr_read( ber_pvt_sb_get_desc( c->c_sb ), 1 );
+               slapd_clr_read( sd, 1 );
 
                /* abandon active operations */
                connection_abandon( c );
 
                /* wake write blocked operations */
-               slapd_clr_write( ber_pvt_sb_get_desc(c->c_sb), 1 );
+               slapd_clr_write( sd, 1 );
                ldap_pvt_thread_cond_signal( &c->c_write_cv );
        }
 }
 
 static void connection_close( Connection *c )
 {
+       ber_socket_t    sd;
+
        assert( connections != NULL );
        assert( c != NULL );
        assert( c->c_struct_state == SLAP_C_USED );
@@ -618,16 +634,17 @@ static void connection_close( Connection *c )
 
        /* note: connections_mutex and c_mutex should be locked by caller */
 
+       ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd );
        if( c->c_ops != NULL ) {
                Debug( LDAP_DEBUG_TRACE,
                        "connection_close: deferring conn=%ld sd=%d\n",
-                       c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
+                       c->c_connid, sd, 0 );
 
                return;
        }
 
        Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d\n",
-               c->c_connid, ber_pvt_sb_get_desc( c->c_sb ), 0 );
+               c->c_connid, sd, 0 );
 
        connection_destroy( c );
 }
@@ -893,15 +910,14 @@ int connection_read(ber_socket_t s)
                         * to propagate to client. */
                        FD_ZERO(&rfd);
                        FD_SET(s, &rfd);
-                       ber_pvt_sb_set_readahead(c->c_sb, 0);
                        for (rc=1; rc>0;)
                        {
-                           char buf[4096];
                            tv.tv_sec = 1;
                            tv.tv_usec = 0;
                            rc = select(s+1, &rfd, NULL, NULL, &tv);
                            if (rc == 1)
-                               rc = ber_pvt_sb_read(c->c_sb, buf, sizeof(buf));
+                               ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DRAIN,
+                                   NULL);
                        }
                        connection_close( c );
                } else if ( rc == 0 ) {
@@ -916,7 +932,7 @@ int connection_read(ber_socket_t s)
 #define CONNECTION_INPUT_LOOP 1
 
 #ifdef DATA_READY_LOOP
-       while(!rc && ber_pvt_sb_data_ready(&c->c_sb))
+       while( !rc && ber_sockbuf_ctrl( c->c_sb, LBER_SB_DATA_READY, NULL ) )
 #elif CONNECTION_INPUT_LOOP
        while(!rc)
 #endif
@@ -935,9 +951,9 @@ int connection_read(ber_socket_t s)
                connection_close( c );
        }
 
-       if ( ber_pvt_sb_needs_read( c->c_sb ) )
+       if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) )
                slapd_set_read( s, 1 );
-       if ( ber_pvt_sb_needs_write( c->c_sb ) )
+       if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) )
                slapd_set_write( s, 1 );
        connection_return( c );
        ldap_pvt_thread_mutex_unlock( &connections_mutex );
@@ -966,16 +982,13 @@ connection_input(
            != LDAP_TAG_MESSAGE )
        {
                int err = errno;
+               ber_socket_t    sd;
+
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
 
                Debug( LDAP_DEBUG_TRACE,
                        "ber_get_next on fd %d failed errno=%d (%s)\n",
-                       ber_pvt_sb_get_desc( conn->c_sb ), err, sock_errstr(err) );
-               Debug( LDAP_DEBUG_TRACE,
-                       "\t*** got %ld of %lu so far\n",
-                       (long) ( conn->c_currentber->ber_buf
-                               ?  conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf
-                               : 0 ),
-                       (long) conn->c_currentber->ber_len, 0 );
+                       sd, err, sock_errstr(err) );
 
                if ( err != EWOULDBLOCK && err != EAGAIN ) {
                        /* log, close and send error */
@@ -1043,9 +1056,12 @@ connection_resched( Connection *conn )
        Operation *op;
 
        if( conn->c_conn_state == SLAP_C_CLOSING ) {
+               ber_socket_t    sd;
+
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
                Debug( LDAP_DEBUG_TRACE,
                        "connection_resched: attempting closing conn=%ld sd=%d\n",
-                       conn->c_connid, ber_pvt_sb_get_desc( conn->c_sb ), 0 );
+                       conn->c_connid, sd, 0 );
 
                connection_close( conn );
                return 0;
@@ -1158,9 +1174,9 @@ int connection_write(ber_socket_t s)
 
        ldap_pvt_thread_cond_signal( &c->c_write_cv );
 
-       if ( ber_pvt_sb_needs_read( c->c_sb ) )
+       if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) )
                slapd_set_read( s, 1 );
-       if ( ber_pvt_sb_needs_write( c->c_sb ) )
+       if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) )
                slapd_set_write( s, 1 );
        connection_return( c );
        ldap_pvt_thread_mutex_unlock( &connections_mutex );
index d8bc0ffd18b4fc7245c55345081b46770e1e1e6f..75d30de43f01b29700b4fb598a95a33977eb0cc1 100644 (file)
@@ -19,9 +19,6 @@
 
 #include "slap.h"
 
-/* we need LBER internals */
-#include "../../libraries/liblber/lber-int.h"
-
 static char *v2ref( struct berval **ref, const char *text )
 {
        size_t len = 0, i = 0;
@@ -196,6 +193,7 @@ static long send_ldap_ber(
        /* write the pdu */
        while( 1 ) {
                int err;
+               ber_socket_t    sd;
 
                if ( connection_state_closing( conn ) ) {
                        ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
@@ -230,7 +228,8 @@ static long send_ldap_ber(
 
                /* wait for socket to be write-ready */
                conn->c_writewaiter = 1;
-               slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
+               slapd_set_write( sd, 1 );
 
                ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
                conn->c_writewaiter = 0;
@@ -382,7 +381,8 @@ send_ldap_disconnect(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
                    &op->o_clientaddr)->sin_addr ),
@@ -453,7 +453,8 @@ send_ldap_result(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
                    &op->o_clientaddr)->sin_addr ),
@@ -499,7 +500,8 @@ send_ldap_sasl(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
                    &op->o_clientaddr)->sin_addr ),
@@ -540,7 +542,8 @@ send_ldap_extended(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
                    &op->o_clientaddr)->sin_addr ),
@@ -603,7 +606,8 @@ send_search_result(
 
 #ifdef LDAP_CONNECTIONLESS
        if ( op->o_cldap ) {
-               ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
+               ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
+                   (void *)&op->o_clientaddr );
                Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
                    inet_ntoa(((struct sockaddr_in *)
                    &op->o_clientaddr)->sin_addr ),