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