X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Fliblber%2Fsockbuf.c;h=d997e92910954b943e5b3fe7139ff4caaeaf49bf;hb=f7a8ddc17e291c94af29a291a637652d396ff664;hp=3899206fc5a269527128edf2986e160baac709fc;hpb=a50f391bb37b059733404b7ec380a883162b23fb;p=openldap diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index 3899206fc5..d997e92910 100644 --- a/libraries/liblber/sockbuf.c +++ b/libraries/liblber/sockbuf.c @@ -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 . + * + * Copyright 1998-2013 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 + * . */ #include "portable.h" @@ -21,6 +30,10 @@ #include #endif /* HAVE_IO_H */ +#if defined( HAVE_FCNTL_H ) +#include +#endif + #if defined( HAVE_SYS_FILIO_H ) #include #elif defined( HAVE_SYS_IOCTL_H ) @@ -29,21 +42,24 @@ #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; + if( sb == NULL ) return NULL; ber_int_sb_init( sb ); return sb; @@ -68,52 +84,88 @@ 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 ) - *((int *)arg) = sb->sb_fd; + if ( arg != NULL ) { + *((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; + 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; + + 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; } @@ -128,8 +180,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 +192,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; @@ -148,37 +202,41 @@ 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 ) ) + + 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 +255,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 +269,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; } @@ -239,10 +296,11 @@ ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len ) 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; } @@ -251,7 +309,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 ) ); @@ -259,37 +317,35 @@ 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 ) - /* not enough data, so pretend no data was sent. */ - return -1; - return ret; + } + + 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 ) + if( nb ) { flags |= O_NONBLOCK; - else + } else { flags &= ~O_NONBLOCK; + } return fcntl( sd, F_SETFL, flags ); #elif defined( FIONBIO ) @@ -303,16 +359,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 @@ -324,15 +380,15 @@ 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; + 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; + return 0; } int @@ -348,7 +404,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 ); } @@ -364,12 +421,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; } @@ -385,12 +443,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; } @@ -409,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__ ) @@ -422,23 +481,8 @@ 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 recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); - return rc; - } #elif defined( HAVE_NCSA ) /* * NCSA Telnet TCP/IP stack (under DOS) @@ -462,10 +506,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, - (lensbiod_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 ); @@ -501,7 +530,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, - (lensbiod_sb->sb_fd, buf, len ); #endif @@ -512,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; } @@ -521,8 +551,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; } @@ -532,152 +563,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) @@ -691,15 +585,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 @@ -711,8 +608,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 ); @@ -740,8 +636,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; @@ -749,14 +644,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 ); @@ -790,12 +685,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 ); } @@ -803,8 +700,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 */ @@ -823,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 ); } @@ -841,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; } @@ -861,9 +776,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 */ @@ -880,12 +794,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,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; } @@ -932,31 +849,136 @@ 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; } -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; + 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 */