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