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