]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
Rebuild
[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)
248       return -1;
249    }
250
251         if ( buf->buf_size < pw ) {
252                 p = LBER_REALLOC( buf->buf_base, pw );
253                 if ( p == NULL )
254                         return -1;
255                 buf->buf_base = p;
256                 buf->buf_size = pw;
257    }
258         return 0;
259 }
260
261 ber_len_t
262 ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
263 {
264         ber_len_t               max;
265
266         assert( buf != NULL );
267         assert( sbb != NULL );
268 #if 0
269         assert( sbb->buf_size > 0 );
270 #endif
271
272         max = sbb->buf_end - sbb->buf_ptr;
273         max = ( max < len) ? max : len;
274         if ( max ) {
275                 AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
276                 sbb->buf_ptr += max;
277                 if ( sbb->buf_ptr >= sbb->buf_end ) {
278                         sbb->buf_ptr = sbb->buf_end = 0;
279                 }
280    }
281         return max;
282 }
283
284 ber_slen_t
285 ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
286 {
287         ber_len_t               to_go;
288         ber_slen_t ret;
289
290         assert( sbiod != NULL );
291         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
292
293         to_go = buf_out->buf_end - buf_out->buf_ptr;
294         assert( to_go > 0 );
295    
296         for(;;) {
297                 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
298                         buf_out->buf_ptr, to_go );
299 #ifdef EINTR
300                 if ((ret<0) && (errno==EINTR)) continue;
301 #endif
302                 break;
303         }
304
305         if ( ret <= 0 ) return ret;
306    
307         buf_out->buf_ptr += ret;
308         if (buf_out->buf_ptr == buf_out->buf_end) {
309                 buf_out->buf_end = buf_out->buf_ptr = 0;
310         }
311
312         if ( (ber_len_t)ret < to_go ) {
313                 /* not enough data, so pretend no data was sent. */
314                 return -1;
315         }
316
317         return ret;
318 }
319
320 int
321 ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
322 {
323 #if HAVE_FCNTL
324         int flags = fcntl( sd, F_GETFL);
325         if( nb ) {
326                 flags |= O_NONBLOCK;
327         } else {
328                 flags &= ~O_NONBLOCK;
329         }
330         return fcntl( sd, F_SETFL, flags );
331                 
332 #elif defined( FIONBIO )
333         ioctl_t status = nb ? 1 : 0;
334         return ioctl( sd, FIONBIO, &status );
335 #endif
336 }
337
338 int
339 ber_int_sb_init( Sockbuf *sb )
340 {
341         assert( sb != NULL);
342
343         sb->sb_valid=LBER_VALID_SOCKBUF;
344         sb->sb_options = 0;
345         sb->sb_debug = ber_int_debug;
346         sb->sb_fd = AC_SOCKET_INVALID;
347         sb->sb_iod = NULL;
348         sb->sb_trans_needs_read = 0;
349         sb->sb_trans_needs_write = 0;
350    
351         assert( SOCKBUF_VALID( sb ) );
352         return 0;
353 }
354    
355 int
356 ber_int_sb_close( Sockbuf *sb )
357 {
358         Sockbuf_IO_Desc         *p;
359
360         assert( sb != NULL);
361    
362         p = sb->sb_iod;
363         while ( p ) {
364                 if ( p->sbiod_io->sbi_close &&
365                         p->sbiod_io->sbi_close( p ) < 0 )
366                 {
367                         return -1;
368                 }
369                 p = p->sbiod_next;
370         }
371    
372         sb->sb_fd = AC_SOCKET_INVALID;
373    
374         return 0;
375 }
376
377 int
378 ber_int_sb_destroy( Sockbuf *sb )
379 {
380         Sockbuf_IO_Desc         *p;
381
382         assert( sb != NULL);
383         assert( SOCKBUF_VALID( sb ) );
384    
385         while ( sb->sb_iod ) {
386                 p = sb->sb_iod->sbiod_next;
387                 ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io,
388                         sb->sb_iod->sbiod_level );
389                 sb->sb_iod = p;
390         }
391
392         return ber_int_sb_init( sb );
393 }
394
395 ber_slen_t
396 ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
397 {
398         ber_slen_t              ret;
399
400         assert( buf != NULL );
401         assert( sb != NULL);
402         assert( sb->sb_iod != NULL );
403         assert( SOCKBUF_VALID( sb ) );
404
405         for (;;) {
406                 ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
407
408 #ifdef EINTR    
409                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
410 #endif
411                 break;
412         }
413
414         return ret;
415 }
416
417 ber_slen_t
418 ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
419 {
420         ber_slen_t              ret;
421
422         assert( buf != NULL );
423         assert( sb != NULL);
424         assert( sb->sb_iod != NULL );
425         assert( SOCKBUF_VALID( sb ) );
426
427         for (;;) {
428                 ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
429
430 #ifdef EINTR    
431                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
432 #endif
433                 break;
434         }
435
436         return ret;
437 }
438
439 /*
440  * Support for TCP
441  */
442
443 static ber_slen_t
444 sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
445 {
446         assert( sbiod != NULL);
447         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
448
449 #if defined(MACOS)
450 /*
451  * MacTCP/OpenTransport
452  */
453         return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
454                    len, NULL );
455
456 #elif defined( HAVE_PCNFS ) || \
457    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
458 /*
459  * PCNFS (under DOS)
460  */
461 /*
462  * Windows Socket API (under DOS/Windows 3.x)
463  */
464 /*
465  * 32-bit Windows Socket API (under Windows NT or Windows 95)
466  */
467         {
468                 int rc;
469
470                 rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
471
472 #ifdef HAVE_WINSOCK
473                 if ( rc < 0 ) {
474                         int err;
475
476                         err = WSAGetLastError();
477                         errno = err;
478                 }
479 #endif
480
481                 return rc;
482         }
483
484 #elif defined( HAVE_NCSA )
485 /*
486  * NCSA Telnet TCP/IP stack (under DOS)
487  */
488         return nread( sbiod->sbiod_sb->sb_fd, buf, len );
489
490 #else
491         return read( sbiod->sbiod_sb->sb_fd, buf, len );
492 #endif
493 }
494
495 static ber_slen_t
496 sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
497 {
498         assert( sbiod != NULL);
499         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
500
501 #if defined(MACOS) 
502 /*
503  * MacTCP/OpenTransport
504  */
505 #define MAX_WRITE       65535
506         return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
507                 (len<MAX_WRITE) ? len : MAX_WRITE );
508
509 #elif defined( HAVE_PCNFS) \
510         || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
511 /*
512  * PCNFS (under DOS)
513  */
514 /*
515  * Windows Socket API (under DOS/Windows 3.x)
516  */
517 /*
518  * 32-bit Windows Socket API (under Windows NT or Windows 95)
519  */
520         {
521                 int rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
522
523 #ifdef HAVE_WINSOCK
524                 if ( rc < 0 ) {
525                         int err;
526                         err = WSAGetLastError();
527                         errno = err;
528                 }
529 #endif
530                 return rc;
531         }
532
533 #elif defined(HAVE_NCSA)
534         return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
535
536 #elif defined(VMS)
537 /*
538  * VMS -- each write must be 64K or smaller
539  */
540 #define MAX_WRITE 65535
541         return write( sbiod->sbiod_sb->sb_fd, buf,
542                 (len<MAX_WRITE) ? len : MAX_WRITE);
543 #else
544         return write( sbiod->sbiod_sb->sb_fd, buf, len );
545 #endif   
546 }   
547    
548 static int 
549 sb_stream_close( Sockbuf_IO_Desc *sbiod )
550 {
551         assert( sbiod != NULL );
552         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
553         tcp_close( sbiod->sbiod_sb->sb_fd );
554    return 0;
555 }
556
557 /* The argument is a pointer to the socket descriptor */
558 static int
559 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
560         assert( sbiod != NULL );
561
562         if ( arg != NULL ) {
563                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
564         }
565         return 0;
566 }
567
568 static int
569 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
570         /* This is an end IO descriptor */
571         return 0;
572 }
573
574 Sockbuf_IO ber_sockbuf_io_tcp = {
575         sb_stream_setup,        /* sbi_setup */
576         NULL,                           /* sbi_remove */
577         sb_stream_ctrl,         /* sbi_ctrl */
578         sb_stream_read,         /* sbi_read */
579         sb_stream_write,        /* sbi_write */
580         sb_stream_close         /* sbi_close */
581 };
582
583
584 /*
585  * Support for readahead (UDP needs it)
586  */
587
588 static int
589 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
590 {
591         Sockbuf_Buf             *p;
592
593         assert( sbiod != NULL );
594
595         p = LBER_MALLOC( sizeof( *p ) );
596         if ( p == NULL ) return -1;
597
598         ber_pvt_sb_buf_init( p );
599
600         if ( arg == NULL ) {
601                 ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
602         } else {
603                 ber_pvt_sb_grow_buffer( p, *((int *)arg) );
604         }
605
606         sbiod->sbiod_pvt = p;
607         return 0;
608 }
609
610 static int
611 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
612 {
613         Sockbuf_Buf             *p;
614
615         assert( sbiod != NULL );
616
617         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
618
619         if ( p->buf_ptr != p->buf_end ) return -1;
620
621         ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
622         LBER_FREE( sbiod->sbiod_pvt );
623         sbiod->sbiod_pvt = NULL;
624
625         return 0;
626 }
627
628 static ber_slen_t
629 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
630 {
631         Sockbuf_Buf             *p;
632         ber_slen_t              bufptr = 0, ret, max;
633
634         assert( sbiod != NULL );
635         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
636         assert( sbiod->sbiod_next != NULL );
637
638         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
639
640         assert( p->buf_size > 0 );
641
642         /* Are there anything left in the buffer? */
643         ret = ber_pvt_sb_copy_out( p, buf, len );
644         bufptr += ret;
645         len -= ret;
646
647         if ( len == 0 ) return bufptr;
648
649         max = p->buf_size - p->buf_end;
650         ret = 0;
651         while ( max > 0 ) {
652                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
653                         max );
654 #ifdef EINTR    
655                 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
656 #endif
657                 break;
658         }
659
660         if ( ret < 0 ) {
661                 return ( bufptr ? bufptr : ret );
662         }
663
664         p->buf_end += ret;
665         bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
666         return bufptr;
667 }
668
669 static ber_slen_t
670 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
671 {
672         assert( sbiod != NULL );
673         assert( sbiod->sbiod_next != NULL );
674
675         return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
676 }
677
678 static int
679 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
680 {
681         assert( sbiod != NULL );
682
683         /* Just erase the buffer */
684         ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
685         return 0;
686 }
687
688 static int
689 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
690 {
691         Sockbuf_Buf             *p;
692
693         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
694
695         if ( opt == LBER_SB_OPT_DATA_READY ) {
696                 if ( p->buf_ptr != p->buf_end ) {
697                         return 1;
698                 }
699
700         } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
701                 if ( p->buf_size >= *((ber_len_t *)arg) ) {
702                         return 0;
703                 }
704                 return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
705                         -1 : 1 );
706         }
707
708         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
709 }
710
711 Sockbuf_IO ber_sockbuf_io_readahead = {
712         sb_rdahead_setup,       /* sbi_setup */
713         sb_rdahead_remove,      /* sbi_remove */
714         sb_rdahead_ctrl,        /* sbi_ctrl */
715         sb_rdahead_read,        /* sbi_read */
716         sb_rdahead_write,       /* sbi_write */
717         sb_rdahead_close        /* sbi_close */
718 };
719
720 /*
721  * Support for simple file IO
722  */
723
724 static ber_slen_t
725 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
726 {
727         assert( sbiod != NULL);
728         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
729
730         return read( sbiod->sbiod_sb->sb_fd, buf, len );
731 }
732
733 static ber_slen_t
734 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
735 {
736         assert( sbiod != NULL);
737         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
738
739         return write( sbiod->sbiod_sb->sb_fd, buf, len );
740 }
741
742 static int 
743 sb_fd_close( Sockbuf_IO_Desc *sbiod )
744 {   
745         assert( sbiod != NULL );
746         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
747
748         close( sbiod->sbiod_sb->sb_fd );
749         return 0;
750 }
751
752 /* The argument is a pointer to the file descriptor */
753 static int
754 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
755         assert( sbiod != NULL );
756
757         if ( arg != NULL )
758                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
759         return 0;
760 }
761
762 static int
763 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
764         /* This is an end IO descriptor */
765         return 0;
766 }
767
768 Sockbuf_IO ber_sockbuf_io_fd = {
769         sb_fd_setup,    /* sbi_setup */
770         NULL,                   /* sbi_remove */
771         sb_fd_ctrl,             /* sbi_ctrl */
772         sb_fd_read,             /* sbi_read */
773         sb_fd_write,            /* sbi_write */
774         sb_fd_close             /* sbi_close */
775 };
776
777 /*
778  * Debugging layer
779  */
780
781 static int
782 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
783 {
784         assert( sbiod != NULL );
785         
786         if ( arg == NULL ) arg = "sockbuf_";
787
788         sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
789         if ( sbiod->sbiod_pvt == NULL ) return -1;
790
791         strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
792         return 0;
793 }
794
795 static int
796 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
797 {
798         assert( sbiod != NULL );
799         assert( sbiod->sbiod_pvt != NULL );
800
801         LBER_FREE( sbiod->sbiod_pvt );
802         sbiod->sbiod_pvt = NULL;
803         return 0;
804 }
805
806 static int
807 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
808 {
809         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
810 }
811
812 static ber_slen_t
813 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
814 {
815         ber_slen_t              ret;
816
817         ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
818         if ( ret < 0 ) {
819                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
820                         "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
821                         (long)len, STRERROR( errno ) );
822
823         } else {
824                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
825                         "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
826                         (long)len, (long)ret );
827                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
828                         (const char *)buf, ret );
829         }
830         return ret;
831 }
832
833 static ber_slen_t
834 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
835 {
836         ber_slen_t              ret;
837
838         ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
839         if ( ret < 0 ) {
840                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
841                         "%swrite: want=%ld error=%s\n",
842                         (char *)sbiod->sbiod_pvt, (long)len,
843                         STRERROR( errno ) );
844
845         } else {
846                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
847                         "%swrite: want=%ld, written=%ld\n",
848                         (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
849                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
850                         (const char *)buf, ret );
851         }
852
853         return ret;
854 }
855
856 Sockbuf_IO ber_sockbuf_io_debug = {
857         sb_debug_setup,         /* sbi_setup */
858         sb_debug_remove,        /* sbi_remove */
859         sb_debug_ctrl,          /* sbi_ctrl */
860         sb_debug_read,          /* sbi_read */
861         sb_debug_write,         /* sbi_write */
862         NULL                            /* sbi_close */
863 };
864