X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Fliblber%2Fsockbuf.c;h=0d1c513b9bcda930aba4fe0c059e59384c3e1249;hb=cba0d05a9dfd3cad69380e3ee2b492ddd7c7ca84;hp=e201157433b6808ec62f4833b4b2606ad85403f7;hpb=2f6b7e3d43ee1cb271feab6cf38eb202ed17fb0a;p=openldap diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index e201157433..0d1c513b9b 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-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 + * . */ #include "portable.h" @@ -37,7 +46,7 @@ #define LBER_MIN_BUFF_SIZE 4096 #endif #ifndef LBER_MAX_BUFF_SIZE -#define LBER_MAX_BUFF_SIZE 65536 +#define LBER_MAX_BUFF_SIZE (65536*256) #endif #ifndef LBER_DEFAULT_READAHEAD #define LBER_DEFAULT_READAHEAD 16384 @@ -48,8 +57,6 @@ ber_sockbuf_alloc( void ) { Sockbuf *sb; - ber_int_options.lbo_valid = LBER_INITIALIZED; - sb = LBER_CALLOC( 1, sizeof( Sockbuf ) ); if( sb == NULL ) return NULL; @@ -95,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; @@ -143,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; } @@ -182,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; } @@ -213,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; } @@ -313,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; @@ -365,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; @@ -455,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__ ) @@ -468,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 ) /* @@ -521,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 ); @@ -554,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; } @@ -731,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 ); } @@ -749,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; } @@ -817,22 +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 (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) - { - 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; } @@ -841,23 +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 (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) - { - 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; @@ -871,3 +880,105 @@ Sockbuf_IO ber_sockbuf_io_debug = { sb_debug_write, /* sbi_write */ 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 */