]> git.sur5r.net Git - openldap/blobdiff - libraries/liblber/sockbuf.c
ITS#6932: Move assert(str) before Debug(..str).
[openldap] / libraries / liblber / sockbuf.c
index b4d7c4194b410d1ca78b8661e9485ed99f054f27..0d1c513b9bcda930aba4fe0c059e59384c3e1249 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-2011 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*256)
+#endif
+#ifndef LBER_DEFAULT_READAHEAD
+#define LBER_DEFAULT_READAHEAD 16384
+#endif
 
 Sockbuf *
 ber_sockbuf_alloc( void )
 {
        Sockbuf                 *sb;
 
-       ber_int_options.lbo_valid = LBER_INITIALIZED;
-
        sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
 
        if( sb == NULL ) return NULL;
@@ -89,13 +102,13 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
 
                case LBER_SB_OPT_GET_FD:
                        if ( arg != NULL ) {
-                               *((int *)arg) = sb->sb_fd;
+                               *((ber_socket_t *)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);
+                       sb->sb_fd = *((ber_socket_t *)arg);
                        ret = 1;
                        break;
 
@@ -108,7 +121,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 ) );
@@ -137,9 +150,22 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
                        ret = 1;
                        break;
 
+               case LBER_SB_OPT_UNGET_BUF:
+#ifdef LDAP_PF_LOCAL_SENDMSG
+                       sb->sb_ungetlen = ((struct berval *)arg)->bv_len;
+                       if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) {
+                               AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val,
+                                       sb->sb_ungetlen );
+                               ret = 1;
+                       } else {
+                               sb->sb_ungetlen = 0;
+                               ret = -1;
+                       }
+#endif
+                       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;
    }
 
@@ -176,11 +202,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;
 }
    
@@ -207,7 +233,7 @@ ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
                        }
                        *q = p->sbiod_next;
                        LBER_FREE( p );
-               break;
+                       break;
                }
                q = &p->sbiod_next;
        }
@@ -243,8 +269,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 ) {
@@ -307,18 +333,13 @@ 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;
 }
 
 int
 ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
 {
-#if HAVE_FCNTL
+#ifdef HAVE_FCNTL
        int flags = fcntl( sd, F_GETFL);
        if( nb ) {
                flags |= O_NONBLOCK;
@@ -359,9 +380,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;
@@ -449,7 +468,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__ )
@@ -462,22 +481,7 @@ 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;
-
-               rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
-
-#ifdef HAVE_WINSOCK
-               if ( rc < 0 ) {
-                       int err;
-
-                       err = WSAGetLastError();
-                       errno = err;
-               }
-#endif
-
-               return rc;
-       }
+       return recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 
 #elif defined( HAVE_NCSA )
 /*
@@ -515,18 +519,7 @@ 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 );
-
-#ifdef HAVE_WINSOCK
-               if ( rc < 0 ) {
-                       int err;
-                       err = WSAGetLastError();
-                       errno = err;
-               }
-#endif
-               return rc;
-       }
+       return send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
 
 #elif defined(HAVE_NCSA)
        return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
@@ -548,7 +541,8 @@ sb_stream_close( Sockbuf_IO_Desc *sbiod )
 {
        assert( sbiod != NULL );
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-       tcp_close( sbiod->sbiod_sb->sb_fd );
+       if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
+               tcp_close( sbiod->sbiod_sb->sb_fd );
    return 0;
 }
 
@@ -596,7 +590,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) );
        }
@@ -725,6 +719,24 @@ sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
        assert( sbiod != NULL);
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
+#ifdef LDAP_PF_LOCAL_SENDMSG
+       if ( sbiod->sbiod_sb->sb_ungetlen ) {
+               ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen;
+               if ( blen > len )
+                       blen = len;
+               AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen );
+               buf = (char *) buf + blen;
+               len -= blen;
+               sbiod->sbiod_sb->sb_ungetlen -= blen;
+               if ( sbiod->sbiod_sb->sb_ungetlen ) {
+                       AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf,
+                               sbiod->sbiod_sb->sb_ungetbuf+blen,
+                               sbiod->sbiod_sb->sb_ungetlen );
+               }
+               if ( len == 0 )
+                       return blen;
+       }
+#endif
        return read( sbiod->sbiod_sb->sb_fd, buf, len );
 }
 
@@ -743,7 +755,8 @@ sb_fd_close( Sockbuf_IO_Desc *sbiod )
        assert( sbiod != NULL );
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
-       close( sbiod->sbiod_sb->sb_fd );
+       if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
+               close( sbiod->sbiod_sb->sb_fd );
        return 0;
 }
 
@@ -811,19 +824,23 @@ static ber_slen_t
 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
 {
        ber_slen_t              ret;
+       char ebuf[128];
 
        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 = sock_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, AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
+               } 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 );
+               }
+               sock_errset(err);
        }
        return ret;
 }
@@ -832,20 +849,24 @@ static ber_slen_t
 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
 {
        ber_slen_t              ret;
+       char ebuf[128];
 
        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 = sock_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,
+                               AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
+               } 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 );
+               }
+               sock_errset(err);
        }
 
        return ret;
@@ -860,3 +881,104 @@ 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;
+       ber_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 = (char *) 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 = (char *) 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 ) );
+  
+       if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
+               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 */