xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblber/sockbuf.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /* sockbuf.c - i/o routines with support for adding i/o layers. */
2 /* $OpenLDAP: pkg/ldap/libraries/liblber/sockbuf.c,v 1.65.2.4 2008/02/11 23:26:41 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 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 
55 Sockbuf *
56 ber_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 
68 void
69 ber_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  */
82 int
83 ber_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 
175 int
176 ber_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 
213 int
214 ber_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 
244 void
245 ber_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 
253 void
254 ber_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 
264 int
265 ber_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 
285 ber_len_t
286 ber_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 
308 ber_slen_t
309 ber_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 
339 int
340 ber_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 
357 int
358 ber_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 
374 int
375 ber_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 
394 int
395 ber_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 
412 ber_slen_t
413 ber_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 
434 ber_slen_t
435 ber_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 
460 static ber_slen_t
461 sb_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 
497 static ber_slen_t
498 sb_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 
539 static int
540 sb_stream_close( Sockbuf_IO_Desc *sbiod )
541 {
542 	assert( sbiod != NULL );
543 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
544 	tcp_close( sbiod->sbiod_sb->sb_fd );
545    return 0;
546 }
547 
548 /* The argument is a pointer to the socket descriptor */
549 static int
550 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
551 	assert( sbiod != NULL );
552 
553 	if ( arg != NULL ) {
554 		sbiod->sbiod_sb->sb_fd = *((int *)arg);
555 	}
556 	return 0;
557 }
558 
559 static int
560 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
561 	/* This is an end IO descriptor */
562 	return 0;
563 }
564 
565 Sockbuf_IO ber_sockbuf_io_tcp = {
566 	sb_stream_setup,	/* sbi_setup */
567 	NULL,				/* sbi_remove */
568 	sb_stream_ctrl,		/* sbi_ctrl */
569 	sb_stream_read,		/* sbi_read */
570 	sb_stream_write,	/* sbi_write */
571 	sb_stream_close		/* sbi_close */
572 };
573 
574 
575 /*
576  * Support for readahead (UDP needs it)
577  */
578 
579 static int
580 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
581 {
582 	Sockbuf_Buf		*p;
583 
584 	assert( sbiod != NULL );
585 
586 	p = LBER_MALLOC( sizeof( *p ) );
587 	if ( p == NULL ) return -1;
588 
589 	ber_pvt_sb_buf_init( p );
590 
591 	if ( arg == NULL ) {
592 		ber_pvt_sb_grow_buffer( p, LBER_DEFAULT_READAHEAD );
593 	} else {
594 		ber_pvt_sb_grow_buffer( p, *((int *)arg) );
595 	}
596 
597 	sbiod->sbiod_pvt = p;
598 	return 0;
599 }
600 
601 static int
602 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
603 {
604 	Sockbuf_Buf		*p;
605 
606 	assert( sbiod != NULL );
607 
608 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
609 
610 	if ( p->buf_ptr != p->buf_end ) return -1;
611 
612 	ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
613 	LBER_FREE( sbiod->sbiod_pvt );
614 	sbiod->sbiod_pvt = NULL;
615 
616 	return 0;
617 }
618 
619 static ber_slen_t
620 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
621 {
622 	Sockbuf_Buf		*p;
623 	ber_slen_t		bufptr = 0, ret, max;
624 
625 	assert( sbiod != NULL );
626 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
627 	assert( sbiod->sbiod_next != NULL );
628 
629 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
630 
631 	assert( p->buf_size > 0 );
632 
633 	/* Are there anything left in the buffer? */
634 	ret = ber_pvt_sb_copy_out( p, buf, len );
635 	bufptr += ret;
636 	len -= ret;
637 
638 	if ( len == 0 ) return bufptr;
639 
640 	max = p->buf_size - p->buf_end;
641 	ret = 0;
642 	while ( max > 0 ) {
643 		ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
644 			max );
645 #ifdef EINTR
646 		if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
647 #endif
648 		break;
649 	}
650 
651 	if ( ret < 0 ) {
652 		return ( bufptr ? bufptr : ret );
653 	}
654 
655 	p->buf_end += ret;
656 	bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
657 	return bufptr;
658 }
659 
660 static ber_slen_t
661 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
662 {
663 	assert( sbiod != NULL );
664 	assert( sbiod->sbiod_next != NULL );
665 
666 	return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
667 }
668 
669 static int
670 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
671 {
672 	assert( sbiod != NULL );
673 
674 	/* Just erase the buffer */
675 	ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
676 	return 0;
677 }
678 
679 static int
680 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
681 {
682 	Sockbuf_Buf		*p;
683 
684 	p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
685 
686 	if ( opt == LBER_SB_OPT_DATA_READY ) {
687 		if ( p->buf_ptr != p->buf_end ) {
688 			return 1;
689 		}
690 
691 	} else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
692 		if ( p->buf_size >= *((ber_len_t *)arg) ) {
693 			return 0;
694 		}
695 		return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
696 			-1 : 1 );
697 	}
698 
699 	return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
700 }
701 
702 Sockbuf_IO ber_sockbuf_io_readahead = {
703 	sb_rdahead_setup,	/* sbi_setup */
704 	sb_rdahead_remove,	/* sbi_remove */
705 	sb_rdahead_ctrl,	/* sbi_ctrl */
706 	sb_rdahead_read,	/* sbi_read */
707 	sb_rdahead_write,	/* sbi_write */
708 	sb_rdahead_close	/* sbi_close */
709 };
710 
711 /*
712  * Support for simple file IO
713  */
714 
715 static ber_slen_t
716 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
717 {
718 	assert( sbiod != NULL);
719 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
720 
721 #ifdef LDAP_PF_LOCAL_SENDMSG
722 	if ( sbiod->sbiod_sb->sb_ungetlen ) {
723 		ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen;
724 		if ( blen > len )
725 			blen = len;
726 		AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen );
727 		buf = (char *) buf + blen;
728 		len -= blen;
729 		sbiod->sbiod_sb->sb_ungetlen -= blen;
730 		if ( sbiod->sbiod_sb->sb_ungetlen ) {
731 			AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf,
732 				sbiod->sbiod_sb->sb_ungetbuf+blen,
733 				sbiod->sbiod_sb->sb_ungetlen );
734 		}
735 		if ( len == 0 )
736 			return blen;
737 	}
738 #endif
739 	return read( sbiod->sbiod_sb->sb_fd, buf, len );
740 }
741 
742 static ber_slen_t
743 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
744 {
745 	assert( sbiod != NULL);
746 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
747 
748 	return write( sbiod->sbiod_sb->sb_fd, buf, len );
749 }
750 
751 static int
752 sb_fd_close( Sockbuf_IO_Desc *sbiod )
753 {
754 	assert( sbiod != NULL );
755 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
756 
757 	close( sbiod->sbiod_sb->sb_fd );
758 	return 0;
759 }
760 
761 /* The argument is a pointer to the file descriptor */
762 static int
763 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
764 	assert( sbiod != NULL );
765 
766 	if ( arg != NULL )
767 		sbiod->sbiod_sb->sb_fd = *((int *)arg);
768 	return 0;
769 }
770 
771 static int
772 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
773 	/* This is an end IO descriptor */
774 	return 0;
775 }
776 
777 Sockbuf_IO ber_sockbuf_io_fd = {
778 	sb_fd_setup,	/* sbi_setup */
779 	NULL,			/* sbi_remove */
780 	sb_fd_ctrl,		/* sbi_ctrl */
781 	sb_fd_read,		/* sbi_read */
782 	sb_fd_write,		/* sbi_write */
783 	sb_fd_close		/* sbi_close */
784 };
785 
786 /*
787  * Debugging layer
788  */
789 
790 static int
791 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
792 {
793 	assert( sbiod != NULL );
794 
795 	if ( arg == NULL ) arg = "sockbuf_";
796 
797 	sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
798 	if ( sbiod->sbiod_pvt == NULL ) return -1;
799 
800 	strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
801 	return 0;
802 }
803 
804 static int
805 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
806 {
807 	assert( sbiod != NULL );
808 	assert( sbiod->sbiod_pvt != NULL );
809 
810 	LBER_FREE( sbiod->sbiod_pvt );
811 	sbiod->sbiod_pvt = NULL;
812 	return 0;
813 }
814 
815 static int
816 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
817 {
818 	return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
819 }
820 
821 static ber_slen_t
822 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
823 {
824 	ber_slen_t		ret;
825 	char ebuf[128];
826 
827 	ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
828 	if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
829 		int err = sock_errno();
830 		if ( ret < 0 ) {
831 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
832 				"%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
833 				(long)len, AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
834 		} else {
835 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
836 				"%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
837 				(long)len, (long)ret );
838 			ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
839 				(const char *)buf, ret );
840 		}
841 		sock_errset(err);
842 	}
843 	return ret;
844 }
845 
846 static ber_slen_t
847 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
848 {
849 	ber_slen_t		ret;
850 	char ebuf[128];
851 
852 	ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
853 	if (sbiod->sbiod_sb->sb_debug & LDAP_DEBUG_PACKETS) {
854 		int err = sock_errno();
855 		if ( ret < 0 ) {
856 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
857 				"%swrite: want=%ld error=%s\n",
858 				(char *)sbiod->sbiod_pvt, (long)len,
859 				AC_STRERROR_R( err, ebuf, sizeof ebuf ) );
860 		} else {
861 			ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
862 				"%swrite: want=%ld, written=%ld\n",
863 				(char *)sbiod->sbiod_pvt, (long)len, (long)ret );
864 			ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
865 				(const char *)buf, ret );
866 		}
867 		sock_errset(err);
868 	}
869 
870 	return ret;
871 }
872 
873 Sockbuf_IO ber_sockbuf_io_debug = {
874 	sb_debug_setup,		/* sbi_setup */
875 	sb_debug_remove,	/* sbi_remove */
876 	sb_debug_ctrl,		/* sbi_ctrl */
877 	sb_debug_read,		/* sbi_read */
878 	sb_debug_write,		/* sbi_write */
879 	NULL				/* sbi_close */
880 };
881 
882 #ifdef LDAP_CONNECTIONLESS
883 
884 /*
885  * Support for UDP (CLDAP)
886  *
887  * All I/O at this level must be atomic. For ease of use, the sb_readahead
888  * must be used above this module. All data reads and writes are prefixed
889  * with a sockaddr containing the address of the remote entity. Upper levels
890  * must read and write this sockaddr before doing the usual ber_printf/scanf
891  * operations on LDAP messages.
892  */
893 
894 static int
895 sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
896 {
897 	assert( sbiod != NULL);
898 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
899 
900 	if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg);
901 	return 0;
902 }
903 
904 static ber_slen_t
905 sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
906 {
907 	ber_slen_t rc;
908 	ber_socklen_t addrlen;
909 	struct sockaddr *src;
910 
911 	assert( sbiod != NULL );
912 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
913 	assert( buf != NULL );
914 
915 	addrlen = sizeof( struct sockaddr );
916 	src = buf;
917 	buf = (char *) buf + addrlen;
918 	len -= addrlen;
919 	rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen );
920 
921 	return rc > 0 ? rc+sizeof(struct sockaddr) : rc;
922 }
923 
924 static ber_slen_t
925 sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
926 {
927 	ber_slen_t rc;
928 	struct sockaddr *dst;
929 
930 	assert( sbiod != NULL );
931 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
932 	assert( buf != NULL );
933 
934 	dst = buf;
935 	buf = (char *) buf + sizeof( struct sockaddr );
936 	len -= sizeof( struct sockaddr );
937 
938 	rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst,
939 		sizeof( struct sockaddr ) );
940 
941 	if ( rc < 0 ) return -1;
942 
943 	/* fake error if write was not atomic */
944 	if (rc < len) {
945 # ifdef EMSGSIZE
946 		errno = EMSGSIZE;
947 # endif
948 		return -1;
949 	}
950 	rc = len + sizeof(struct sockaddr);
951 	return rc;
952 }
953 
954 static int
955 sb_dgram_close( Sockbuf_IO_Desc *sbiod )
956 {
957 	assert( sbiod != NULL );
958 	assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
959 
960 	tcp_close( sbiod->sbiod_sb->sb_fd );
961 	return 0;
962 }
963 
964 static int
965 sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
966 {
967 	/* This is an end IO descriptor */
968 	return 0;
969 }
970 
971 Sockbuf_IO ber_sockbuf_io_udp =
972 {
973 	sb_dgram_setup,		/* sbi_setup */
974 	NULL,			/* sbi_remove */
975 	sb_dgram_ctrl,		/* sbi_ctrl */
976 	sb_dgram_read,		/* sbi_read */
977 	sb_dgram_write,		/* sbi_write */
978 	sb_dgram_close		/* sbi_close */
979 };
980 
981 #endif	/* LDAP_CONNECTIONLESS */
982