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