]> git.sur5r.net Git - openldap/blobdiff - libraries/liblber/sockbuf.c
Update copyright statements
[openldap] / libraries / liblber / sockbuf.c
index e3ddbcd44a8833bcb0db1c830ef52797629e5fdf..ae5c07c8c1e4c28e1fba4bf370de5b3a203b185f 100644 (file)
@@ -1,7 +1,7 @@
 /* sockbuf.c - i/o routines with support for adding i/o layers. */
 /* $OpenLDAP$ */
 /*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
 #include <io.h>
 #endif /* HAVE_IO_H */
 
+#if defined( HAVE_FCNTL_H )
+#include <fcntl.h>
+#endif
+
 #if defined( HAVE_SYS_FILIO_H )
 #include <sys/filio.h>
 #elif defined( HAVE_SYS_IOCTL_H )
 
 #include "lber-int.h"
 
-#define MIN_BUFF_SIZE          4096
-#define MAX_BUFF_SIZE          65536
-#define DEFAULT_READAHEAD      16384
+#ifndef LBER_MIN_BUFF_SIZE
+#define LBER_MIN_BUFF_SIZE             4096
+#endif
+#ifndef LBER_MAX_BUFF_SIZE
+#define LBER_MAX_BUFF_SIZE             65536
+#endif
+#ifndef LBER_DEFAULT_READAHEAD
+#define LBER_DEFAULT_READAHEAD 16384
+#endif
 
 Sockbuf *
 ber_sockbuf_alloc( void )
@@ -42,8 +52,7 @@ ber_sockbuf_alloc( void )
 
        sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
 
-       if( sb == NULL )
-               return NULL;
+       if( sb == NULL ) return NULL;
 
        ber_int_sb_init( sb );
        return sb;
@@ -68,49 +77,72 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
 {
        Sockbuf_IO_Desc         *p;
        int                     ret = 0;
-       char                    buf[4096];
 
        assert( sb != NULL );
+       assert( SOCKBUF_VALID( sb ) );
 
        switch ( opt ) {
                case LBER_SB_OPT_HAS_IO:
                        p = sb->sb_iod;
-   
-                       while ( p && p->sbiod_io != (Sockbuf_IO *)arg )
+                       while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) {
                                p = p->sbiod_next;
+                       }
    
-                       if ( p )
+                       if ( p ) {
                                ret = 1;
+                       }
                        break;
+
                case LBER_SB_OPT_GET_FD:
-                       if ( arg != NULL )
+                       if ( arg != NULL ) {
                                *((int *)arg) = sb->sb_fd;
+                       }
                        ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
                        break;
+
                case LBER_SB_OPT_SET_FD:
                        sb->sb_fd = *((int *)arg);
                        ret = 1;
                        break;
+
                case LBER_SB_OPT_SET_NONBLOCK:
                        ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
                                ? -1 : 1;
                        break;
-               case LBER_SB_OPT_DRAIN:
-                       /* Drain the data source to enable possible errors (e.g.
-                        * TLS) to be propagated to the upper layers
-                        */
-                       do {
-                               ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
-                       } while ( ret == sizeof( buf ) );
 
-                       ret = 1;
-                       break;
+               case LBER_SB_OPT_DRAIN: {
+                               /* Drain the data source to enable possible errors (e.g.
+                                * TLS) to be propagated to the upper layers
+                                */
+                               char buf[LBER_MIN_BUFF_SIZE];
+
+                               do {
+                                       ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
+                               } while ( ret == sizeof( buf ) );
+
+                               ret = 1;
+                       } break;
+
                case LBER_SB_OPT_NEEDS_READ:
                        ret = ( sb->sb_trans_needs_read ? 1 : 0 );
                        break;
+
                case LBER_SB_OPT_NEEDS_WRITE:
                        ret = ( sb->sb_trans_needs_write ? 1 : 0 );
                        break;
+
+               case LBER_SB_OPT_GET_MAX_INCOMING:
+                       if ( arg != NULL ) {
+                               *((ber_len_t *)arg) = sb->sb_max_incoming;
+                       }
+                       ret = 1;
+                       break;
+
+               case LBER_SB_OPT_SET_MAX_INCOMING:
+                       sb->sb_max_incoming = *((ber_len_t *)arg);
+                       ret = 1;
+                       break;
+
                default:
                        ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod,
                                opt, arg );
@@ -128,8 +160,9 @@ ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
        assert( sb != NULL );
        assert( SOCKBUF_VALID( sb ) );
    
-       if ( sbio == NULL )
+       if ( sbio == NULL ) {
                return -1;
+       }
    
        q = &sb->sb_iod;
        p = *q;
@@ -139,8 +172,9 @@ ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
        }
    
        d = LBER_MALLOC( sizeof( *d ) );
-       if ( d == NULL )
+       if ( d == NULL ) {
                return -1;
+       }
    
        d->sbiod_level = layer;
        d->sbiod_sb = sb;
@@ -149,36 +183,40 @@ ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
        d->sbiod_next = p;
        *q = d;
       
-       if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) )
+       if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
                return -1;
+       }
       
        return 0;
-   }
+}
    
 int
 ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
 {
        Sockbuf_IO_Desc         *p, **q;
 
-   assert( sb != NULL );
+       assert( sb != NULL );
        assert( SOCKBUF_VALID( sb ) );
    
-       if ( sb->sb_iod == NULL )
+       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 )
+                               p->sbiod_io->sbi_remove( p ) < 0 )
+                       {
                                return -1;
+                       }
                        *q = p->sbiod_next;
                        LBER_FREE( p );
-        break;
-   }
+               break;
+               }
                q = &p->sbiod_next;
-}
+       }
 
        return 0;
 }
@@ -197,8 +235,9 @@ ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
 {
        assert( buf != NULL);
 
-       if (buf->buf_base)
+       if (buf->buf_base) {
                LBER_FREE( buf->buf_base );
+       }
        ber_pvt_sb_buf_init( buf );
 }
 
@@ -210,18 +249,16 @@ ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
    
        assert( buf != NULL );
 
-       for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
-               if (pw > MAX_BUFF_SIZE)
-      return -1;
-   }
+       for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
+               if (pw > LBER_MAX_BUFF_SIZE) return -1;
+       }
 
        if ( buf->buf_size < pw ) {
                p = LBER_REALLOC( buf->buf_base, pw );
-               if ( p == NULL )
-                       return -1;
+               if ( p == NULL ) return -1;
                buf->buf_base = p;
                buf->buf_size = pw;
-   }
+       }
        return 0;
 }
 
@@ -232,15 +269,18 @@ ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
 
        assert( buf != NULL );
        assert( sbb != NULL );
+#if 0
        assert( sbb->buf_size > 0 );
+#endif
 
        max = sbb->buf_end - sbb->buf_ptr;
        max = ( max < len) ? max : len;
        if ( max ) {
-               memcpy( buf, sbb->buf_base + sbb->buf_ptr, max );
+               AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
                sbb->buf_ptr += max;
-               if ( sbb->buf_ptr >= sbb->buf_end )
+               if ( sbb->buf_ptr >= sbb->buf_end ) {
                        sbb->buf_ptr = sbb->buf_end = 0;
+               }
    }
        return max;
 }
@@ -249,7 +289,7 @@ 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_slen_t ret;
 
        assert( sbiod != NULL );
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
@@ -257,26 +297,28 @@ ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
        to_go = buf_out->buf_end - buf_out->buf_ptr;
        assert( to_go > 0 );
    
-      for(;;) {
+       for(;;) {
                ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
                        buf_out->buf_ptr, to_go );
 #ifdef EINTR
-        if ((ret<0) && (errno==EINTR))
-          continue;
+               if ((ret<0) && (errno==EINTR)) continue;
 #endif
-        break;
-      }
+               break;
+       }
 
-       if ( ret <= 0 )
-   return ret;
+       if ( ret <= 0 ) return ret;
    
        buf_out->buf_ptr += ret;
-       if (buf_out->buf_ptr == buf_out->buf_end)
+       if (buf_out->buf_ptr == buf_out->buf_end) {
                buf_out->buf_end = buf_out->buf_ptr = 0;
-       if ( (ber_len_t)ret < to_go )
+       }
+
+       if ( (ber_len_t)ret < to_go ) {
                /* not enough data, so pretend no data was sent. */
                return -1;
-   return ret;
+       }
+
+       return ret;
 }
 
 int
@@ -284,10 +326,11 @@ ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
 {
 #if HAVE_FCNTL
        int flags = fcntl( sd, F_GETFL);
-       if( nb )
+       if( nb ) {
                flags |= O_NONBLOCK;
-       else
+       } else {
                flags &= ~O_NONBLOCK;
+       }
        return fcntl( sd, F_SETFL, flags );
                
 #elif defined( FIONBIO )
@@ -301,16 +344,16 @@ ber_int_sb_init( Sockbuf *sb )
 {
        assert( sb != NULL);
 
-   sb->sb_valid=LBER_VALID_SOCKBUF;
-   sb->sb_options = 0;
+       sb->sb_valid=LBER_VALID_SOCKBUF;
+       sb->sb_options = 0;
        sb->sb_debug = ber_int_debug;
        sb->sb_fd = AC_SOCKET_INVALID;
        sb->sb_iod = NULL;
-   sb->sb_trans_needs_read = 0;
-   sb->sb_trans_needs_write = 0;
+       sb->sb_trans_needs_read = 0;
+       sb->sb_trans_needs_write = 0;
    
-   assert( SOCKBUF_VALID( sb ) );
-   return 0;
+       assert( SOCKBUF_VALID( sb ) );
+       return 0;
 }
    
 int
@@ -323,14 +366,16 @@ ber_int_sb_close( Sockbuf *sb )
        p = sb->sb_iod;
        while ( p ) {
                if ( p->sbiod_io->sbi_close &&
-                               p->sbiod_io->sbi_close( p ) < 0 )
-      return -1;
+                       p->sbiod_io->sbi_close( p ) < 0 )
+               {
+                       return -1;
+               }
                p = p->sbiod_next;
-   }
+       }
    
        sb->sb_fd = AC_SOCKET_INVALID;
    
-   return 0;
+       return 0;
 }
 
 int
@@ -346,7 +391,8 @@ ber_int_sb_destroy( Sockbuf *sb )
                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 );
 }
 
@@ -362,12 +408,13 @@ ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
 
        for (;;) {
                ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
+
 #ifdef EINTR   
-               if ( ( ret < 0 ) && ( errno == EINTR ) )
-                       continue;
+               if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
 #endif
                break;
-}
+       }
+
        return ret;
 }
 
@@ -383,12 +430,13 @@ ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
 
        for (;;) {
                ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
+
 #ifdef EINTR   
-               if ( ( ret < 0 ) && ( errno == EINTR ) )
-                       continue;
+               if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
 #endif
                break;
-}
+       }
+
        return ret;
 }
 
@@ -420,23 +468,23 @@ sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
 /*
  * 32-bit Windows Socket API (under Windows NT or Windows 95)
  */
-   {
-   int rc;
+       {
+               int rc;
 
                rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 
 #ifdef HAVE_WINSOCK
-   if ( rc < 0 )
-   {
-     int err;
+               if ( rc < 0 ) {
+                       int err;
 
-     err = WSAGetLastError();
-     errno = err;
-   }
+                       err = WSAGetLastError();
+                       errno = err;
+               }
 #endif
 
-   return rc;
-   }
+               return rc;
+       }
+
 #elif defined( HAVE_NCSA )
 /*
  * NCSA Telnet TCP/IP stack (under DOS)
@@ -460,10 +508,10 @@ sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
  */
 #define MAX_WRITE      65535
        return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
-                   (len<MAX_WRITE)? len : MAX_WRITE );
+               (len<MAX_WRITE) ? len : MAX_WRITE );
 
 #elif defined( HAVE_PCNFS) \
-   || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
+       || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
 /*
  * PCNFS (under DOS)
  */
@@ -473,22 +521,18 @@ sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
 /*
  * 32-bit Windows Socket API (under Windows NT or Windows 95)
  */
+       {
+               int rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 
-   {
-   int rc;
-       
-               rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 #ifdef HAVE_WINSOCK
-   if ( rc < 0 )
-   {
-     int err;
-               
-     err = WSAGetLastError();
-     errno = err;
-   }
+               if ( rc < 0 ) {
+                       int err;
+                       err = WSAGetLastError();
+                       errno = err;
+               }
 #endif
-   return rc;
-   }
+               return rc;
+       }
 
 #elif defined(HAVE_NCSA)
        return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
@@ -499,7 +543,7 @@ sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
  */
 #define MAX_WRITE 65535
        return write( sbiod->sbiod_sb->sb_fd, buf,
-                (len<MAX_WRITE)? len : MAX_WRITE);
+               (len<MAX_WRITE) ? len : MAX_WRITE);
 #else
        return write( sbiod->sbiod_sb->sb_fd, buf, len );
 #endif   
@@ -519,8 +563,9 @@ static int
 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
        assert( sbiod != NULL );
 
-       if ( arg != NULL )
+       if ( arg != NULL ) {
                sbiod->sbiod_sb->sb_fd = *((int *)arg);
+       }
        return 0;
 }
 
@@ -530,152 +575,15 @@ sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
        return 0;
 }
 
-Sockbuf_IO ber_sockbuf_io_tcp =
-{
+Sockbuf_IO ber_sockbuf_io_tcp = {
        sb_stream_setup,        /* sbi_setup */
-       NULL,                   /* sbi_remove */
+       NULL,                           /* sbi_remove */
        sb_stream_ctrl,         /* sbi_ctrl */
        sb_stream_read,         /* sbi_read */
        sb_stream_write,        /* sbi_write */
        sb_stream_close         /* sbi_close */
 };
 
-/*
- * Support for UDP (CLDAP)
- */
-
-struct dgram_data
-{
-       struct sockaddr dst;
-       struct sockaddr src;
-};
-
-static int 
-sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
-{
-       struct dgram_data       *p;
-
-       assert( sbiod != NULL);
-       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-
-       p = LBER_MALLOC( sizeof( *p ) );
-       if ( p == NULL )
-     return -1;
-       memset( p, '\0', sizeof( *p ) );
-       sbiod->sbiod_pvt = (void *)p;
-       if ( arg != NULL )
-               sbiod->sbiod_sb->sb_fd = *((int *)arg);
-   return 0;
-}
-
-static int 
-sb_dgram_release( Sockbuf_IO_Desc *sbiod )
-{
-       assert( sbiod != NULL);
-       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-
-       LBER_FREE( sbiod->sbiod_pvt );
-       sbiod->sbiod_pvt = NULL;
-   return 0;
-}
-
-static ber_slen_t
-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       *p;
-   
-       assert( sbiod != NULL );
-       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-       assert( buf != NULL );
-
-       p = (struct dgram_data *)sbiod->sbiod_pvt;
-   
-   addrlen = sizeof( struct sockaddr );
-       rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->src,
-               &addrlen );
-   
-   return rc;
-# else /* LDAP_CONNECTIONLESS */
-   return -1;
-# endif /* LDAP_CONNECTIONLESS */
-}
-
-static ber_slen_t 
-sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
-{
-#ifdef LDAP_CONNECTIONLESS
-   ber_slen_t rc;
-       struct dgram_data       *p;
-   
-       assert( sbiod != NULL );
-       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-       assert( buf != NULL );
-
-       p = (struct dgram_data *)sbiod->sbiod_pvt;
-   
-       rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->dst,
-            sizeof( struct sockaddr ) );
-
-   if ( rc <= 0 )
-               return -1;
-   
-   /* fake error if write was not atomic */
-   if (rc < len) {
-# ifdef EMSGSIZE
-      errno = EMSGSIZE;
-# endif
-               return -1;
-   }
-   return rc;
-#else
-   return -1;
-#endif 
-}
-
-static int 
-sb_dgram_close( Sockbuf_IO_Desc *sbiod )
-{
-       assert( sbiod != NULL );
-       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-
-       tcp_close( sbiod->sbiod_sb->sb_fd );
-       return 0;
-}
-
-static int
-sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
-{
-       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 */
-};
 
 /*
  * Support for readahead (UDP needs it)
@@ -689,15 +597,18 @@ sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
        assert( sbiod != NULL );
 
        p = LBER_MALLOC( sizeof( *p ) );
-       if ( p == NULL )
-               return -1;
+       if ( p == NULL ) return -1;
+
        ber_pvt_sb_buf_init( p );
-       if ( arg == NULL )
-               ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
-       else
+
+       if ( arg == NULL ) {
+               ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD );
+       } else {
                ber_pvt_sb_grow_buffer( p, *((int *)arg) );
+       }
+
        sbiod->sbiod_pvt = p;
-   return 0;
+       return 0;
 }
 
 static int
@@ -709,8 +620,7 @@ sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
 
        p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
 
-       if ( p->buf_ptr != p->buf_end )
-               return -1;
+       if ( p->buf_ptr != p->buf_end ) return -1;
 
        ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
        LBER_FREE( sbiod->sbiod_pvt );
@@ -738,8 +648,7 @@ sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
        bufptr += ret;
        len -= ret;
 
-       if ( len == 0 )
-               return bufptr;
+       if ( len == 0 ) return bufptr;
 
        max = p->buf_size - p->buf_end;
        ret = 0;
@@ -747,14 +656,14 @@ sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
                ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
                        max );
 #ifdef EINTR   
-               if ( ( ret < 0 ) && ( errno == EINTR ) )
-                       continue;
+               if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
 #endif
                break;
-}
+       }
 
-       if ( ret < 0 )
+       if ( ret < 0 ) {
                return ( bufptr ? bufptr : ret );
+       }
 
        p->buf_end += ret;
        bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
@@ -788,12 +697,14 @@ sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
        p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
 
        if ( opt == LBER_SB_OPT_DATA_READY ) {
-               if ( p->buf_ptr != p->buf_end )
+               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) )
+               }
+
+       } 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 );
        }
@@ -801,8 +712,7 @@ sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
 }
 
-Sockbuf_IO ber_sockbuf_io_readahead =
-{
+Sockbuf_IO ber_sockbuf_io_readahead = {
        sb_rdahead_setup,       /* sbi_setup */
        sb_rdahead_remove,      /* sbi_remove */
        sb_rdahead_ctrl,        /* sbi_ctrl */
@@ -859,9 +769,8 @@ sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
        return 0;
 }
 
-Sockbuf_IO ber_sockbuf_io_fd =
-{
-       sb_fd_setup,            /* sbi_setup */
+Sockbuf_IO ber_sockbuf_io_fd = {
+       sb_fd_setup,    /* sbi_setup */
        NULL,                   /* sbi_remove */
        sb_fd_ctrl,             /* sbi_ctrl */
        sb_fd_read,             /* sbi_read */
@@ -878,12 +787,11 @@ sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 {
        assert( sbiod != NULL );
        
-       if ( arg == NULL )
-               arg = "sockbuf_";
+       if ( arg == NULL ) arg = "sockbuf_";
 
        sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
-       if ( sbiod->sbiod_pvt == NULL )
-   return -1;
+       if ( sbiod->sbiod_pvt == NULL ) return -1;
+
        strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
        return 0;
 }
@@ -911,17 +819,21 @@ 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 ) {
+       if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS)
+       {
+           int err = errno;
+           if ( ret < 0 ) {
                ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
-                       (long)len, strerror( errno ) );
-       }
-       else {
+                       (long)len, STRERROR( errno ) );
+           } else {
                ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
                        (long)len, (long)ret );
                ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        (const char *)buf, ret );
+           }
+           errno = err;
        }
        return ret;
 }
@@ -932,29 +844,136 @@ 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 ) {
+       if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS)
+       {
+           int err = errno;
+           if ( ret < 0 ) {
                ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        "%swrite: want=%ld error=%s\n",
                        (char *)sbiod->sbiod_pvt, (long)len,
-                       strerror( errno ) );
-       }
-       else {
+                       STRERROR( errno ) );
+               errno = err;
+           } else {
                ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        "%swrite: want=%ld, written=%ld\n",
                        (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
                ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
                        (const char *)buf, ret );
+           }
+           errno = err;
        }
+
        return ret;
 }
 
-Sockbuf_IO ber_sockbuf_io_debug =
-{
+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 */
+       NULL                            /* sbi_close */
+};
+
+#ifdef LDAP_CONNECTIONLESS
+
+/*
+ * Support for UDP (CLDAP)
+ *
+ * All I/O at this level must be atomic. For ease of use, the sb_readahead
+ * must be used above this module. All data reads and writes are prefixed
+ * with a sockaddr containing the address of the remote entity. Upper levels
+ * must read and write this sockaddr before doing the usual ber_printf/scanf
+ * operations on LDAP messages.
+ */
+
+static int 
+sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
+{
+       assert( sbiod != NULL);
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       if ( arg != NULL )
+               sbiod->sbiod_sb->sb_fd = *((int *)arg);
+       return 0;
+}
+
+static ber_slen_t
+sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
+{
+       ber_slen_t rc;
+       socklen_t  addrlen;
+       struct sockaddr *src;
+   
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+       assert( buf != NULL );
+
+       addrlen = sizeof( struct sockaddr );
+       src = buf;
+       buf += addrlen;
+       rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src,
+               &addrlen );
+
+       return rc > 0 ? rc+sizeof(struct sockaddr) : rc;
+}
+
+static ber_slen_t 
+sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
+{
+       ber_slen_t rc;
+       struct sockaddr *dst;
+   
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+       assert( buf != NULL );
+
+       dst = buf;
+       buf += sizeof( struct sockaddr );
+       len -= sizeof( struct sockaddr );
+   
+       rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst,
+            sizeof( struct sockaddr ) );
+
+       if ( rc < 0 )
+               return -1;
+   
+       /* fake error if write was not atomic */
+       if (rc < len) {
+# ifdef EMSGSIZE
+       errno = EMSGSIZE;
+# endif
+               return -1;
+       }
+       rc = len + sizeof(struct sockaddr);
+       return rc;
+}
+
+static int 
+sb_dgram_close( Sockbuf_IO_Desc *sbiod )
+{
+       assert( sbiod != NULL );
+       assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+       tcp_close( sbiod->sbiod_sb->sb_fd );
+       return 0;
+}
+
+static int
+sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+       /* This is an end IO descriptor */
+       return 0;
+}
+
+Sockbuf_IO ber_sockbuf_io_udp =
+{
+       sb_dgram_setup,         /* sbi_setup */
+       NULL,                   /* sbi_remove */
+       sb_dgram_ctrl,          /* sbi_ctrl */
+       sb_dgram_read,          /* sbi_read */
+       sb_dgram_write,         /* sbi_write */
+       sb_dgram_close          /* sbi_close */
 };
 
+#endif /* LDAP_CONNECTIONLESS */