Home | History | Annotate | Line # | Download | only in liblber
      1 /*	$NetBSD: sockbuf.c,v 1.4 2025/09/05 21:16:20 christos Exp $	*/
      2 
      3 /* sockbuf.c - i/o routines with support for adding i/o layers. */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 
     19 #include <sys/cdefs.h>
     20 __RCSID("$NetBSD: sockbuf.c,v 1.4 2025/09/05 21:16:20 christos Exp $");
     21 
     22 #include "portable.h"
     23 
     24 #include <stdio.h>
     25 
     26 #include <ac/stdlib.h>
     27 
     28 #include <ac/ctype.h>
     29 #include <ac/errno.h>
     30 #include <ac/socket.h>
     31 #include <ac/string.h>
     32 #include <ac/unistd.h>
     33 
     34 #ifdef HAVE_IO_H
     35 #include <io.h>
     36 #endif /* HAVE_IO_H */
     37 
     38 #if defined( HAVE_FCNTL_H )
     39 #include <fcntl.h>
     40 #endif
     41 
     42 #if defined( HAVE_SYS_FILIO_H )
     43 #include <sys/filio.h>
     44 #elif defined( HAVE_SYS_IOCTL_H )
     45 #include <sys/ioctl.h>
     46 #endif
     47 
     48 #include "lber-int.h"
     49 
     50 #ifndef LBER_MIN_BUFF_SIZE
     51 #define LBER_MIN_BUFF_SIZE		4096
     52 #endif
     53 #ifndef LBER_MAX_BUFF_SIZE
     54 #define LBER_MAX_BUFF_SIZE		(65536*256)
     55 #endif
     56 #ifndef LBER_DEFAULT_READAHEAD
     57 #define LBER_DEFAULT_READAHEAD	16384
     58 #endif
     59 
     60 Sockbuf *
     61 ber_sockbuf_alloc( void )
     62 {
     63 	Sockbuf			*sb;
     64 
     65 	sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
     66 
     67 	if( sb == NULL ) return NULL;
     68 
     69 	ber_int_sb_init( sb );
     70 	return sb;
     71 }
     72 
     73 void
     74 ber_sockbuf_free( Sockbuf *sb )
     75 {
     76 	assert( sb != NULL );
     77 	assert( SOCKBUF_VALID( sb ) );
     78 
     79 	ber_int_sb_close( sb );
     80 	ber_int_sb_destroy( sb );
     81 	LBER_FREE( sb );
     82 }
     83 
     84 /* Return values: -1: error, 0: no operation performed or the answer is false,
     85  * 1: successful operation or the answer is true
     86  */
     87 int
     88 ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
     89 {
     90 	Sockbuf_IO_Desc		*p;
     91 	int			ret = 0;
     92 
     93 	assert( sb != NULL );
     94 	assert( SOCKBUF_VALID( sb ) );
     95 
     96 	switch ( opt ) {
     97 		case LBER_SB_OPT_HAS_IO:
     98 			p = sb->sb_iod;
     99 			while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) {
    100 				p = p->sbiod_next;
    101 			}
    102 
    103 			if ( p ) {
    104 				ret = 1;
    105 			}
    106 			break;
    107 
    108 		case LBER_SB_OPT_GET_FD:
    109 			if ( arg != NULL ) {
    110 				*((ber_socket_t *)arg) = sb->sb_fd;
    111 			}
    112 			ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
    113 			break;
    114 
    115 		case LBER_SB_OPT_SET_FD:
    116 			sb->sb_fd = *((ber_socket_t *)arg);
    117 			ret = 1;
    118 			break;
    119 
    120 		case LBER_SB_OPT_SET_NONBLOCK:
    121 			ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
    122 				? -1 : 1;
    123 			break;
    124 
    125 		case LBER_SB_OPT_DRAIN: {
    126 				/* Drain the data source to enable possible errors (e.g.
    127 				 * TLS) to be propagated to the upper layers
    128 				 */
    129 				char buf[LBER_MIN_BUFF_SIZE];
    130 
    131 				do {
    132 					ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
    133 				} while ( ret == sizeof( buf ) );
    134 
    135 				ret = 1;
    136 			} break;
    137 
    138 		case LBER_SB_OPT_NEEDS_READ:
    139 			ret = ( sb->sb_trans_needs_read ? 1 : 0 );
    140 			break;
    141 
    142 		case LBER_SB_OPT_NEEDS_WRITE:
    143 			ret = ( sb->sb_trans_needs_write ? 1 : 0 );
    144 			break;
    145 
    146 		case LBER_SB_OPT_GET_MAX_INCOMING:
    147 			if ( arg != NULL ) {
    148 				*((ber_len_t *)arg) = sb->sb_max_incoming;
    149 			}
    150 			ret = 1;
    151 			break;
    152 
    153 		case LBER_SB_OPT_SET_MAX_INCOMING:
    154 			sb->sb_max_incoming = *((ber_len_t *)arg);
    155 			ret = 1;
    156 			break;
    157 
    158 		case LBER_SB_OPT_UNGET_BUF:
    159 #ifdef LDAP_PF_LOCAL_SENDMSG
    160 			sb->sb_ungetlen = ((struct berval *)arg)->bv_len;
    161 			if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) {
    162 				AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val,
    163 					sb->sb_ungetlen );
    164 				ret = 1;
    165 			} else {
    166 				sb->sb_ungetlen = 0;
    167 				ret = -1;
    168 			}
    169 #endif
    170 			break;
    171 
    172 		default:
    173 			ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg );
    174 			break;
    175    }
    176 
    177 	return ret;
    178 }
    179 
    180 int
    181 ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
    182 {
    183 	Sockbuf_IO_Desc		*d, *p, **q;
    184 
    185 	assert( sb != NULL );
    186 	assert( SOCKBUF_VALID( sb ) );
    187 
    188 	if ( sbio == NULL ) {
    189 		return -1;
    190 	}
    191 
    192 	q = &sb->sb_iod;
    193 	p = *q;
    194 	while ( p && p->sbiod_level > layer ) {
    195 		q = &p->sbiod_next;
    196 		p = *q;
    197 	}
    198 
    199 	d = LBER_MALLOC( sizeof( *d ) );
    200 	if ( d == NULL ) {
    201 		return -1;
    202 	}
    203 
    204 	d->sbiod_level = layer;
    205 	d->sbiod_sb = sb;
    206 	d->sbiod_io = sbio;
    207 	memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) );
    208 	d->sbiod_next = p;
    209 	*q = d;
    210 
    211 	if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
    212 		return -1;
    213 	}
    214 
    215 	return 0;
    216 }
    217 
    218 int
    219 ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
    220 {
    221 	Sockbuf_IO_Desc		*p, **q;
    222 
    223 	assert( sb != NULL );
    224 	assert( SOCKBUF_VALID( sb ) );
    225 
    226 	if ( sb->sb_iod == NULL ) {
    227 		return -1;
    228 	}
    229 
    230 	q = &sb->sb_iod;
    231 	while ( *q != NULL ) {
    232 		p = *q;
    233 		if ( layer == p->sbiod_level && p->sbiod_io == sbio ) {
    234 			if ( p->sbiod_io->sbi_remove != NULL &&
    235 				p->sbiod_io->sbi_remove( p ) < 0 )
    236 			{
    237 				return -1;
    238 			}
    239 			*q = p->sbiod_next;
    240 			LBER_FREE( p );
    241 			break;
    242 		}
    243 		q = &p->sbiod_next;
    244 	}
    245 
    246 	return 0;
    247 }
    248 
    249 void
    250 ber_pvt_sb_buf_init( Sockbuf_Buf *buf )
    251 {
    252 	buf->buf_base = NULL;
    253 	buf->buf_ptr = 0;
    254 	buf->buf_end = 0;
    255 	buf->buf_size = 0;
    256 }
    257 
    258 void
    259 ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
    260 {
    261 	assert( buf != NULL);
    262 
    263 	if (buf->buf_base) {
    264 		LBER_FREE( buf->buf_base );
    265 	}
    266 	ber_pvt_sb_buf_init( buf );
    267 }
    268 
    269 int
    270 ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
    271 {
    272 	ber_len_t		pw;
    273 	char			*p;
    274 
    275 	assert( buf != NULL );
    276 
    277 	for ( pw = LBER_MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
    278 		if (pw > LBER_MAX_BUFF_SIZE) return -1;
    279 	}
    280 
    281 	if ( buf->buf_size < pw ) {
    282 		p = LBER_REALLOC( buf->buf_base, pw );
    283 		if ( p == NULL ) return -1;
    284 		buf->buf_base = p;
    285 		buf->buf_size = pw;
    286 	}
    287 	return 0;
    288 }
    289 
    290 ber_len_t
    291 ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
    292 {
    293 	ber_len_t		max;
    294 
    295 	assert( buf != NULL );
    296 	assert( sbb != NULL );
    297 #if 0
    298 	assert( sbb->buf_size > 0 );
    299 #endif
    300 
    301 	max = sbb->buf_end - sbb->buf_ptr;
    302 	max = ( max < len) ? max : len;
    303 	if ( max ) {
    304 		AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
    305 		sbb->buf_ptr += max;
    306 		if ( sbb->buf_ptr >= sbb->buf_end ) {
    307 			sbb->buf_ptr = sbb->buf_end = 0;
    308 		}
    309    }
    310 	return max;
    311 }
    312 
    313 ber_slen_t
    314 ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
    315 {
    316 	ber_len_t		to_go;
    317 	ber_slen_t ret;
    318 
    319 	assert( sbiod != NULL );
    320 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    321 
    322 	to_go = buf_out->buf_end - buf_out->buf_ptr;
    323 	assert( to_go > 0 );
    324 
    325 	for(;;) {
    326 		ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
    327 			buf_out->buf_ptr, to_go );
    328 #ifdef EINTR
    329 		if ((ret<0) && (errno==EINTR)) continue;
    330 #endif
    331 		break;
    332 	}
    333 
    334 	if ( ret <= 0 ) return ret;
    335 
    336 	buf_out->buf_ptr += ret;
    337 	if (buf_out->buf_ptr == buf_out->buf_end) {
    338 		buf_out->buf_end = buf_out->buf_ptr = 0;
    339 	}
    340 
    341 	return ret;
    342 }
    343 
    344 int
    345 ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
    346 {
    347 #ifdef HAVE_FCNTL
    348 	int flags = fcntl( sd, F_GETFL);
    349 	if( nb ) {
    350 		flags |= O_NONBLOCK;
    351 	} else {
    352 		flags &= ~O_NONBLOCK;
    353 	}
    354 	return fcntl( sd, F_SETFL, flags );
    355 
    356 #elif defined( FIONBIO )
    357 	ioctl_t status = nb ? 1 : 0;
    358 	return ioctl( sd, FIONBIO, &status );
    359 #endif
    360 }
    361 
    362 int
    363 ber_int_sb_init( Sockbuf *sb )
    364 {
    365 	assert( sb != NULL);
    366 
    367 	sb->sb_valid=LBER_VALID_SOCKBUF;
    368 	sb->sb_options = 0;
    369 	sb->sb_debug = ber_int_debug;
    370 	sb->sb_fd = AC_SOCKET_INVALID;
    371 	sb->sb_iod = NULL;
    372 	sb->sb_trans_needs_read = 0;
    373 	sb->sb_trans_needs_write = 0;
    374 
    375 	assert( SOCKBUF_VALID( sb ) );
    376 	return 0;
    377 }
    378 
    379 int
    380 ber_int_sb_close( Sockbuf *sb )
    381 {
    382 	Sockbuf_IO_Desc		*p;
    383 
    384 	assert( sb != NULL);
    385 
    386 	p = sb->sb_iod;
    387 	while ( p ) {
    388 		if ( p->sbiod_io->sbi_close && p->sbiod_io->sbi_close( p ) < 0 ) {
    389 			return -1;
    390 		}
    391 		p = p->sbiod_next;
    392 	}
    393 
    394 	sb->sb_fd = AC_SOCKET_INVALID;
    395 
    396 	return 0;
    397 }
    398 
    399 int
    400 ber_int_sb_destroy( Sockbuf *sb )
    401 {
    402 	Sockbuf_IO_Desc		*p;
    403 
    404 	assert( sb != NULL);
    405 	assert( SOCKBUF_VALID( sb ) );
    406 
    407 	while ( sb->sb_iod ) {
    408 		p = sb->sb_iod->sbiod_next;
    409 		ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io,
    410 			sb->sb_iod->sbiod_level );
    411 		sb->sb_iod = p;
    412 	}
    413 
    414 	return ber_int_sb_init( sb );
    415 }
    416 
    417 ber_slen_t
    418 ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
    419 {
    420 	ber_slen_t		ret;
    421 
    422 	assert( buf != NULL );
    423 	assert( sb != NULL);
    424 	assert( sb->sb_iod != NULL );
    425 	assert( SOCKBUF_VALID( sb ) );
    426 
    427 	for (;;) {
    428 		ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
    429 
    430 #ifdef EINTR
    431 		if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
    432 #endif
    433 		break;
    434 	}
    435 
    436 	return ret;
    437 }
    438 
    439 ber_slen_t
    440 ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
    441 {
    442 	ber_slen_t		ret;
    443 
    444 	assert( buf != NULL );
    445 	assert( sb != NULL);
    446 	assert( sb->sb_iod != NULL );
    447 	assert( SOCKBUF_VALID( sb ) );
    448 
    449 	for (;;) {
    450 		ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
    451 
    452 #ifdef EINTR
    453 		if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
    454 #endif
    455 		break;
    456 	}
    457 
    458 	return ret;
    459 }
    460 
    461 /*
    462  * Support for TCP
    463  */
    464 
    465 static ber_slen_t
    466 sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    467 {
    468 	assert( sbiod != NULL);
    469 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    470 
    471 #if defined(MACOS)
    472 /*
    473  * MacTCP/OpenTransport
    474  */
    475 	return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
    476 		len, NULL );
    477 
    478 #elif defined( HAVE_PCNFS ) || \
    479    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
    480 /*
    481  * PCNFS (under DOS)
    482  */
    483 /*
    484  * Windows Socket API (under DOS/Windows 3.x)
    485  */
    486 /*
    487  * 32-bit Windows Socket API (under Windows NT or Windows 95)
    488  */
    489 	return recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
    490 
    491 #elif defined( HAVE_NCSA )
    492 /*
    493  * NCSA Telnet TCP/IP stack (under DOS)
    494  */
    495 	return nread( sbiod->sbiod_sb->sb_fd, buf, len );
    496 
    497 #else
    498 	return read( sbiod->sbiod_sb->sb_fd, buf, len );
    499 #endif
    500 }
    501 
    502 static ber_slen_t
    503 sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    504 {
    505 	assert( sbiod != NULL);
    506 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    507 
    508 #if defined(MACOS)
    509 /*
    510  * MacTCP/OpenTransport
    511  */
    512 #define MAX_WRITE	65535
    513 	return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
    514 		(len<MAX_WRITE) ? len : MAX_WRITE );
    515 
    516 #elif defined( HAVE_PCNFS) \
    517 	|| defined( HAVE_WINSOCK) || defined ( __BEOS__ )
    518 /*
    519  * PCNFS (under DOS)
    520  */
    521 /*
    522  * Windows Socket API (under DOS/Windows 3.x)
    523  */
    524 /*
    525  * 32-bit Windows Socket API (under Windows NT or Windows 95)
    526  */
    527 	return send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
    528 
    529 #elif defined(HAVE_NCSA)
    530 	return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
    531 
    532 #elif defined(VMS)
    533 /*
    534  * VMS -- each write must be 64K or smaller
    535  */
    536 #define MAX_WRITE 65535
    537 	return write( sbiod->sbiod_sb->sb_fd, buf,
    538 		(len<MAX_WRITE) ? len : MAX_WRITE);
    539 #else
    540 	return write( sbiod->sbiod_sb->sb_fd, buf, len );
    541 #endif
    542 }
    543 
    544 static int
    545 sb_stream_close( Sockbuf_IO_Desc *sbiod )
    546 {
    547 	assert( sbiod != NULL );
    548 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    549 	if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
    550 		tcp_close( sbiod->sbiod_sb->sb_fd );
    551    return 0;
    552 }
    553 
    554 /* The argument is a pointer to the socket descriptor */
    555 static int
    556 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
    557 	assert( sbiod != NULL );
    558 
    559 	if ( arg != NULL ) {
    560 		sbiod->sbiod_sb->sb_fd = *((int *)arg);
    561 	}
    562 	return 0;
    563 }
    564 
    565 static int
    566 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
    567 	/* This is an end IO descriptor */
    568 	return 0;
    569 }
    570 
    571 Sockbuf_IO ber_sockbuf_io_tcp = {
    572 	sb_stream_setup,	/* sbi_setup */
    573 	NULL,				/* sbi_remove */
    574 	sb_stream_ctrl,		/* sbi_ctrl */
    575 	sb_stream_read,		/* sbi_read */
    576 	sb_stream_write,	/* sbi_write */
    577 	sb_stream_close		/* sbi_close */
    578 };
    579 
    580 
    581 /*
    582  * Support for readahead (UDP needs it)
    583  */
    584 
    585 static int
    586 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
    587 {
    588 	Sockbuf_Buf		*p;
    589 
    590 	assert( sbiod != NULL );
    591 
    592 	p = LBER_MALLOC( sizeof( *p ) );
    593 	if ( p == NULL ) return -1;
    594 
    595 	ber_pvt_sb_buf_init( p );
    596 
    597 	if ( arg == NULL ) {
    598 		ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD );
    599 	} else {
    600 		ber_pvt_sb_grow_buffer( p, *((int *)arg) );
    601 	}
    602 
    603 	sbiod->sbiod_pvt = p;
    604 	return 0;
    605 }
    606 
    607 static int
    608 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
    609 {
    610 	Sockbuf_Buf		*p;
    611 
    612 	assert( sbiod != NULL );
    613 
    614 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
    615 
    616 	if ( p->buf_ptr != p->buf_end ) return -1;
    617 
    618 	ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
    619 	LBER_FREE( sbiod->sbiod_pvt );
    620 	sbiod->sbiod_pvt = NULL;
    621 
    622 	return 0;
    623 }
    624 
    625 static ber_slen_t
    626 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    627 {
    628 	Sockbuf_Buf		*p;
    629 	ber_slen_t		bufptr = 0, ret, max;
    630 
    631 	assert( sbiod != NULL );
    632 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    633 	assert( sbiod->sbiod_next != NULL );
    634 
    635 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
    636 
    637 	assert( p->buf_size > 0 );
    638 
    639 	/* Are there anything left in the buffer? */
    640 	ret = ber_pvt_sb_copy_out( p, buf, len );
    641 	bufptr += ret;
    642 	len -= ret;
    643 
    644 	if ( len == 0 ) return bufptr;
    645 
    646 	max = p->buf_size - p->buf_end;
    647 	ret = 0;
    648 	while ( max > 0 ) {
    649 		ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
    650 			max );
    651 #ifdef EINTR
    652 		if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
    653 #endif
    654 		break;
    655 	}
    656 
    657 	if ( ret < 0 ) {
    658 		return ( bufptr ? bufptr : ret );
    659 	}
    660 
    661 	p->buf_end += ret;
    662 	bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
    663 	return bufptr;
    664 }
    665 
    666 static ber_slen_t
    667 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    668 {
    669 	assert( sbiod != NULL );
    670 	assert( sbiod->sbiod_next != NULL );
    671 
    672 	return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
    673 }
    674 
    675 static int
    676 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
    677 {
    678 	assert( sbiod != NULL );
    679 
    680 	/* Just erase the buffer */
    681 	ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
    682 	return 0;
    683 }
    684 
    685 static int
    686 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
    687 {
    688 	Sockbuf_Buf		*p;
    689 
    690 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
    691 
    692 	if ( opt == LBER_SB_OPT_DATA_READY ) {
    693 		if ( p->buf_ptr != p->buf_end ) {
    694 			return 1;
    695 		}
    696 
    697 	} else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
    698 		if ( p->buf_size >= *((ber_len_t *)arg) ) {
    699 			return 0;
    700 		}
    701 		return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
    702 			-1 : 1 );
    703 	}
    704 
    705 	return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
    706 }
    707 
    708 Sockbuf_IO ber_sockbuf_io_readahead = {
    709 	sb_rdahead_setup,	/* sbi_setup */
    710 	sb_rdahead_remove,	/* sbi_remove */
    711 	sb_rdahead_ctrl,	/* sbi_ctrl */
    712 	sb_rdahead_read,	/* sbi_read */
    713 	sb_rdahead_write,	/* sbi_write */
    714 	sb_rdahead_close	/* sbi_close */
    715 };
    716 
    717 /*
    718  * Support for simple file IO
    719  */
    720 
    721 static ber_slen_t
    722 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    723 {
    724 	assert( sbiod != NULL);
    725 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    726 
    727 #ifdef LDAP_PF_LOCAL_SENDMSG
    728 	if ( sbiod->sbiod_sb->sb_ungetlen ) {
    729 		ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen;
    730 		if ( blen > len )
    731 			blen = len;
    732 		AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen );
    733 		buf = (char *) buf + blen;
    734 		len -= blen;
    735 		sbiod->sbiod_sb->sb_ungetlen -= blen;
    736 		if ( sbiod->sbiod_sb->sb_ungetlen ) {
    737 			AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf,
    738 				sbiod->sbiod_sb->sb_ungetbuf+blen,
    739 				sbiod->sbiod_sb->sb_ungetlen );
    740 		}
    741 		if ( len == 0 )
    742 			return blen;
    743 	}
    744 #endif
    745 	return read( sbiod->sbiod_sb->sb_fd, buf, len );
    746 }
    747 
    748 static ber_slen_t
    749 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    750 {
    751 	assert( sbiod != NULL);
    752 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    753 
    754 	return write( sbiod->sbiod_sb->sb_fd, buf, len );
    755 }
    756 
    757 static int
    758 sb_fd_close( Sockbuf_IO_Desc *sbiod )
    759 {
    760 	assert( sbiod != NULL );
    761 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    762 
    763 	if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
    764 		close( sbiod->sbiod_sb->sb_fd );
    765 	return 0;
    766 }
    767 
    768 /* The argument is a pointer to the file descriptor */
    769 static int
    770 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
    771 	assert( sbiod != NULL );
    772 
    773 	if ( arg != NULL )
    774 		sbiod->sbiod_sb->sb_fd = *((int *)arg);
    775 	return 0;
    776 }
    777 
    778 static int
    779 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
    780 	/* This is an end IO descriptor */
    781 	return 0;
    782 }
    783 
    784 Sockbuf_IO ber_sockbuf_io_fd = {
    785 	sb_fd_setup,	/* sbi_setup */
    786 	NULL,			/* sbi_remove */
    787 	sb_fd_ctrl,		/* sbi_ctrl */
    788 	sb_fd_read,		/* sbi_read */
    789 	sb_fd_write,		/* sbi_write */
    790 	sb_fd_close		/* sbi_close */
    791 };
    792 
    793 /*
    794  * Debugging layer
    795  */
    796 
    797 static int
    798 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
    799 {
    800 	assert( sbiod != NULL );
    801 
    802 	if ( arg == NULL ) arg = "sockbuf_";
    803 
    804 	sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
    805 	if ( sbiod->sbiod_pvt == NULL ) return -1;
    806 
    807 	strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
    808 	return 0;
    809 }
    810 
    811 static int
    812 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
    813 {
    814 	assert( sbiod != NULL );
    815 	assert( sbiod->sbiod_pvt != NULL );
    816 
    817 	LBER_FREE( sbiod->sbiod_pvt );
    818 	sbiod->sbiod_pvt = NULL;
    819 	return 0;
    820 }
    821 
    822 static int
    823 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
    824 {
    825 	return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
    826 }
    827 
    828 static ber_slen_t
    829 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    830 {
    831 	ber_slen_t		ret;
    832 	char ebuf[128];
    833 
    834 	ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
    835 	if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
    836 		int err = sock_errno();
    837 		if ( ret < 0 ) {
    838 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    839 				"%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
    840 				(long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
    841 		} else {
    842 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    843 				"%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
    844 				(long)len, (long)ret );
    845 			ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    846 				(const char *)buf, ret );
    847 		}
    848 		sock_errset(err);
    849 	}
    850 	return ret;
    851 }
    852 
    853 static ber_slen_t
    854 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    855 {
    856 	ber_slen_t		ret;
    857 	char ebuf[128];
    858 
    859 	ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
    860 	if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
    861 		int err = sock_errno();
    862 		if ( ret < 0 ) {
    863 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    864 				"%swrite: want=%ld error=%s\n",
    865 				(char *)sbiod->sbiod_pvt, (long)len,
    866 				AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
    867 		} else {
    868 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    869 				"%swrite: want=%ld, written=%ld\n",
    870 				(char *)sbiod->sbiod_pvt, (long)len, (long)ret );
    871 			ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
    872 				(const char *)buf, ret );
    873 		}
    874 		sock_errset(err);
    875 	}
    876 
    877 	return ret;
    878 }
    879 
    880 Sockbuf_IO ber_sockbuf_io_debug = {
    881 	sb_debug_setup,		/* sbi_setup */
    882 	sb_debug_remove,	/* sbi_remove */
    883 	sb_debug_ctrl,		/* sbi_ctrl */
    884 	sb_debug_read,		/* sbi_read */
    885 	sb_debug_write,		/* sbi_write */
    886 	NULL				/* sbi_close */
    887 };
    888 
    889 #ifdef LDAP_CONNECTIONLESS
    890 
    891 /*
    892  * Support for UDP (CLDAP)
    893  *
    894  * All I/O at this level must be atomic. For ease of use, the sb_readahead
    895  * must be used above this module. All data reads and writes are prefixed
    896  * with a sockaddr_storage containing the address of the remote entity. Upper levels
    897  * must read and write this sockaddr_storage before doing the usual ber_printf/scanf
    898  * operations on LDAP messages.
    899  */
    900 
    901 static int
    902 sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
    903 {
    904 	assert( sbiod != NULL);
    905 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    906 
    907 	if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg);
    908 	return 0;
    909 }
    910 
    911 static ber_slen_t
    912 sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    913 {
    914 	ber_slen_t rc;
    915 	ber_socklen_t addrlen;
    916 	struct sockaddr *src;
    917 
    918 	assert( sbiod != NULL );
    919 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    920 	assert( buf != NULL );
    921 
    922 	addrlen = sizeof( struct sockaddr_storage );
    923 	src = buf;
    924 	buf = (char *) buf + addrlen;
    925 	len -= addrlen;
    926 	rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen );
    927 
    928 	return rc > 0 ? rc+sizeof(struct sockaddr_storage) : rc;
    929 }
    930 
    931 static ber_slen_t
    932 sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
    933 {
    934 	ber_slen_t rc;
    935 	struct sockaddr *dst;
    936 	socklen_t dstsize;
    937 
    938 	assert( sbiod != NULL );
    939 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    940 	assert( buf != NULL );
    941 
    942 	dst = buf;
    943 	buf = (char *) buf + sizeof( struct sockaddr_storage );
    944 	len -= sizeof( struct sockaddr_storage );
    945 	dstsize = dst->sa_family == AF_INET ? sizeof( struct sockaddr_in )
    946 #ifdef LDAP_PF_INET6
    947 		: dst->sa_family == AF_INET6 ? sizeof( struct sockaddr_in6 )
    948 #endif
    949 		: sizeof( struct sockaddr_storage );
    950 	rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, dstsize );
    951 
    952 	if ( rc < 0 ) return -1;
    953 
    954 	/* fake error if write was not atomic */
    955 	if (rc < len) {
    956 # ifdef EMSGSIZE
    957 		errno = EMSGSIZE;
    958 # endif
    959 		return -1;
    960 	}
    961 	rc = len + sizeof(struct sockaddr_storage);
    962 	return rc;
    963 }
    964 
    965 static int
    966 sb_dgram_close( Sockbuf_IO_Desc *sbiod )
    967 {
    968 	assert( sbiod != NULL );
    969 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
    970 
    971 	if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID )
    972 		tcp_close( sbiod->sbiod_sb->sb_fd );
    973 	return 0;
    974 }
    975 
    976 static int
    977 sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
    978 {
    979 	/* This is an end IO descriptor */
    980 	return 0;
    981 }
    982 
    983 Sockbuf_IO ber_sockbuf_io_udp =
    984 {
    985 	sb_dgram_setup,		/* sbi_setup */
    986 	NULL,			/* sbi_remove */
    987 	sb_dgram_ctrl,		/* sbi_ctrl */
    988 	sb_dgram_read,		/* sbi_read */
    989 	sb_dgram_write,		/* sbi_write */
    990 	sb_dgram_close		/* sbi_close */
    991 };
    992 
    993 #endif	/* LDAP_CONNECTIONLESS */
    994