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