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