xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblber/sockbuf.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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 
57 Sockbuf *
58 ber_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 
70 void
71 ber_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  */
84 int
85 ber_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 
177 int
178 ber_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 
215 int
216 ber_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 
246 void
247 ber_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 
255 void
256 ber_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 
266 int
267 ber_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 
287 ber_len_t
288 ber_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 
310 ber_slen_t
311 ber_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 
341 int
342 ber_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 
359 int
360 ber_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 
376 int
377 ber_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 
396 int
397 ber_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 
414 ber_slen_t
415 ber_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 
436 ber_slen_t
437 ber_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 
462 static ber_slen_t
463 sb_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 
499 static ber_slen_t
500 sb_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 
541 static int
542 sb_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 */
552 static int
553 sb_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 
562 static int
563 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
564 	/* This is an end IO descriptor */
565 	return 0;
566 }
567 
568 Sockbuf_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 
582 static int
583 sb_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 
604 static int
605 sb_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 
622 static ber_slen_t
623 sb_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 
663 static ber_slen_t
664 sb_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 
672 static int
673 sb_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 
682 static int
683 sb_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 
705 Sockbuf_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 
718 static ber_slen_t
719 sb_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 
745 static ber_slen_t
746 sb_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 
754 static int
755 sb_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 */
766 static int
767 sb_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 
775 static int
776 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
777 	/* This is an end IO descriptor */
778 	return 0;
779 }
780 
781 Sockbuf_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 
794 static int
795 sb_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 
808 static int
809 sb_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 
819 static int
820 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
821 {
822 	return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
823 }
824 
825 static ber_slen_t
826 sb_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 
850 static ber_slen_t
851 sb_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 
877 Sockbuf_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 
898 static int
899 sb_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 
908 static ber_slen_t
909 sb_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 
928 static ber_slen_t
929 sb_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 
958 static int
959 sb_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 
969 static int
970 sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
971 {
972 	/* This is an end IO descriptor */
973 	return 0;
974 }
975 
976 Sockbuf_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