]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
s/SAFEMEMCPY/AC_MEMCPY/
[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         char                    buf[4096];
72
73         assert( sb != NULL );
74
75         switch ( opt ) {
76                 case LBER_SB_OPT_HAS_IO:
77                         p = sb->sb_iod;
78    
79                         while ( p && p->sbiod_io != (Sockbuf_IO *)arg )
80                                 p = p->sbiod_next;
81    
82                         if ( p )
83                                 ret = 1;
84                         break;
85                 case LBER_SB_OPT_GET_FD:
86                         if ( arg != NULL )
87                                 *((int *)arg) = sb->sb_fd;
88                         ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
89                         break;
90                 case LBER_SB_OPT_SET_FD:
91                         sb->sb_fd = *((int *)arg);
92                         ret = 1;
93                         break;
94                 case LBER_SB_OPT_SET_NONBLOCK:
95                         ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
96                                 ? -1 : 1;
97                         break;
98                 case LBER_SB_OPT_DRAIN:
99                         /* Drain the data source to enable possible errors (e.g.
100                          * TLS) to be propagated to the upper layers
101                          */
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  * Support for UDP (CLDAP)
547  */
548
549 struct dgram_data
550 {
551         struct sockaddr dst;
552         struct sockaddr src;
553 };
554
555 static int 
556 sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
557 {
558         struct dgram_data       *p;
559
560         assert( sbiod != NULL);
561         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
562
563         p = LBER_MALLOC( sizeof( *p ) );
564         if ( p == NULL )
565      return -1;
566         memset( p, '\0', sizeof( *p ) );
567         sbiod->sbiod_pvt = (void *)p;
568         if ( arg != NULL )
569                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
570    return 0;
571 }
572
573 static int 
574 sb_dgram_release( Sockbuf_IO_Desc *sbiod )
575 {
576         assert( sbiod != NULL);
577         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
578
579         LBER_FREE( sbiod->sbiod_pvt );
580         sbiod->sbiod_pvt = NULL;
581    return 0;
582 }
583
584 static ber_slen_t
585 sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
586 {
587 #ifdef LDAP_CONNECTIONLESS
588    ber_slen_t rc;
589    socklen_t  addrlen;
590         struct dgram_data       *p;
591    
592         assert( sbiod != NULL );
593         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
594         assert( buf != NULL );
595
596         p = (struct dgram_data *)sbiod->sbiod_pvt;
597    
598    addrlen = sizeof( struct sockaddr );
599         rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->src,
600                 &addrlen );
601    
602    return rc;
603 # else /* LDAP_CONNECTIONLESS */
604    return -1;
605 # endif /* LDAP_CONNECTIONLESS */
606 }
607
608 static ber_slen_t 
609 sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
610 {
611 #ifdef LDAP_CONNECTIONLESS
612    ber_slen_t rc;
613         struct dgram_data       *p;
614    
615         assert( sbiod != NULL );
616         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
617         assert( buf != NULL );
618
619         p = (struct dgram_data *)sbiod->sbiod_pvt;
620    
621         rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, &p->dst,
622              sizeof( struct sockaddr ) );
623
624    if ( rc <= 0 )
625                 return -1;
626    
627    /* fake error if write was not atomic */
628    if (rc < len) {
629 # ifdef EMSGSIZE
630       errno = EMSGSIZE;
631 # endif
632                 return -1;
633    }
634    return rc;
635 #else
636    return -1;
637 #endif  
638 }
639
640 static int 
641 sb_dgram_close( Sockbuf_IO_Desc *sbiod )
642 {
643         assert( sbiod != NULL );
644         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
645
646         tcp_close( sbiod->sbiod_sb->sb_fd );
647         return 0;
648 }
649
650 static int
651 sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
652 {
653         struct dgram_data       *p;
654
655         assert( sbiod != NULL );
656         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
657
658         p = (struct dgram_data *)sbiod->sbiod_pvt;
659
660         if ( opt == LBER_SB_OPT_UDP_SET_DST ) {
661                 AC_MEMCPY( &p->dst, arg, sizeof( struct sockaddr ) );
662                 return 1;
663         }
664         else if ( opt == LBER_SB_OPT_UDP_GET_SRC ) {
665                 *(( struct sockaddr **)arg) = &p->src;
666                 return 1;
667         }
668         /* This is an end IO descriptor */
669         return 0;
670 }
671
672 Sockbuf_IO ber_sockbuf_io_udp =
673 {
674         sb_dgram_setup,         /* sbi_setup */
675         sb_dgram_release,       /* sbi_release */
676         sb_dgram_ctrl,          /* sbi_ctrl */
677         sb_dgram_read,          /* sbi_read */
678         sb_dgram_write,         /* sbi_write */
679         sb_dgram_close          /* sbi_close */
680 };
681
682 /*
683  * Support for readahead (UDP needs it)
684  */
685
686 static int
687 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
688 {
689         Sockbuf_Buf             *p;
690
691         assert( sbiod != NULL );
692
693         p = LBER_MALLOC( sizeof( *p ) );
694         if ( p == NULL )
695                 return -1;
696         ber_pvt_sb_buf_init( p );
697         if ( arg == NULL )
698                 ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
699         else
700                 ber_pvt_sb_grow_buffer( p, *((int *)arg) );
701         sbiod->sbiod_pvt = p;
702    return 0;
703 }
704
705 static int
706 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
707 {
708         Sockbuf_Buf             *p;
709
710         assert( sbiod != NULL );
711
712         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
713
714         if ( p->buf_ptr != p->buf_end )
715                 return -1;
716
717         ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
718         LBER_FREE( sbiod->sbiod_pvt );
719         sbiod->sbiod_pvt = NULL;
720
721         return 0;
722 }
723
724 static ber_slen_t
725 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
726 {
727         Sockbuf_Buf             *p;
728         ber_slen_t              bufptr = 0, ret, max;
729
730         assert( sbiod != NULL );
731         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
732         assert( sbiod->sbiod_next != NULL );
733
734         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
735
736         assert( p->buf_size > 0 );
737
738         /* Are there anything left in the buffer? */
739         ret = ber_pvt_sb_copy_out( p, buf, len );
740         bufptr += ret;
741         len -= ret;
742
743         if ( len == 0 )
744                 return bufptr;
745
746         max = p->buf_size - p->buf_end;
747         ret = 0;
748         while ( max > 0 ) {
749                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
750                         max );
751 #ifdef EINTR    
752                 if ( ( ret < 0 ) && ( errno == EINTR ) )
753                         continue;
754 #endif
755                 break;
756 }
757
758         if ( ret < 0 )
759                 return ( bufptr ? bufptr : ret );
760
761         p->buf_end += ret;
762         bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
763         return bufptr;
764 }
765
766 static ber_slen_t
767 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
768 {
769         assert( sbiod != NULL );
770         assert( sbiod->sbiod_next != NULL );
771
772         return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
773 }
774
775 static int
776 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
777 {
778         assert( sbiod != NULL );
779
780         /* Just erase the buffer */
781         ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
782         return 0;
783 }
784
785 static int
786 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
787 {
788         Sockbuf_Buf             *p;
789
790         p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
791
792         if ( opt == LBER_SB_OPT_DATA_READY ) {
793                 if ( p->buf_ptr != p->buf_end )
794                         return 1;
795         }
796         else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
797                 if ( p->buf_size >= *((ber_len_t *)arg) )
798                         return 0;
799                 return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
800                         -1 : 1 );
801         }
802
803         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
804 }
805
806 Sockbuf_IO ber_sockbuf_io_readahead =
807 {
808         sb_rdahead_setup,       /* sbi_setup */
809         sb_rdahead_remove,      /* sbi_remove */
810         sb_rdahead_ctrl,        /* sbi_ctrl */
811         sb_rdahead_read,        /* sbi_read */
812         sb_rdahead_write,       /* sbi_write */
813         sb_rdahead_close        /* sbi_close */
814 };
815
816 /*
817  * Support for simple file IO
818  */
819
820 static ber_slen_t
821 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
822 {
823         assert( sbiod != NULL);
824         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
825
826         return read( sbiod->sbiod_sb->sb_fd, buf, len );
827 }
828
829 static ber_slen_t
830 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
831 {
832         assert( sbiod != NULL);
833         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
834
835         return write( sbiod->sbiod_sb->sb_fd, buf, len );
836 }
837
838 static int 
839 sb_fd_close( Sockbuf_IO_Desc *sbiod )
840 {   
841         assert( sbiod != NULL );
842         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
843
844         close( sbiod->sbiod_sb->sb_fd );
845         return 0;
846 }
847
848 /* The argument is a pointer to the file descriptor */
849 static int
850 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
851         assert( sbiod != NULL );
852
853         if ( arg != NULL )
854                 sbiod->sbiod_sb->sb_fd = *((int *)arg);
855         return 0;
856 }
857
858 static int
859 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
860         /* This is an end IO descriptor */
861         return 0;
862 }
863
864 Sockbuf_IO ber_sockbuf_io_fd =
865 {
866         sb_fd_setup,            /* sbi_setup */
867         NULL,                   /* sbi_remove */
868         sb_fd_ctrl,             /* sbi_ctrl */
869         sb_fd_read,             /* sbi_read */
870         sb_fd_write,            /* sbi_write */
871         sb_fd_close             /* sbi_close */
872 };
873
874 /*
875  * Debugging layer
876  */
877
878 static int
879 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
880 {
881         assert( sbiod != NULL );
882         
883         if ( arg == NULL )
884                 arg = "sockbuf_";
885
886         sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
887         if ( sbiod->sbiod_pvt == NULL )
888    return -1;
889         strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
890         return 0;
891 }
892
893 static int
894 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
895 {
896         assert( sbiod != NULL );
897         assert( sbiod->sbiod_pvt != NULL );
898
899         LBER_FREE( sbiod->sbiod_pvt );
900         sbiod->sbiod_pvt = NULL;
901         return 0;
902 }
903
904 static int
905 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
906 {
907         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
908 }
909
910 static ber_slen_t
911 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
912 {
913         ber_slen_t              ret;
914
915         ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
916         if ( ret < 0 ) {
917                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
918                         "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
919                         (long)len, STRERROR( errno ) );
920         }
921         else {
922                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
923                         "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
924                         (long)len, (long)ret );
925                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
926                         (const char *)buf, ret );
927         }
928         return ret;
929 }
930
931 static ber_slen_t
932 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
933 {
934         ber_slen_t              ret;
935
936         ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
937         if ( ret < 0 ) {
938                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
939                         "%swrite: want=%ld error=%s\n",
940                         (char *)sbiod->sbiod_pvt, (long)len,
941                         STRERROR( errno ) );
942         }
943         else {
944                 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
945                         "%swrite: want=%ld, written=%ld\n",
946                         (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
947                 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
948                         (const char *)buf, ret );
949         }
950         return ret;
951 }
952
953 Sockbuf_IO ber_sockbuf_io_debug =
954 {
955         sb_debug_setup,         /* sbi_setup */
956         sb_debug_remove,        /* sbi_remove */
957         sb_debug_ctrl,          /* sbi_ctrl */
958         sb_debug_read,          /* sbi_read */
959         sb_debug_write,         /* sbi_write */
960         NULL                    /* sbi_close */
961 };
962