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