]> git.sur5r.net Git - openldap/blobdiff - libraries/liblber/sockbuf.c
ITS#4046 fix from HEAD
[openldap] / libraries / liblber / sockbuf.c
index e16a76c6f92c8c3b356df8dd5eb7beeb8e18caae..6747093853cec69bf5254278e16250d3b8ab52b4 100644 (file)
@@ -1,8 +1,17 @@
 /* sockbuf.c - i/o routines with support for adding i/o layers. */
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2005 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
  */
 
 #include "portable.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 )
@@ -73,6 +88,7 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
        int                     ret = 0;
 
        assert( sb != NULL );
+       assert( SOCKBUF_VALID( sb ) );
 
        switch ( opt ) {
                case LBER_SB_OPT_HAS_IO:
@@ -107,7 +123,7 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
                                /* Drain the data source to enable possible errors (e.g.
                                 * TLS) to be propagated to the upper layers
                                 */
-                               char buf[MIN_BUFF_SIZE];
+                               char buf[LBER_MIN_BUFF_SIZE];
 
                                do {
                                        ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
@@ -124,9 +140,20 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
                        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 );
+                       ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg );
                        break;
    }
 
@@ -163,11 +190,11 @@ ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
        memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) );
        d->sbiod_next = p;
        *q = d;
-      
+
        if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
                return -1;
        }
-      
+
        return 0;
 }
    
@@ -230,8 +257,8 @@ 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 ) {
@@ -294,11 +321,6 @@ ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
                buf_out->buf_end = buf_out->buf_ptr = 0;
        }
 
-       if ( (ber_len_t)ret < to_go ) {
-               /* not enough data, so pretend no data was sent. */
-               return -1;
-       }
-
        return ret;
 }
 
@@ -346,9 +368,7 @@ 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 )
-               {
+               if ( p->sbiod_io->sbi_close && p->sbiod_io->sbi_close( p ) < 0 ) {
                        return -1;
                }
                p = p->sbiod_next;
@@ -436,7 +456,7 @@ sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
  * MacTCP/OpenTransport
  */
        return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
-                  len, NULL );
+               len, NULL );
 
 #elif defined( HAVE_PCNFS ) || \
    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
@@ -583,7 +603,7 @@ sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
        ber_pvt_sb_buf_init( p );
 
        if ( arg == NULL ) {
-               ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
+               ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD );
        } else {
                ber_pvt_sb_grow_buffer( p, *((int *)arg) );
        }
@@ -800,17 +820,20 @@ 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 );
+       if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
+               int err = errno;
+               if ( ret < 0 ) {
+                       ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
+                               "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
+                               (long)len, STRERROR( errno ) );
+               } else {
+                       ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
+                               "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
+                               (long)len, (long)ret );
+                       ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
+                               (const char *)buf, ret );
+               }
+               errno = err;
        }
        return ret;
 }
@@ -821,18 +844,21 @@ 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 );
+       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 {
+                       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;
@@ -847,3 +873,103 @@ Sockbuf_IO ber_sockbuf_io_debug = {
        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;
+       len -= 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 */