openldap/libraries/liblber/sockbuf.c
Kurt Zeilenga 2e0912622b ITS#537: lber io rewrite from Gambor Gombas.
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.
2000-06-01 20:59:21 +00:00

960 lines
18 KiB
C

/* 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
*/
#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/unistd.h>
#ifdef HAVE_IO_H
#include <io.h>
#endif /* HAVE_IO_H */
#if defined( HAVE_SYS_FILIO_H )
#include <sys/filio.h>
#elif defined( HAVE_SYS_IOCTL_H )
#include <sys/ioctl.h>
#endif
#include "lber-int.h"
#define MIN_BUFF_SIZE 4096
#define MAX_BUFF_SIZE 65536
#define DEFAULT_READAHEAD 16384
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;
ber_int_sb_init( sb );
return sb;
}
void
ber_sockbuf_free( Sockbuf *sb )
{
assert( sb != NULL );
assert( SOCKBUF_VALID( sb ) );
ber_int_sb_close( sb );
ber_int_sb_destroy( sb );
LBER_FREE( sb );
}
/* 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 )
{
Sockbuf_IO_Desc *p;
int ret = 0;
char buf[4096];
assert( sb != NULL );
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 ret;
}
int
ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
{
Sockbuf_IO_Desc *d, *p, **q;
assert( sb != NULL );
assert( SOCKBUF_VALID( sb ) );
if ( sbio == NULL )
return -1;
q = &sb->sb_iod;
p = *q;
while ( p && p->sbiod_level > layer ) {
q = &p->sbiod_next;
p = *q;
}
d = LBER_MALLOC( sizeof( *d ) );
if ( d == NULL )
return -1;
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 ( 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( SOCKBUF_VALID( sb ) );
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;
}
q = &p->sbiod_next;
}
return 0;
}
void
ber_pvt_sb_buf_init( Sockbuf_Buf *buf )
{
buf->buf_base = NULL;
buf->buf_ptr = 0;
buf->buf_end = 0;
buf->buf_size = 0;
}
void
ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
{
assert( buf != NULL);
if (buf->buf_base)
LBER_FREE( buf->buf_base );
ber_pvt_sb_buf_init( buf );
}
int
ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
{
ber_len_t pw;
char *p;
assert( buf != NULL );
for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
if (pw > MAX_BUFF_SIZE)
return -1;
}
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;
}
return 0;
}
ber_len_t
ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
{
ber_len_t max;
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;
}
return max;
}
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;
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
to_go = buf_out->buf_end - buf_out->buf_ptr;
assert( to_go > 0 );
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;
#endif
break;
}
if ( ret <= 0 )
return ret;
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_socket_set_nonblock( ber_socket_t sd, int nb )
{
#if HAVE_FCNTL
int flags = fcntl( sd, F_GETFL);
if( nb )
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
return fcntl( sd, F_SETFL, flags );
#elif defined( FIONBIO )
ioctl_t status = nb ? 1 : 0;
return ioctl( sd, FIONBIO, &status );
#endif
}
int
ber_int_sb_init( Sockbuf *sb )
{
assert( sb != NULL);
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;
assert( SOCKBUF_VALID( sb ) );
return 0;
}
int
ber_int_sb_close( Sockbuf *sb )
{
Sockbuf_IO_Desc *p;
assert( sb != NULL);
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;
}
sb->sb_fd = AC_SOCKET_INVALID;
return 0;
}
int
ber_int_sb_destroy( Sockbuf *sb )
{
Sockbuf_IO_Desc *p;
assert( sb != NULL);
assert( SOCKBUF_VALID( sb ) );
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 );
}
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 ) );
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;
}
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 ) );
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;
}
/*
* Support for TCP
*/
static ber_slen_t
sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
{
assert( sbiod != NULL);
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
#if defined(MACOS)
/*
* MacTCP/OpenTransport
*/
return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
len, NULL );
#elif defined( HAVE_PCNFS ) || \
defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
/*
* PCNFS (under DOS)
*/
/*
* Windows Socket API (under DOS/Windows 3.x)
*/
/*
* 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;
}
#elif defined( HAVE_NCSA )
/*
* NCSA Telnet TCP/IP stack (under DOS)
*/
return nread( sbiod->sbiod_sb->sb_fd, buf, len );
#else
return read( sbiod->sbiod_sb->sb_fd, buf, len );
#endif
}
static ber_slen_t
sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
{
assert( sbiod != NULL);
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
#if defined(MACOS)
/*
* MacTCP/OpenTransport
*/
#define MAX_WRITE 65535
return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
(len<MAX_WRITE)? len : MAX_WRITE );
#elif defined( HAVE_PCNFS) \
|| defined( HAVE_WINSOCK) || defined ( __BEOS__ )
/*
* PCNFS (under DOS)
*/
/*
* Windows Socket API (under DOS/Windows 3.x)
*/
/*
* 32-bit Windows Socket API (under Windows NT or Windows 95)
*/
{
int rc;
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;
}
#elif defined(HAVE_NCSA)
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( sbiod->sbiod_sb->sb_fd, buf,
(len<MAX_WRITE)? len : MAX_WRITE);
#else
return write( sbiod->sbiod_sb->sb_fd, buf, len );
#endif
}
static int
sb_stream_close( Sockbuf_IO_Desc *sbiod )
{
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
tcp_close( sbiod->sbiod_sb->sb_fd );
return 0;
}
/* 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 =
{
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 */
};
/*
* 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)
*/
static int
sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
{
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;
}
static int
sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
{
Sockbuf_Buf *p;
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 */
};
/*
* Support for simple file IO
*/
static ber_slen_t
sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
{
assert( sbiod != NULL);
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
return read( sbiod->sbiod_sb->sb_fd, buf, len );
}
static ber_slen_t
sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
{
assert( sbiod != NULL);
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
return write( sbiod->sbiod_sb->sb_fd, buf, len );
}
static int
sb_fd_close( Sockbuf_IO_Desc *sbiod )
{
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
*/
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 */
};