]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
More contrib cleanout
[openldap] / libraries / liblber / sockbuf.c
1 /* sockbuf.c - i/o routines with support for adding i/o layers. */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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 #define MIN_BUFF_SIZE           4096
37 #define MAX_BUFF_SIZE           65536
38 #define DEFAULT_READAHEAD       16384
39
40 Sockbuf *
41 ber_sockbuf_alloc( void )
42 {
43         Sockbuf                 *sb;
44
45         ber_int_options.lbo_valid = LBER_INITIALIZED;
46
47         sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
48
49         if( sb == NULL ) return NULL;
50
51         ber_int_sb_init( sb );
52         return sb;
53 }
54
55 void
56 ber_sockbuf_free( Sockbuf *sb )
57 {
58         assert( sb != NULL );
59         assert( SOCKBUF_VALID( sb ) );
60
61         ber_int_sb_close( sb );
62         ber_int_sb_destroy( sb );
63         LBER_FREE( sb );
64 }
65
66 /* Return values: -1: error, 0: no operation performed or the answer is false,
67  * 1: successful operation or the answer is true
68  */
69 int
70 ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
71 {
72         Sockbuf_IO_Desc         *p;
73         int                     ret = 0;
74
75         assert( sb != NULL );
76         assert( SOCKBUF_VALID( sb ) );
77
78         switch ( opt ) {
79                 case LBER_SB_OPT_HAS_IO:
80                         p = sb->sb_iod;
81                         while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) {
82                                 p = p->sbiod_next;
83                         }
84    
85                         if ( p ) {
86                                 ret = 1;
87                         }
88                         break;
89
90                 case LBER_SB_OPT_GET_FD:
91                         if ( arg != NULL ) {
92                                 *((int *)arg) = sb->sb_fd;
93                         }
94                         ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
95                         break;
96
97                 case LBER_SB_OPT_SET_FD:
98                         sb->sb_fd = *((int *)arg);
99                         ret = 1;
100                         break;
101
102                 case LBER_SB_OPT_SET_NONBLOCK:
103                         ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
104                                 ? -1 : 1;
105                         break;
106
107                 case LBER_SB_OPT_DRAIN: {
108                                 /* Drain the data source to enable possible errors (e.g.
109                                  * TLS) to be propagated to the upper layers
110                                  */
111                                 char buf[MIN_BUFF_SIZE];
112
113                                 do {
114                                         ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
115                                 } while ( ret == sizeof( buf ) );
116
117                                 ret = 1;
118                         } break;
119
120                 case LBER_SB_OPT_NEEDS_READ:
121                         ret = ( sb->sb_trans_needs_read ? 1 : 0 );
122                         break;
123
124                 case LBER_SB_OPT_NEEDS_WRITE:
125                         ret = ( sb->sb_trans_needs_write ? 1 : 0 );
126                         break;
127
128                 case LBER_SB_OPT_GET_MAX_INCOMING:
129                         if ( arg != NULL ) {
130                                 *((ber_len_t *)arg) = sb->sb_max_incoming;
131                         }
132                         ret = 1;
133                         break;
134
135                 case LBER_SB_OPT_SET_MAX_INCOMING:
136                         sb->sb_max_incoming = *((ber_len_t *)arg);
137                         ret = 1;
138                         break;
139
140                 default:
141                         ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod,
142                                 opt, arg );
143                         break;
144    }
145
146         return ret;
147 }
148
149 int
150 ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
151 {
152         Sockbuf_IO_Desc         *d, *p, **q;
153    
154         assert( sb != NULL );
155         assert( SOCKBUF_VALID( sb ) );
156    
157         if ( sbio == NULL ) {
158                 return -1;
159         }
160    
161         q = &sb->sb_iod;
162         p = *q;
163         while ( p && p->sbiod_level > layer ) {
164                 q = &p->sbiod_next;
165                 p = *q;
166         }
167    
168         d = LBER_MALLOC( sizeof( *d ) );
169         if ( d == NULL ) {
170                 return -1;
171         }
172    
173         d->sbiod_level = layer;
174         d->sbiod_sb = sb;
175         d->sbiod_io = sbio;
176         memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) );
177         d->sbiod_next = p;
178         *q = d;
179       
180         if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
181                 return -1;
182         }
183       
184         return 0;
185 }
186    
187 int
188 ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
189 {
190         Sockbuf_IO_Desc         *p, **q;
191
192         assert( sb != NULL );
193         assert( SOCKBUF_VALID( sb ) );
194    
195         if ( sb->sb_iod == NULL ) {
196                 return -1;
197         }
198    
199         q = &sb->sb_iod;
200         while ( *q != NULL ) {
201                 p = *q;
202                 if ( layer == p->sbiod_level && p->sbiod_io == sbio ) {
203                         if ( p->sbiod_io->sbi_remove != NULL &&
204                                 p->sbiod_io->sbi_remove( p ) < 0 )
205                         {
206                                 return -1;
207                         }
208                         *q = p->sbiod_next;
209                         LBER_FREE( p );
210                 break;
211                 }
212                 q = &p->sbiod_next;
213         }
214
215         return 0;
216 }
217
218 void
219 ber_pvt_sb_buf_init( Sockbuf_Buf *buf )
220 {
221         buf->buf_base = NULL;
222         buf->buf_ptr = 0;
223         buf->buf_end = 0;
224         buf->buf_size = 0;
225 }
226
227 void
228 ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
229 {
230         assert( buf != NULL);
231
232         if (buf->buf_base) {
233                 LBER_FREE( buf->buf_base );
234         }
235         ber_pvt_sb_buf_init( buf );
236 }
237
238 int
239 ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
240 {
241         ber_len_t               pw;
242         char                    *p;
243    
244         assert( buf != NULL );
245
246         for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
247                 if (pw > MAX_BUFF_SIZE) return -1;
248         }
249
250         if ( buf->buf_size < pw ) {
251                 p = LBER_REALLOC( buf->buf_base, pw );
252                 if ( p == NULL ) return -1;
253                 buf->buf_base = p;
254                 buf->buf_size = pw;
255         }
256         return 0;
257 }
258
259 ber_len_t
260 ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
261 {
262         ber_len_t               max;
263
264         assert( buf != NULL );
265         assert( sbb != NULL );
266 #if 0
267         assert( sbb->buf_size > 0 );
268 #endif
269
270         max = sbb->buf_end - sbb->buf_ptr;
271         max = ( max < len) ? max : len;
272         if ( max ) {
273                 AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
274                 sbb->buf_ptr += max;
275                 if ( sbb->buf_ptr >= sbb->buf_end ) {
276                         sbb->buf_ptr = sbb->buf_end = 0;
277                 }
278    }
279         return max;
280 }
281
282 ber_slen_t
283 ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
284 {
285         ber_len_t               to_go;
286         ber_slen_t ret;
287
288         assert( sbiod != NULL );
289         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
290
291         to_go = buf_out->buf_end - buf_out->buf_ptr;
292         assert( to_go > 0 );
293    
294         for(;;) {
295                 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
296                         buf_out->buf_ptr, to_go );
297 #ifdef EINTR
298                 if ((ret<0) && (errno==EINTR)) continue;
299 #endif
300                 break;
301         }
302
303         if ( ret <= 0 ) return ret;
304    
305         buf_out->buf_ptr += ret;
306         if (buf_out->buf_ptr == buf_out->buf_end) {
307                 buf_out->buf_end = buf_out->buf_ptr = 0;
308         }
309
310         if ( (ber_len_t)ret < to_go ) {
311                 /* not enough data, so pretend no data was sent. */
312                 return -1;
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 &&
363                         p->sbiod_io->sbi_close( p ) < 0 )
364                 {
365                         return -1;
366                 }
367                 p = p->sbiod_next;
368         }
369    
370         sb->sb_fd = AC_SOCKET_INVALID;
371    
372         return 0;
373 }
374
375 int
376 ber_int_sb_destroy( Sockbuf *sb )
377 {
378         Sockbuf_IO_Desc         *p;
379
380         assert( sb != NULL);
381         assert( SOCKBUF_VALID( sb ) );
382    
383         while ( sb->sb_iod ) {
384                 p = sb->sb_iod->sbiod_next;
385                 ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io,
386                         sb->sb_iod->sbiod_level );
387                 sb->sb_iod = p;
388         }
389
390         return ber_int_sb_init( sb );
391 }
392
393 ber_slen_t
394 ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
395 {
396         ber_slen_t              ret;
397
398         assert( buf != NULL );
399         assert( sb != NULL);
400         assert( sb->sb_iod != NULL );
401         assert( SOCKBUF_VALID( sb ) );
402
403         for (;;) {
404                 ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
405
406 #ifdef EINTR    
407                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
408 #endif
409                 break;
410         }
411
412         return ret;
413 }
414
415 ber_slen_t
416 ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
417 {
418         ber_slen_t              ret;
419
420         assert( buf != NULL );
421         assert( sb != NULL);
422         assert( sb->sb_iod != NULL );
423         assert( SOCKBUF_VALID( sb ) );
424
425         for (;;) {
426                 ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
427
428 #ifdef EINTR    
429                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
430 #endif
431                 break;
432         }
433
434         return ret;
435 }
436
437 /*
438  * Support for TCP
439  */
440
441 static ber_slen_t
442 sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
443 {
444         assert( sbiod != NULL);
445         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
446
447 #if defined(MACOS)
448 /*
449  * MacTCP/OpenTransport
450  */
451         return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
452                    len, NULL );
453
454 #elif defined( HAVE_PCNFS ) || \
455    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
456 /*
457  * PCNFS (under DOS)
458  */
459 /*
460  * Windows Socket API (under DOS/Windows 3.x)
461  */
462 /*
463  * 32-bit Windows Socket API (under Windows NT or Windows 95)
464  */
465         {
466                 int rc;
467
468                 rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
469
470 #ifdef HAVE_WINSOCK
471                 if ( rc < 0 ) {
472                         int err;
473
474                         err = WSAGetLastError();
475                         errno = err;
476                 }
477 #endif
478
479                 return rc;
480         }
481
482 #elif defined( HAVE_NCSA )
483 /*
484  * NCSA Telnet TCP/IP stack (under DOS)
485  */
486         return nread( sbiod->sbiod_sb->sb_fd, buf, len );
487
488 #else
489         return read( sbiod->sbiod_sb->sb_fd, buf, len );
490 #endif
491 }
492
493 static ber_slen_t
494 sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
495 {
496         assert( sbiod != NULL);
497         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
498
499 #if defined(MACOS) 
500 /*
501  * MacTCP/OpenTransport
502  */
503 #define MAX_WRITE       65535
504         return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
505                 (len<MAX_WRITE) ? len : MAX_WRITE );
506
507 #elif defined( HAVE_PCNFS) \
508         || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
509 /*
510  * PCNFS (under DOS)
511  */
512 /*
513  * Windows Socket API (under DOS/Windows 3.x)
514  */
515 /*
516  * 32-bit Windows Socket API (under Windows NT or Windows 95)
517  */
518         {
519                 int rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
520
521 #ifdef HAVE_WINSOCK
522                 if ( rc < 0 ) {
523                         int err;
524                         err = WSAGetLastError();
525                         errno = err;
526                 }
527 #endif
528                 return rc;
529         }
530
531 #elif defined(HAVE_NCSA)
532         return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
533
534 #elif defined(VMS)
535 /*
536  * VMS -- each write must be 64K or smaller
537  */
538 #define MAX_WRITE 65535
539         return write( sbiod->sbiod_sb->sb_fd, buf,
540                 (len<MAX_WRITE) ? len : MAX_WRITE);
541 #else
542         return write( sbiod->sbiod_sb->sb_fd, buf, len );
543 #endif   
544 }   
545    
546 static int 
547 sb_stream_close( Sockbuf_IO_Desc *sbiod )
548 {
549         assert( sbiod != NULL );
550         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
551         tcp_close( sbiod->sbiod_sb->sb_fd );
552    return 0;
553 }
554
555 /* The argument is a pointer to the socket descriptor */
556 static int
557 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
558         assert( sbiod != NULL );
559
560         if ( arg != NULL ) {
561                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
562         }
563         return 0;
564 }
565
566 static int
567 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
568         /* This is an end IO descriptor */
569         return 0;
570 }
571
572 Sockbuf_IO ber_sockbuf_io_tcp = {
573         sb_stream_setup,        /* sbi_setup */
574         NULL,                           /* sbi_remove */
575         sb_stream_ctrl,         /* sbi_ctrl */
576         sb_stream_read,         /* sbi_read */
577         sb_stream_write,        /* sbi_write */
578         sb_stream_close         /* sbi_close */
579 };
580
581
582 /*
583  * Support for readahead (UDP needs it)
584  */
585
586 static int
587 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
588 {
589         Sockbuf_Buf             *p;
590
591         assert( sbiod != NULL );
592
593         p = LBER_MALLOC( sizeof( *p ) );
594         if ( p == NULL ) return -1;
595
596         ber_pvt_sb_buf_init( p );
597
598         if ( arg == NULL ) {
599                 ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
600         } else {
601                 ber_pvt_sb_grow_buffer( p, *((int *)arg) );
602         }
603
604         sbiod->sbiod_pvt = p;
605         return 0;
606 }
607
608 static int
609 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
610 {
611         Sockbuf_Buf             *p;
612
613         assert( sbiod != NULL );
614
615         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
616
617         if ( p->buf_ptr != p->buf_end ) return -1;
618
619         ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
620         LBER_FREE( sbiod->sbiod_pvt );
621         sbiod->sbiod_pvt = NULL;
622
623         return 0;
624 }
625
626 static ber_slen_t
627 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
628 {
629         Sockbuf_Buf             *p;
630         ber_slen_t              bufptr = 0, ret, max;
631
632         assert( sbiod != NULL );
633         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
634         assert( sbiod->sbiod_next != NULL );
635
636         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
637
638         assert( p->buf_size > 0 );
639
640         /* Are there anything left in the buffer? */
641         ret = ber_pvt_sb_copy_out( p, buf, len );
642         bufptr += ret;
643         len -= ret;
644
645         if ( len == 0 ) return bufptr;
646
647         max = p->buf_size - p->buf_end;
648         ret = 0;
649         while ( max > 0 ) {
650                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
651                         max );
652 #ifdef EINTR    
653                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
654 #endif
655                 break;
656         }
657
658         if ( ret < 0 ) {
659                 return ( bufptr ? bufptr : ret );
660         }
661
662         p->buf_end += ret;
663         bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
664         return bufptr;
665 }
666
667 static ber_slen_t
668 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
669 {
670         assert( sbiod != NULL );
671         assert( sbiod->sbiod_next != NULL );
672
673         return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
674 }
675
676 static int
677 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
678 {
679         assert( sbiod != NULL );
680
681         /* Just erase the buffer */
682         ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
683         return 0;
684 }
685
686 static int
687 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
688 {
689         Sockbuf_Buf             *p;
690
691         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
692
693         if ( opt == LBER_SB_OPT_DATA_READY ) {
694                 if ( p->buf_ptr != p->buf_end ) {
695                         return 1;
696                 }
697
698         } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
699                 if ( p->buf_size >= *((ber_len_t *)arg) ) {
700                         return 0;
701                 }
702                 return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
703                         -1 : 1 );
704         }
705
706         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
707 }
708
709 Sockbuf_IO ber_sockbuf_io_readahead = {
710         sb_rdahead_setup,       /* sbi_setup */
711         sb_rdahead_remove,      /* sbi_remove */
712         sb_rdahead_ctrl,        /* sbi_ctrl */
713         sb_rdahead_read,        /* sbi_read */
714         sb_rdahead_write,       /* sbi_write */
715         sb_rdahead_close        /* sbi_close */
716 };
717
718 /*
719  * Support for simple file IO
720  */
721
722 static ber_slen_t
723 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
724 {
725         assert( sbiod != NULL);
726         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
727
728         return read( sbiod->sbiod_sb->sb_fd, buf, len );
729 }
730
731 static ber_slen_t
732 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
733 {
734         assert( sbiod != NULL);
735         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
736
737         return write( sbiod->sbiod_sb->sb_fd, buf, len );
738 }
739
740 static int 
741 sb_fd_close( Sockbuf_IO_Desc *sbiod )
742 {   
743         assert( sbiod != NULL );
744         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
745
746         close( sbiod->sbiod_sb->sb_fd );
747         return 0;
748 }
749
750 /* The argument is a pointer to the file descriptor */
751 static int
752 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
753         assert( sbiod != NULL );
754
755         if ( arg != NULL )
756                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
757         return 0;
758 }
759
760 static int
761 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
762         /* This is an end IO descriptor */
763         return 0;
764 }
765
766 Sockbuf_IO ber_sockbuf_io_fd = {
767         sb_fd_setup,    /* sbi_setup */
768         NULL,                   /* sbi_remove */
769         sb_fd_ctrl,             /* sbi_ctrl */
770         sb_fd_read,             /* sbi_read */
771         sb_fd_write,            /* sbi_write */
772         sb_fd_close             /* sbi_close */
773 };
774
775 /*
776  * Debugging layer
777  */
778
779 static int
780 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
781 {
782         assert( sbiod != NULL );
783         
784         if ( arg == NULL ) arg = "sockbuf_";
785
786         sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
787         if ( sbiod->sbiod_pvt == NULL ) return -1;
788
789         strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
790         return 0;
791 }
792
793 static int
794 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
795 {
796         assert( sbiod != NULL );
797         assert( sbiod->sbiod_pvt != NULL );
798
799         LBER_FREE( sbiod->sbiod_pvt );
800         sbiod->sbiod_pvt = NULL;
801         return 0;
802 }
803
804 static int
805 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
806 {
807         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
808 }
809
810 static ber_slen_t
811 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
812 {
813         ber_slen_t              ret;
814
815         ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
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
821         } else {
822                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
823                         "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
824                         (long)len, (long)ret );
825                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
826                         (const char *)buf, ret );
827         }
828         return ret;
829 }
830
831 static ber_slen_t
832 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
833 {
834         ber_slen_t              ret;
835
836         ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
837         if ( ret < 0 ) {
838                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
839                         "%swrite: want=%ld error=%s\n",
840                         (char *)sbiod->sbiod_pvt, (long)len,
841                         STRERROR( errno ) );
842
843         } else {
844                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
845                         "%swrite: want=%ld, written=%ld\n",
846                         (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
847                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
848                         (const char *)buf, ret );
849         }
850
851         return ret;
852 }
853
854 Sockbuf_IO ber_sockbuf_io_debug = {
855         sb_debug_setup,         /* sbi_setup */
856         sb_debug_remove,        /* sbi_remove */
857         sb_debug_ctrl,          /* sbi_ctrl */
858         sb_debug_read,          /* sbi_read */
859         sb_debug_write,         /* sbi_write */
860         NULL                            /* sbi_close */
861 };
862