/* 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 )
int ret = 0;
assert( sb != NULL );
+ assert( SOCKBUF_VALID( sb ) );
switch ( opt ) {
case LBER_SB_OPT_HAS_IO:
/* 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 ) );
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 );
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 ) {
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) );
}
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 {
+ } 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;
}
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 {
+ 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;
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 */