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