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