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