1*549b59edSchristos /* $NetBSD: sockbuf.c,v 1.3 2021/08/14 16:14:55 christos Exp $ */
24e6df137Slukem
32de962bdSlukem /* sockbuf.c - i/o routines with support for adding i/o layers. */
4d11b170bStron /* $OpenLDAP$ */
52de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
62de962bdSlukem *
7*549b59edSchristos * Copyright 1998-2021 The OpenLDAP Foundation.
82de962bdSlukem * All rights reserved.
92de962bdSlukem *
102de962bdSlukem * Redistribution and use in source and binary forms, with or without
112de962bdSlukem * modification, are permitted only as authorized by the OpenLDAP
122de962bdSlukem * Public License.
132de962bdSlukem *
142de962bdSlukem * A copy of this license is available in the file LICENSE in the
152de962bdSlukem * top-level directory of the distribution or, alternatively, at
162de962bdSlukem * <http://www.OpenLDAP.org/license.html>.
172de962bdSlukem */
182de962bdSlukem
19376af7d7Schristos #include <sys/cdefs.h>
20*549b59edSchristos __RCSID("$NetBSD: sockbuf.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
21376af7d7Schristos
222de962bdSlukem #include "portable.h"
232de962bdSlukem
242de962bdSlukem #include <stdio.h>
252de962bdSlukem
262de962bdSlukem #include <ac/stdlib.h>
272de962bdSlukem
282de962bdSlukem #include <ac/ctype.h>
292de962bdSlukem #include <ac/errno.h>
302de962bdSlukem #include <ac/socket.h>
312de962bdSlukem #include <ac/string.h>
322de962bdSlukem #include <ac/unistd.h>
332de962bdSlukem
342de962bdSlukem #ifdef HAVE_IO_H
352de962bdSlukem #include <io.h>
362de962bdSlukem #endif /* HAVE_IO_H */
372de962bdSlukem
382de962bdSlukem #if defined( HAVE_FCNTL_H )
392de962bdSlukem #include <fcntl.h>
402de962bdSlukem #endif
412de962bdSlukem
422de962bdSlukem #if defined( HAVE_SYS_FILIO_H )
432de962bdSlukem #include <sys/filio.h>
442de962bdSlukem #elif defined( HAVE_SYS_IOCTL_H )
452de962bdSlukem #include <sys/ioctl.h>
462de962bdSlukem #endif
472de962bdSlukem
482de962bdSlukem #include "lber-int.h"
492de962bdSlukem
502de962bdSlukem #ifndef LBER_MIN_BUFF_SIZE
512de962bdSlukem #define LBER_MIN_BUFF_SIZE 4096
522de962bdSlukem #endif
532de962bdSlukem #ifndef LBER_MAX_BUFF_SIZE
542de962bdSlukem #define LBER_MAX_BUFF_SIZE (65536*256)
552de962bdSlukem #endif
562de962bdSlukem #ifndef LBER_DEFAULT_READAHEAD
572de962bdSlukem #define LBER_DEFAULT_READAHEAD 16384
582de962bdSlukem #endif
592de962bdSlukem
602de962bdSlukem Sockbuf *
ber_sockbuf_alloc(void)612de962bdSlukem ber_sockbuf_alloc( void )
622de962bdSlukem {
632de962bdSlukem Sockbuf *sb;
642de962bdSlukem
652de962bdSlukem sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
662de962bdSlukem
672de962bdSlukem if( sb == NULL ) return NULL;
682de962bdSlukem
692de962bdSlukem ber_int_sb_init( sb );
702de962bdSlukem return sb;
712de962bdSlukem }
722de962bdSlukem
732de962bdSlukem void
ber_sockbuf_free(Sockbuf * sb)742de962bdSlukem ber_sockbuf_free( Sockbuf *sb )
752de962bdSlukem {
762de962bdSlukem assert( sb != NULL );
772de962bdSlukem assert( SOCKBUF_VALID( sb ) );
782de962bdSlukem
792de962bdSlukem ber_int_sb_close( sb );
802de962bdSlukem ber_int_sb_destroy( sb );
812de962bdSlukem LBER_FREE( sb );
822de962bdSlukem }
832de962bdSlukem
842de962bdSlukem /* Return values: -1: error, 0: no operation performed or the answer is false,
852de962bdSlukem * 1: successful operation or the answer is true
862de962bdSlukem */
872de962bdSlukem int
ber_sockbuf_ctrl(Sockbuf * sb,int opt,void * arg)882de962bdSlukem ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
892de962bdSlukem {
902de962bdSlukem Sockbuf_IO_Desc *p;
912de962bdSlukem int ret = 0;
922de962bdSlukem
932de962bdSlukem assert( sb != NULL );
942de962bdSlukem assert( SOCKBUF_VALID( sb ) );
952de962bdSlukem
962de962bdSlukem switch ( opt ) {
972de962bdSlukem case LBER_SB_OPT_HAS_IO:
982de962bdSlukem p = sb->sb_iod;
992de962bdSlukem while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) {
1002de962bdSlukem p = p->sbiod_next;
1012de962bdSlukem }
1022de962bdSlukem
1032de962bdSlukem if ( p ) {
1042de962bdSlukem ret = 1;
1052de962bdSlukem }
1062de962bdSlukem break;
1072de962bdSlukem
1082de962bdSlukem case LBER_SB_OPT_GET_FD:
1092de962bdSlukem if ( arg != NULL ) {
1102de962bdSlukem *((ber_socket_t *)arg) = sb->sb_fd;
1112de962bdSlukem }
1122de962bdSlukem ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
1132de962bdSlukem break;
1142de962bdSlukem
1152de962bdSlukem case LBER_SB_OPT_SET_FD:
1162de962bdSlukem sb->sb_fd = *((ber_socket_t *)arg);
1172de962bdSlukem ret = 1;
1182de962bdSlukem break;
1192de962bdSlukem
1202de962bdSlukem case LBER_SB_OPT_SET_NONBLOCK:
1212de962bdSlukem ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
1222de962bdSlukem ? -1 : 1;
1232de962bdSlukem break;
1242de962bdSlukem
1252de962bdSlukem case LBER_SB_OPT_DRAIN: {
1262de962bdSlukem /* Drain the data source to enable possible errors (e.g.
1272de962bdSlukem * TLS) to be propagated to the upper layers
1282de962bdSlukem */
1292de962bdSlukem char buf[LBER_MIN_BUFF_SIZE];
1302de962bdSlukem
1312de962bdSlukem do {
1322de962bdSlukem ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
1332de962bdSlukem } while ( ret == sizeof( buf ) );
1342de962bdSlukem
1352de962bdSlukem ret = 1;
1362de962bdSlukem } break;
1372de962bdSlukem
1382de962bdSlukem case LBER_SB_OPT_NEEDS_READ:
1392de962bdSlukem ret = ( sb->sb_trans_needs_read ? 1 : 0 );
1402de962bdSlukem break;
1412de962bdSlukem
1422de962bdSlukem case LBER_SB_OPT_NEEDS_WRITE:
1432de962bdSlukem ret = ( sb->sb_trans_needs_write ? 1 : 0 );
1442de962bdSlukem break;
1452de962bdSlukem
1462de962bdSlukem case LBER_SB_OPT_GET_MAX_INCOMING:
1472de962bdSlukem if ( arg != NULL ) {
1482de962bdSlukem *((ber_len_t *)arg) = sb->sb_max_incoming;
1492de962bdSlukem }
1502de962bdSlukem ret = 1;
1512de962bdSlukem break;
1522de962bdSlukem
1532de962bdSlukem case LBER_SB_OPT_SET_MAX_INCOMING:
1542de962bdSlukem sb->sb_max_incoming = *((ber_len_t *)arg);
1552de962bdSlukem ret = 1;
1562de962bdSlukem break;
1572de962bdSlukem
1582de962bdSlukem case LBER_SB_OPT_UNGET_BUF:
1592de962bdSlukem #ifdef LDAP_PF_LOCAL_SENDMSG
1602de962bdSlukem sb->sb_ungetlen = ((struct berval *)arg)->bv_len;
1612de962bdSlukem if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) {
1622de962bdSlukem AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val,
1632de962bdSlukem sb->sb_ungetlen );
1642de962bdSlukem ret = 1;
1652de962bdSlukem } else {
1662de962bdSlukem sb->sb_ungetlen = 0;
1672de962bdSlukem ret = -1;
1682de962bdSlukem }
1692de962bdSlukem #endif
1702de962bdSlukem break;
1712de962bdSlukem
1722de962bdSlukem default:
1732de962bdSlukem ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg );
1742de962bdSlukem break;
1752de962bdSlukem }
1762de962bdSlukem
1772de962bdSlukem return ret;
1782de962bdSlukem }
1792de962bdSlukem
1802de962bdSlukem int
ber_sockbuf_add_io(Sockbuf * sb,Sockbuf_IO * sbio,int layer,void * arg)1812de962bdSlukem ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
1822de962bdSlukem {
1832de962bdSlukem Sockbuf_IO_Desc *d, *p, **q;
1842de962bdSlukem
1852de962bdSlukem assert( sb != NULL );
1862de962bdSlukem assert( SOCKBUF_VALID( sb ) );
1872de962bdSlukem
1882de962bdSlukem if ( sbio == NULL ) {
1892de962bdSlukem return -1;
1902de962bdSlukem }
1912de962bdSlukem
1922de962bdSlukem q = &sb->sb_iod;
1932de962bdSlukem p = *q;
1942de962bdSlukem while ( p && p->sbiod_level > layer ) {
1952de962bdSlukem q = &p->sbiod_next;
1962de962bdSlukem p = *q;
1972de962bdSlukem }
1982de962bdSlukem
1992de962bdSlukem d = LBER_MALLOC( sizeof( *d ) );
2002de962bdSlukem if ( d == NULL ) {
2012de962bdSlukem return -1;
2022de962bdSlukem }
2032de962bdSlukem
2042de962bdSlukem d->sbiod_level = layer;
2052de962bdSlukem d->sbiod_sb = sb;
2062de962bdSlukem d->sbiod_io = sbio;
2072de962bdSlukem memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) );
2082de962bdSlukem d->sbiod_next = p;
2092de962bdSlukem *q = d;
2102de962bdSlukem
2112de962bdSlukem if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
2122de962bdSlukem return -1;
2132de962bdSlukem }
2142de962bdSlukem
2152de962bdSlukem return 0;
2162de962bdSlukem }
2172de962bdSlukem
2182de962bdSlukem int
ber_sockbuf_remove_io(Sockbuf * sb,Sockbuf_IO * sbio,int layer)2192de962bdSlukem ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
2202de962bdSlukem {
2212de962bdSlukem Sockbuf_IO_Desc *p, **q;
2222de962bdSlukem
2232de962bdSlukem assert( sb != NULL );
2242de962bdSlukem assert( SOCKBUF_VALID( sb ) );
2252de962bdSlukem
2262de962bdSlukem if ( sb->sb_iod == NULL ) {
2272de962bdSlukem return -1;
2282de962bdSlukem }
2292de962bdSlukem
2302de962bdSlukem q = &sb->sb_iod;
2312de962bdSlukem while ( *q != NULL ) {
2322de962bdSlukem p = *q;
2332de962bdSlukem if ( layer == p->sbiod_level && p->sbiod_io == sbio ) {
2342de962bdSlukem if ( p->sbiod_io->sbi_remove != NULL &&
2352de962bdSlukem p->sbiod_io->sbi_remove( p ) < 0 )
2362de962bdSlukem {
2372de962bdSlukem return -1;
2382de962bdSlukem }
2392de962bdSlukem *q = p->sbiod_next;
2402de962bdSlukem LBER_FREE( p );
2412de962bdSlukem break;
2422de962bdSlukem }
2432de962bdSlukem q = &p->sbiod_next;
2442de962bdSlukem }
2452de962bdSlukem
2462de962bdSlukem return 0;
2472de962bdSlukem }
2482de962bdSlukem
2492de962bdSlukem void
ber_pvt_sb_buf_init(Sockbuf_Buf * buf)2502de962bdSlukem ber_pvt_sb_buf_init( Sockbuf_Buf *buf )
2512de962bdSlukem {
2522de962bdSlukem buf->buf_base = NULL;
2532de962bdSlukem buf->buf_ptr = 0;
2542de962bdSlukem buf->buf_end = 0;
2552de962bdSlukem buf->buf_size = 0;
2562de962bdSlukem }
2572de962bdSlukem
2582de962bdSlukem void
ber_pvt_sb_buf_destroy(Sockbuf_Buf * buf)2592de962bdSlukem ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
2602de962bdSlukem {
2612de962bdSlukem assert( buf != NULL);
2622de962bdSlukem
2632de962bdSlukem if (buf->buf_base) {
2642de962bdSlukem LBER_FREE( buf->buf_base );
2652de962bdSlukem }
2662de962bdSlukem ber_pvt_sb_buf_init( buf );
2672de962bdSlukem }
2682de962bdSlukem
2692de962bdSlukem int
ber_pvt_sb_grow_buffer(Sockbuf_Buf * buf,ber_len_t minsize)2702de962bdSlukem ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
2712de962bdSlukem {
2722de962bdSlukem ber_len_t pw;
2732de962bdSlukem char *p;
2742de962bdSlukem
2752de962bdSlukem assert( buf != NULL );
2762de962bdSlukem
2772de962bdSlukem for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
2782de962bdSlukem if (pw > LBER_MAX_BUFF_SIZE) return -1;
2792de962bdSlukem }
2802de962bdSlukem
2812de962bdSlukem if ( buf->buf_size < pw ) {
2822de962bdSlukem p = LBER_REALLOC( buf->buf_base, pw );
2832de962bdSlukem if ( p == NULL ) return -1;
2842de962bdSlukem buf->buf_base = p;
2852de962bdSlukem buf->buf_size = pw;
2862de962bdSlukem }
2872de962bdSlukem return 0;
2882de962bdSlukem }
2892de962bdSlukem
2902de962bdSlukem ber_len_t
ber_pvt_sb_copy_out(Sockbuf_Buf * sbb,char * buf,ber_len_t len)2912de962bdSlukem ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
2922de962bdSlukem {
2932de962bdSlukem ber_len_t max;
2942de962bdSlukem
2952de962bdSlukem assert( buf != NULL );
2962de962bdSlukem assert( sbb != NULL );
2972de962bdSlukem #if 0
2982de962bdSlukem assert( sbb->buf_size > 0 );
2992de962bdSlukem #endif
3002de962bdSlukem
3012de962bdSlukem max = sbb->buf_end - sbb->buf_ptr;
3022de962bdSlukem max = ( max < len) ? max : len;
3032de962bdSlukem if ( max ) {
3042de962bdSlukem AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
3052de962bdSlukem sbb->buf_ptr += max;
3062de962bdSlukem if ( sbb->buf_ptr >= sbb->buf_end ) {
3072de962bdSlukem sbb->buf_ptr = sbb->buf_end = 0;
3082de962bdSlukem }
3092de962bdSlukem }
3102de962bdSlukem return max;
3112de962bdSlukem }
3122de962bdSlukem
3132de962bdSlukem ber_slen_t
ber_pvt_sb_do_write(Sockbuf_IO_Desc * sbiod,Sockbuf_Buf * buf_out)3142de962bdSlukem ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
3152de962bdSlukem {
3162de962bdSlukem ber_len_t to_go;
3172de962bdSlukem ber_slen_t ret;
3182de962bdSlukem
3192de962bdSlukem assert( sbiod != NULL );
3202de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
3212de962bdSlukem
3222de962bdSlukem to_go = buf_out->buf_end - buf_out->buf_ptr;
3232de962bdSlukem assert( to_go > 0 );
3242de962bdSlukem
3252de962bdSlukem for(;;) {
3262de962bdSlukem ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
3272de962bdSlukem buf_out->buf_ptr, to_go );
3282de962bdSlukem #ifdef EINTR
3292de962bdSlukem if ((ret<0) && (errno==EINTR)) continue;
3302de962bdSlukem #endif
3312de962bdSlukem break;
3322de962bdSlukem }
3332de962bdSlukem
3342de962bdSlukem if ( ret <= 0 ) return ret;
3352de962bdSlukem
3362de962bdSlukem buf_out->buf_ptr += ret;
3372de962bdSlukem if (buf_out->buf_ptr == buf_out->buf_end) {
3382de962bdSlukem buf_out->buf_end = buf_out->buf_ptr = 0;
3392de962bdSlukem }
3402de962bdSlukem
3412de962bdSlukem return ret;
3422de962bdSlukem }
3432de962bdSlukem
3442de962bdSlukem int
ber_pvt_socket_set_nonblock(ber_socket_t sd,int nb)3452de962bdSlukem ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
3462de962bdSlukem {
3472de962bdSlukem #ifdef HAVE_FCNTL
3482de962bdSlukem int flags = fcntl( sd, F_GETFL);
3492de962bdSlukem if( nb ) {
3502de962bdSlukem flags |= O_NONBLOCK;
3512de962bdSlukem } else {
3522de962bdSlukem flags &= ~O_NONBLOCK;
3532de962bdSlukem }
3542de962bdSlukem return fcntl( sd, F_SETFL, flags );
3552de962bdSlukem
3562de962bdSlukem #elif defined( FIONBIO )
3572de962bdSlukem ioctl_t status = nb ? 1 : 0;
3582de962bdSlukem return ioctl( sd, FIONBIO, &status );
3592de962bdSlukem #endif
3602de962bdSlukem }
3612de962bdSlukem
3622de962bdSlukem int
ber_int_sb_init(Sockbuf * sb)3632de962bdSlukem ber_int_sb_init( Sockbuf *sb )
3642de962bdSlukem {
3652de962bdSlukem assert( sb != NULL);
3662de962bdSlukem
3672de962bdSlukem sb->sb_valid=LBER_VALID_SOCKBUF;
3682de962bdSlukem sb->sb_options = 0;
3692de962bdSlukem sb->sb_debug = ber_int_debug;
3702de962bdSlukem sb->sb_fd = AC_SOCKET_INVALID;
3712de962bdSlukem sb->sb_iod = NULL;
3722de962bdSlukem sb->sb_trans_needs_read = 0;
3732de962bdSlukem sb->sb_trans_needs_write = 0;
3742de962bdSlukem
3752de962bdSlukem assert( SOCKBUF_VALID( sb ) );
3762de962bdSlukem return 0;
3772de962bdSlukem }
3782de962bdSlukem
3792de962bdSlukem int
ber_int_sb_close(Sockbuf * sb)3802de962bdSlukem ber_int_sb_close( Sockbuf *sb )
3812de962bdSlukem {
3822de962bdSlukem Sockbuf_IO_Desc *p;
3832de962bdSlukem
3842de962bdSlukem assert( sb != NULL);
3852de962bdSlukem
3862de962bdSlukem p = sb->sb_iod;
3872de962bdSlukem while ( p ) {
3882de962bdSlukem if ( p->sbiod_io->sbi_close && p->sbiod_io->sbi_close( p ) < 0 ) {
3892de962bdSlukem return -1;
3902de962bdSlukem }
3912de962bdSlukem p = p->sbiod_next;
3922de962bdSlukem }
3932de962bdSlukem
3942de962bdSlukem sb->sb_fd = AC_SOCKET_INVALID;
3952de962bdSlukem
3962de962bdSlukem return 0;
3972de962bdSlukem }
3982de962bdSlukem
3992de962bdSlukem int
ber_int_sb_destroy(Sockbuf * sb)4002de962bdSlukem ber_int_sb_destroy( Sockbuf *sb )
4012de962bdSlukem {
4022de962bdSlukem Sockbuf_IO_Desc *p;
4032de962bdSlukem
4042de962bdSlukem assert( sb != NULL);
4052de962bdSlukem assert( SOCKBUF_VALID( sb ) );
4062de962bdSlukem
4072de962bdSlukem while ( sb->sb_iod ) {
4082de962bdSlukem p = sb->sb_iod->sbiod_next;
4092de962bdSlukem ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io,
4102de962bdSlukem sb->sb_iod->sbiod_level );
4112de962bdSlukem sb->sb_iod = p;
4122de962bdSlukem }
4132de962bdSlukem
4142de962bdSlukem return ber_int_sb_init( sb );
4152de962bdSlukem }
4162de962bdSlukem
4172de962bdSlukem ber_slen_t
ber_int_sb_read(Sockbuf * sb,void * buf,ber_len_t len)4182de962bdSlukem ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
4192de962bdSlukem {
4202de962bdSlukem ber_slen_t ret;
4212de962bdSlukem
4222de962bdSlukem assert( buf != NULL );
4232de962bdSlukem assert( sb != NULL);
4242de962bdSlukem assert( sb->sb_iod != NULL );
4252de962bdSlukem assert( SOCKBUF_VALID( sb ) );
4262de962bdSlukem
4272de962bdSlukem for (;;) {
4282de962bdSlukem ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
4292de962bdSlukem
4302de962bdSlukem #ifdef EINTR
4312de962bdSlukem if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
4322de962bdSlukem #endif
4332de962bdSlukem break;
4342de962bdSlukem }
4352de962bdSlukem
4362de962bdSlukem return ret;
4372de962bdSlukem }
4382de962bdSlukem
4392de962bdSlukem ber_slen_t
ber_int_sb_write(Sockbuf * sb,void * buf,ber_len_t len)4402de962bdSlukem ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
4412de962bdSlukem {
4422de962bdSlukem ber_slen_t ret;
4432de962bdSlukem
4442de962bdSlukem assert( buf != NULL );
4452de962bdSlukem assert( sb != NULL);
4462de962bdSlukem assert( sb->sb_iod != NULL );
4472de962bdSlukem assert( SOCKBUF_VALID( sb ) );
4482de962bdSlukem
4492de962bdSlukem for (;;) {
4502de962bdSlukem ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
4512de962bdSlukem
4522de962bdSlukem #ifdef EINTR
4532de962bdSlukem if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
4542de962bdSlukem #endif
4552de962bdSlukem break;
4562de962bdSlukem }
4572de962bdSlukem
4582de962bdSlukem return ret;
4592de962bdSlukem }
4602de962bdSlukem
4612de962bdSlukem /*
4622de962bdSlukem * Support for TCP
4632de962bdSlukem */
4642de962bdSlukem
4652de962bdSlukem static ber_slen_t
sb_stream_read(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)4662de962bdSlukem sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
4672de962bdSlukem {
4682de962bdSlukem assert( sbiod != NULL);
4692de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
4702de962bdSlukem
4712de962bdSlukem #if defined(MACOS)
4722de962bdSlukem /*
4732de962bdSlukem * MacTCP/OpenTransport
4742de962bdSlukem */
4752de962bdSlukem return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
4762de962bdSlukem len, NULL );
4772de962bdSlukem
4782de962bdSlukem #elif defined( HAVE_PCNFS ) || \
4792de962bdSlukem defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
4802de962bdSlukem /*
4812de962bdSlukem * PCNFS (under DOS)
4822de962bdSlukem */
4832de962bdSlukem /*
4842de962bdSlukem * Windows Socket API (under DOS/Windows 3.x)
4852de962bdSlukem */
4862de962bdSlukem /*
4872de962bdSlukem * 32-bit Windows Socket API (under Windows NT or Windows 95)
4882de962bdSlukem */
4892de962bdSlukem return recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
4902de962bdSlukem
4912de962bdSlukem #elif defined( HAVE_NCSA )
4922de962bdSlukem /*
4932de962bdSlukem * NCSA Telnet TCP/IP stack (under DOS)
4942de962bdSlukem */
4952de962bdSlukem return nread( sbiod->sbiod_sb->sb_fd, buf, len );
4962de962bdSlukem
4972de962bdSlukem #else
4982de962bdSlukem return read( sbiod->sbiod_sb->sb_fd, buf, len );
4992de962bdSlukem #endif
5002de962bdSlukem }
5012de962bdSlukem
5022de962bdSlukem static ber_slen_t
sb_stream_write(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)5032de962bdSlukem sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
5042de962bdSlukem {
5052de962bdSlukem assert( sbiod != NULL);
5062de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
5072de962bdSlukem
5082de962bdSlukem #if defined(MACOS)
5092de962bdSlukem /*
5102de962bdSlukem * MacTCP/OpenTransport
5112de962bdSlukem */
5122de962bdSlukem #define MAX_WRITE 65535
5132de962bdSlukem return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
5142de962bdSlukem (len<MAX_WRITE) ? len : MAX_WRITE );
5152de962bdSlukem
5162de962bdSlukem #elif defined( HAVE_PCNFS) \
5172de962bdSlukem || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
5182de962bdSlukem /*
5192de962bdSlukem * PCNFS (under DOS)
5202de962bdSlukem */
5212de962bdSlukem /*
5222de962bdSlukem * Windows Socket API (under DOS/Windows 3.x)
5232de962bdSlukem */
5242de962bdSlukem /*
5252de962bdSlukem * 32-bit Windows Socket API (under Windows NT or Windows 95)
5262de962bdSlukem */
5272de962bdSlukem return send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
5282de962bdSlukem
5292de962bdSlukem #elif defined(HAVE_NCSA)
5302de962bdSlukem return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
5312de962bdSlukem
5322de962bdSlukem #elif defined(VMS)
5332de962bdSlukem /*
5342de962bdSlukem * VMS -- each write must be 64K or smaller
5352de962bdSlukem */
5362de962bdSlukem #define MAX_WRITE 65535
5372de962bdSlukem return write( sbiod->sbiod_sb->sb_fd, buf,
5382de962bdSlukem (len<MAX_WRITE) ? len : MAX_WRITE);
5392de962bdSlukem #else
5402de962bdSlukem return write( sbiod->sbiod_sb->sb_fd, buf, len );
5412de962bdSlukem #endif
5422de962bdSlukem }
5432de962bdSlukem
5442de962bdSlukem static int
sb_stream_close(Sockbuf_IO_Desc * sbiod)5452de962bdSlukem sb_stream_close( Sockbuf_IO_Desc *sbiod )
5462de962bdSlukem {
5472de962bdSlukem assert( sbiod != NULL );
5482de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
549d11b170bStron if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
5502de962bdSlukem tcp_close( sbiod->sbiod_sb->sb_fd );
5512de962bdSlukem return 0;
5522de962bdSlukem }
5532de962bdSlukem
5542de962bdSlukem /* The argument is a pointer to the socket descriptor */
5552de962bdSlukem static int
sb_stream_setup(Sockbuf_IO_Desc * sbiod,void * arg)5562de962bdSlukem sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
5572de962bdSlukem assert( sbiod != NULL );
5582de962bdSlukem
5592de962bdSlukem if ( arg != NULL ) {
5602de962bdSlukem sbiod->sbiod_sb->sb_fd = *((int *)arg);
5612de962bdSlukem }
5622de962bdSlukem return 0;
5632de962bdSlukem }
5642de962bdSlukem
5652de962bdSlukem static int
sb_stream_ctrl(Sockbuf_IO_Desc * sbiod,int opt,void * arg)5662de962bdSlukem sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
5672de962bdSlukem /* This is an end IO descriptor */
5682de962bdSlukem return 0;
5692de962bdSlukem }
5702de962bdSlukem
5712de962bdSlukem Sockbuf_IO ber_sockbuf_io_tcp = {
5722de962bdSlukem sb_stream_setup, /* sbi_setup */
5732de962bdSlukem NULL, /* sbi_remove */
5742de962bdSlukem sb_stream_ctrl, /* sbi_ctrl */
5752de962bdSlukem sb_stream_read, /* sbi_read */
5762de962bdSlukem sb_stream_write, /* sbi_write */
5772de962bdSlukem sb_stream_close /* sbi_close */
5782de962bdSlukem };
5792de962bdSlukem
5802de962bdSlukem
5812de962bdSlukem /*
5822de962bdSlukem * Support for readahead (UDP needs it)
5832de962bdSlukem */
5842de962bdSlukem
5852de962bdSlukem static int
sb_rdahead_setup(Sockbuf_IO_Desc * sbiod,void * arg)5862de962bdSlukem sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
5872de962bdSlukem {
5882de962bdSlukem Sockbuf_Buf *p;
5892de962bdSlukem
5902de962bdSlukem assert( sbiod != NULL );
5912de962bdSlukem
5922de962bdSlukem p = LBER_MALLOC( sizeof( *p ) );
5932de962bdSlukem if ( p == NULL ) return -1;
5942de962bdSlukem
5952de962bdSlukem ber_pvt_sb_buf_init( p );
5962de962bdSlukem
5972de962bdSlukem if ( arg == NULL ) {
5982de962bdSlukem ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD );
5992de962bdSlukem } else {
6002de962bdSlukem ber_pvt_sb_grow_buffer( p, *((int *)arg) );
6012de962bdSlukem }
6022de962bdSlukem
6032de962bdSlukem sbiod->sbiod_pvt = p;
6042de962bdSlukem return 0;
6052de962bdSlukem }
6062de962bdSlukem
6072de962bdSlukem static int
sb_rdahead_remove(Sockbuf_IO_Desc * sbiod)6082de962bdSlukem sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
6092de962bdSlukem {
6102de962bdSlukem Sockbuf_Buf *p;
6112de962bdSlukem
6122de962bdSlukem assert( sbiod != NULL );
6132de962bdSlukem
6142de962bdSlukem p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
6152de962bdSlukem
6162de962bdSlukem if ( p->buf_ptr != p->buf_end ) return -1;
6172de962bdSlukem
6182de962bdSlukem ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
6192de962bdSlukem LBER_FREE( sbiod->sbiod_pvt );
6202de962bdSlukem sbiod->sbiod_pvt = NULL;
6212de962bdSlukem
6222de962bdSlukem return 0;
6232de962bdSlukem }
6242de962bdSlukem
6252de962bdSlukem static ber_slen_t
sb_rdahead_read(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)6262de962bdSlukem sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
6272de962bdSlukem {
6282de962bdSlukem Sockbuf_Buf *p;
6292de962bdSlukem ber_slen_t bufptr = 0, ret, max;
6302de962bdSlukem
6312de962bdSlukem assert( sbiod != NULL );
6322de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
6332de962bdSlukem assert( sbiod->sbiod_next != NULL );
6342de962bdSlukem
6352de962bdSlukem p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
6362de962bdSlukem
6372de962bdSlukem assert( p->buf_size > 0 );
6382de962bdSlukem
6392de962bdSlukem /* Are there anything left in the buffer? */
6402de962bdSlukem ret = ber_pvt_sb_copy_out( p, buf, len );
6412de962bdSlukem bufptr += ret;
6422de962bdSlukem len -= ret;
6432de962bdSlukem
6442de962bdSlukem if ( len == 0 ) return bufptr;
6452de962bdSlukem
6462de962bdSlukem max = p->buf_size - p->buf_end;
6472de962bdSlukem ret = 0;
6482de962bdSlukem while ( max > 0 ) {
6492de962bdSlukem ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
6502de962bdSlukem max );
6512de962bdSlukem #ifdef EINTR
6522de962bdSlukem if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
6532de962bdSlukem #endif
6542de962bdSlukem break;
6552de962bdSlukem }
6562de962bdSlukem
6572de962bdSlukem if ( ret < 0 ) {
6582de962bdSlukem return ( bufptr ? bufptr : ret );
6592de962bdSlukem }
6602de962bdSlukem
6612de962bdSlukem p->buf_end += ret;
6622de962bdSlukem bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
6632de962bdSlukem return bufptr;
6642de962bdSlukem }
6652de962bdSlukem
6662de962bdSlukem static ber_slen_t
sb_rdahead_write(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)6672de962bdSlukem sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
6682de962bdSlukem {
6692de962bdSlukem assert( sbiod != NULL );
6702de962bdSlukem assert( sbiod->sbiod_next != NULL );
6712de962bdSlukem
6722de962bdSlukem return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
6732de962bdSlukem }
6742de962bdSlukem
6752de962bdSlukem static int
sb_rdahead_close(Sockbuf_IO_Desc * sbiod)6762de962bdSlukem sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
6772de962bdSlukem {
6782de962bdSlukem assert( sbiod != NULL );
6792de962bdSlukem
6802de962bdSlukem /* Just erase the buffer */
6812de962bdSlukem ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
6822de962bdSlukem return 0;
6832de962bdSlukem }
6842de962bdSlukem
6852de962bdSlukem static int
sb_rdahead_ctrl(Sockbuf_IO_Desc * sbiod,int opt,void * arg)6862de962bdSlukem sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
6872de962bdSlukem {
6882de962bdSlukem Sockbuf_Buf *p;
6892de962bdSlukem
6902de962bdSlukem p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
6912de962bdSlukem
6922de962bdSlukem if ( opt == LBER_SB_OPT_DATA_READY ) {
6932de962bdSlukem if ( p->buf_ptr != p->buf_end ) {
6942de962bdSlukem return 1;
6952de962bdSlukem }
6962de962bdSlukem
6972de962bdSlukem } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
6982de962bdSlukem if ( p->buf_size >= *((ber_len_t *)arg) ) {
6992de962bdSlukem return 0;
7002de962bdSlukem }
7012de962bdSlukem return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
7022de962bdSlukem -1 : 1 );
7032de962bdSlukem }
7042de962bdSlukem
7052de962bdSlukem return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
7062de962bdSlukem }
7072de962bdSlukem
7082de962bdSlukem Sockbuf_IO ber_sockbuf_io_readahead = {
7092de962bdSlukem sb_rdahead_setup, /* sbi_setup */
7102de962bdSlukem sb_rdahead_remove, /* sbi_remove */
7112de962bdSlukem sb_rdahead_ctrl, /* sbi_ctrl */
7122de962bdSlukem sb_rdahead_read, /* sbi_read */
7132de962bdSlukem sb_rdahead_write, /* sbi_write */
7142de962bdSlukem sb_rdahead_close /* sbi_close */
7152de962bdSlukem };
7162de962bdSlukem
7172de962bdSlukem /*
7182de962bdSlukem * Support for simple file IO
7192de962bdSlukem */
7202de962bdSlukem
7212de962bdSlukem static ber_slen_t
sb_fd_read(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)7222de962bdSlukem sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
7232de962bdSlukem {
7242de962bdSlukem assert( sbiod != NULL);
7252de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
7262de962bdSlukem
7272de962bdSlukem #ifdef LDAP_PF_LOCAL_SENDMSG
7282de962bdSlukem if ( sbiod->sbiod_sb->sb_ungetlen ) {
7292de962bdSlukem ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen;
7302de962bdSlukem if ( blen > len )
7312de962bdSlukem blen = len;
7322de962bdSlukem AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen );
7332de962bdSlukem buf = (char *) buf + blen;
7342de962bdSlukem len -= blen;
7352de962bdSlukem sbiod->sbiod_sb->sb_ungetlen -= blen;
7362de962bdSlukem if ( sbiod->sbiod_sb->sb_ungetlen ) {
7372de962bdSlukem AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf,
7382de962bdSlukem sbiod->sbiod_sb->sb_ungetbuf+blen,
7392de962bdSlukem sbiod->sbiod_sb->sb_ungetlen );
7402de962bdSlukem }
7412de962bdSlukem if ( len == 0 )
7422de962bdSlukem return blen;
7432de962bdSlukem }
7442de962bdSlukem #endif
7452de962bdSlukem return read( sbiod->sbiod_sb->sb_fd, buf, len );
7462de962bdSlukem }
7472de962bdSlukem
7482de962bdSlukem static ber_slen_t
sb_fd_write(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)7492de962bdSlukem sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
7502de962bdSlukem {
7512de962bdSlukem assert( sbiod != NULL);
7522de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
7532de962bdSlukem
7542de962bdSlukem return write( sbiod->sbiod_sb->sb_fd, buf, len );
7552de962bdSlukem }
7562de962bdSlukem
7572de962bdSlukem static int
sb_fd_close(Sockbuf_IO_Desc * sbiod)7582de962bdSlukem sb_fd_close( Sockbuf_IO_Desc *sbiod )
7592de962bdSlukem {
7602de962bdSlukem assert( sbiod != NULL );
7612de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
7622de962bdSlukem
763d11b170bStron if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
7642de962bdSlukem close( sbiod->sbiod_sb->sb_fd );
7652de962bdSlukem return 0;
7662de962bdSlukem }
7672de962bdSlukem
7682de962bdSlukem /* The argument is a pointer to the file descriptor */
7692de962bdSlukem static int
sb_fd_setup(Sockbuf_IO_Desc * sbiod,void * arg)7702de962bdSlukem sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
7712de962bdSlukem assert( sbiod != NULL );
7722de962bdSlukem
7732de962bdSlukem if ( arg != NULL )
7742de962bdSlukem sbiod->sbiod_sb->sb_fd = *((int *)arg);
7752de962bdSlukem return 0;
7762de962bdSlukem }
7772de962bdSlukem
7782de962bdSlukem static int
sb_fd_ctrl(Sockbuf_IO_Desc * sbiod,int opt,void * arg)7792de962bdSlukem sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
7802de962bdSlukem /* This is an end IO descriptor */
7812de962bdSlukem return 0;
7822de962bdSlukem }
7832de962bdSlukem
7842de962bdSlukem Sockbuf_IO ber_sockbuf_io_fd = {
7852de962bdSlukem sb_fd_setup, /* sbi_setup */
7862de962bdSlukem NULL, /* sbi_remove */
7872de962bdSlukem sb_fd_ctrl, /* sbi_ctrl */
7882de962bdSlukem sb_fd_read, /* sbi_read */
7892de962bdSlukem sb_fd_write, /* sbi_write */
7902de962bdSlukem sb_fd_close /* sbi_close */
7912de962bdSlukem };
7922de962bdSlukem
7932de962bdSlukem /*
7942de962bdSlukem * Debugging layer
7952de962bdSlukem */
7962de962bdSlukem
7972de962bdSlukem static int
sb_debug_setup(Sockbuf_IO_Desc * sbiod,void * arg)7982de962bdSlukem sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
7992de962bdSlukem {
8002de962bdSlukem assert( sbiod != NULL );
8012de962bdSlukem
8022de962bdSlukem if ( arg == NULL ) arg = "sockbuf_";
8032de962bdSlukem
8042de962bdSlukem sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
8052de962bdSlukem if ( sbiod->sbiod_pvt == NULL ) return -1;
8062de962bdSlukem
8072de962bdSlukem strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
8082de962bdSlukem return 0;
8092de962bdSlukem }
8102de962bdSlukem
8112de962bdSlukem static int
sb_debug_remove(Sockbuf_IO_Desc * sbiod)8122de962bdSlukem sb_debug_remove( Sockbuf_IO_Desc *sbiod )
8132de962bdSlukem {
8142de962bdSlukem assert( sbiod != NULL );
8152de962bdSlukem assert( sbiod->sbiod_pvt != NULL );
8162de962bdSlukem
8172de962bdSlukem LBER_FREE( sbiod->sbiod_pvt );
8182de962bdSlukem sbiod->sbiod_pvt = NULL;
8192de962bdSlukem return 0;
8202de962bdSlukem }
8212de962bdSlukem
8222de962bdSlukem static int
sb_debug_ctrl(Sockbuf_IO_Desc * sbiod,int opt,void * arg)8232de962bdSlukem sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
8242de962bdSlukem {
8252de962bdSlukem return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
8262de962bdSlukem }
8272de962bdSlukem
8282de962bdSlukem static ber_slen_t
sb_debug_read(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)8292de962bdSlukem sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
8302de962bdSlukem {
8312de962bdSlukem ber_slen_t ret;
8322de962bdSlukem char ebuf[128];
8332de962bdSlukem
8342de962bdSlukem ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
8352de962bdSlukem if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
8362de962bdSlukem int err = sock_errno();
8372de962bdSlukem if ( ret < 0 ) {
8382de962bdSlukem ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8392de962bdSlukem "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
8402de962bdSlukem (long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
8412de962bdSlukem } else {
8422de962bdSlukem ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8432de962bdSlukem "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
8442de962bdSlukem (long)len, (long)ret );
8452de962bdSlukem ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8462de962bdSlukem (const char *)buf, ret );
8472de962bdSlukem }
8482de962bdSlukem sock_errset(err);
8492de962bdSlukem }
8502de962bdSlukem return ret;
8512de962bdSlukem }
8522de962bdSlukem
8532de962bdSlukem static ber_slen_t
sb_debug_write(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)8542de962bdSlukem sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
8552de962bdSlukem {
8562de962bdSlukem ber_slen_t ret;
8572de962bdSlukem char ebuf[128];
8582de962bdSlukem
8592de962bdSlukem ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
8602de962bdSlukem if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
8612de962bdSlukem int err = sock_errno();
8622de962bdSlukem if ( ret < 0 ) {
8632de962bdSlukem ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8642de962bdSlukem "%swrite: want=%ld error=%s\n",
8652de962bdSlukem (char *)sbiod->sbiod_pvt, (long)len,
8662de962bdSlukem AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
8672de962bdSlukem } else {
8682de962bdSlukem ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8692de962bdSlukem "%swrite: want=%ld, written=%ld\n",
8702de962bdSlukem (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
8712de962bdSlukem ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
8722de962bdSlukem (const char *)buf, ret );
8732de962bdSlukem }
8742de962bdSlukem sock_errset(err);
8752de962bdSlukem }
8762de962bdSlukem
8772de962bdSlukem return ret;
8782de962bdSlukem }
8792de962bdSlukem
8802de962bdSlukem Sockbuf_IO ber_sockbuf_io_debug = {
8812de962bdSlukem sb_debug_setup, /* sbi_setup */
8822de962bdSlukem sb_debug_remove, /* sbi_remove */
8832de962bdSlukem sb_debug_ctrl, /* sbi_ctrl */
8842de962bdSlukem sb_debug_read, /* sbi_read */
8852de962bdSlukem sb_debug_write, /* sbi_write */
8862de962bdSlukem NULL /* sbi_close */
8872de962bdSlukem };
8882de962bdSlukem
8892de962bdSlukem #ifdef LDAP_CONNECTIONLESS
8902de962bdSlukem
8912de962bdSlukem /*
8922de962bdSlukem * Support for UDP (CLDAP)
8932de962bdSlukem *
8942de962bdSlukem * All I/O at this level must be atomic. For ease of use, the sb_readahead
8952de962bdSlukem * must be used above this module. All data reads and writes are prefixed
896d11b170bStron * with a sockaddr_storage containing the address of the remote entity. Upper levels
897d11b170bStron * must read and write this sockaddr_storage before doing the usual ber_printf/scanf
8982de962bdSlukem * operations on LDAP messages.
8992de962bdSlukem */
9002de962bdSlukem
9012de962bdSlukem static int
sb_dgram_setup(Sockbuf_IO_Desc * sbiod,void * arg)9022de962bdSlukem sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
9032de962bdSlukem {
9042de962bdSlukem assert( sbiod != NULL);
9052de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
9062de962bdSlukem
9072de962bdSlukem if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg);
9082de962bdSlukem return 0;
9092de962bdSlukem }
9102de962bdSlukem
9112de962bdSlukem static ber_slen_t
sb_dgram_read(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)9122de962bdSlukem sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
9132de962bdSlukem {
9142de962bdSlukem ber_slen_t rc;
9152de962bdSlukem ber_socklen_t addrlen;
9162de962bdSlukem struct sockaddr *src;
9172de962bdSlukem
9182de962bdSlukem assert( sbiod != NULL );
9192de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
9202de962bdSlukem assert( buf != NULL );
9212de962bdSlukem
922d11b170bStron addrlen = sizeof( struct sockaddr_storage );
9232de962bdSlukem src = buf;
9242de962bdSlukem buf = (char *) buf + addrlen;
9252de962bdSlukem len -= addrlen;
9262de962bdSlukem rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen );
9272de962bdSlukem
928d11b170bStron return rc > 0 ? rc+sizeof(struct sockaddr_storage) : rc;
9292de962bdSlukem }
9302de962bdSlukem
9312de962bdSlukem static ber_slen_t
sb_dgram_write(Sockbuf_IO_Desc * sbiod,void * buf,ber_len_t len)9322de962bdSlukem sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
9332de962bdSlukem {
9342de962bdSlukem ber_slen_t rc;
9352de962bdSlukem struct sockaddr *dst;
936376af7d7Schristos socklen_t dstsize;
9372de962bdSlukem
9382de962bdSlukem assert( sbiod != NULL );
9392de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
9402de962bdSlukem assert( buf != NULL );
9412de962bdSlukem
9422de962bdSlukem dst = buf;
943d11b170bStron buf = (char *) buf + sizeof( struct sockaddr_storage );
944d11b170bStron len -= sizeof( struct sockaddr_storage );
945376af7d7Schristos dstsize = dst->sa_family == AF_INET ? sizeof( struct sockaddr_in )
946376af7d7Schristos #ifdef LDAP_PF_INET6
947376af7d7Schristos : dst->sa_family == AF_INET6 ? sizeof( struct sockaddr_in6 )
948376af7d7Schristos #endif
949376af7d7Schristos : sizeof( struct sockaddr_storage );
950376af7d7Schristos rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, dstsize );
9512de962bdSlukem
9522de962bdSlukem if ( rc < 0 ) return -1;
9532de962bdSlukem
9542de962bdSlukem /* fake error if write was not atomic */
9552de962bdSlukem if (rc < len) {
9562de962bdSlukem # ifdef EMSGSIZE
9572de962bdSlukem errno = EMSGSIZE;
9582de962bdSlukem # endif
9592de962bdSlukem return -1;
9602de962bdSlukem }
961d11b170bStron rc = len + sizeof(struct sockaddr_storage);
9622de962bdSlukem return rc;
9632de962bdSlukem }
9642de962bdSlukem
9652de962bdSlukem static int
sb_dgram_close(Sockbuf_IO_Desc * sbiod)9662de962bdSlukem sb_dgram_close( Sockbuf_IO_Desc *sbiod )
9672de962bdSlukem {
9682de962bdSlukem assert( sbiod != NULL );
9692de962bdSlukem assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
9702de962bdSlukem
971d11b170bStron if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
9722de962bdSlukem tcp_close( sbiod->sbiod_sb->sb_fd );
9732de962bdSlukem return 0;
9742de962bdSlukem }
9752de962bdSlukem
9762de962bdSlukem static int
sb_dgram_ctrl(Sockbuf_IO_Desc * sbiod,int opt,void * arg)9772de962bdSlukem sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
9782de962bdSlukem {
9792de962bdSlukem /* This is an end IO descriptor */
9802de962bdSlukem return 0;
9812de962bdSlukem }
9822de962bdSlukem
9832de962bdSlukem Sockbuf_IO ber_sockbuf_io_udp =
9842de962bdSlukem {
9852de962bdSlukem sb_dgram_setup, /* sbi_setup */
9862de962bdSlukem NULL, /* sbi_remove */
9872de962bdSlukem sb_dgram_ctrl, /* sbi_ctrl */
9882de962bdSlukem sb_dgram_read, /* sbi_read */
9892de962bdSlukem sb_dgram_write, /* sbi_write */
9902de962bdSlukem sb_dgram_close /* sbi_close */
9912de962bdSlukem };
9922de962bdSlukem
9932de962bdSlukem #endif /* LDAP_CONNECTIONLESS */
994