1 /* sockbuf.c - i/o routines with support for adding i/o layers. */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
21 #include <ac/stdlib.h>
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/unistd.h>
31 #endif /* HAVE_IO_H */
33 #if defined( HAVE_FCNTL_H )
37 #if defined( HAVE_SYS_FILIO_H )
38 #include <sys/filio.h>
39 #elif defined( HAVE_SYS_IOCTL_H )
40 #include <sys/ioctl.h>
45 #ifndef LBER_MIN_BUFF_SIZE
46 #define LBER_MIN_BUFF_SIZE 4096
48 #ifndef LBER_MAX_BUFF_SIZE
49 #define LBER_MAX_BUFF_SIZE (65536*256)
51 #ifndef LBER_DEFAULT_READAHEAD
52 #define LBER_DEFAULT_READAHEAD 16384
56 ber_sockbuf_alloc( void )
60 sb
= LBER_CALLOC( 1, sizeof( Sockbuf
) );
62 if( sb
== NULL
) return NULL
;
64 ber_int_sb_init( sb
);
69 ber_sockbuf_free( Sockbuf
*sb
)
72 assert( SOCKBUF_VALID( sb
) );
74 ber_int_sb_close( sb
);
75 ber_int_sb_destroy( sb
);
79 /* Return values: -1: error, 0: no operation performed or the answer is false,
80 * 1: successful operation or the answer is true
83 ber_sockbuf_ctrl( Sockbuf
*sb
, int opt
, void *arg
)
89 assert( SOCKBUF_VALID( sb
) );
92 case LBER_SB_OPT_HAS_IO
:
94 while ( p
&& p
->sbiod_io
!= (Sockbuf_IO
*)arg
) {
103 case LBER_SB_OPT_GET_FD
:
105 *((ber_socket_t
*)arg
) = sb
->sb_fd
;
107 ret
= ( sb
->sb_fd
== AC_SOCKET_INVALID
? -1 : 1);
110 case LBER_SB_OPT_SET_FD
:
111 sb
->sb_fd
= *((ber_socket_t
*)arg
);
115 case LBER_SB_OPT_SET_NONBLOCK
:
116 ret
= ber_pvt_socket_set_nonblock( sb
->sb_fd
, arg
!= NULL
)
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
124 char buf
[LBER_MIN_BUFF_SIZE
];
127 ret
= ber_int_sb_read( sb
, buf
, sizeof( buf
) );
128 } while ( ret
== sizeof( buf
) );
133 case LBER_SB_OPT_NEEDS_READ
:
134 ret
= ( sb
->sb_trans_needs_read
? 1 : 0 );
137 case LBER_SB_OPT_NEEDS_WRITE
:
138 ret
= ( sb
->sb_trans_needs_write
? 1 : 0 );
141 case LBER_SB_OPT_GET_MAX_INCOMING
:
143 *((ber_len_t
*)arg
) = sb
->sb_max_incoming
;
148 case LBER_SB_OPT_SET_MAX_INCOMING
:
149 sb
->sb_max_incoming
= *((ber_len_t
*)arg
);
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
,
168 ret
= sb
->sb_iod
->sbiod_io
->sbi_ctrl( sb
->sb_iod
, opt
, arg
);
176 ber_sockbuf_add_io( Sockbuf
*sb
, Sockbuf_IO
*sbio
, int layer
, void *arg
)
178 Sockbuf_IO_Desc
*d
, *p
, **q
;
180 assert( sb
!= NULL
);
181 assert( SOCKBUF_VALID( sb
) );
183 if ( sbio
== NULL
) {
189 while ( p
&& p
->sbiod_level
> layer
) {
194 d
= LBER_MALLOC( sizeof( *d
) );
199 d
->sbiod_level
= layer
;
202 memset( &d
->sbiod_pvt
, '\0', sizeof( d
->sbiod_pvt
) );
206 if ( sbio
->sbi_setup
!= NULL
&& ( sbio
->sbi_setup( d
, arg
) < 0 ) ) {
214 ber_sockbuf_remove_io( Sockbuf
*sb
, Sockbuf_IO
*sbio
, int layer
)
216 Sockbuf_IO_Desc
*p
, **q
;
218 assert( sb
!= NULL
);
219 assert( SOCKBUF_VALID( sb
) );
221 if ( sb
->sb_iod
== NULL
) {
226 while ( *q
!= NULL
) {
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 )
245 ber_pvt_sb_buf_init( Sockbuf_Buf
*buf
)
247 buf
->buf_base
= NULL
;
254 ber_pvt_sb_buf_destroy( Sockbuf_Buf
*buf
)
256 assert( buf
!= NULL
);
259 LBER_FREE( buf
->buf_base
);
261 ber_pvt_sb_buf_init( buf
);
265 ber_pvt_sb_grow_buffer( Sockbuf_Buf
*buf
, ber_len_t minsize
)
270 assert( buf
!= NULL
);
272 for ( pw
= LBER_MIN_BUFF_SIZE
; pw
< minsize
; pw
<<= 1 ) {
273 if (pw
> LBER_MAX_BUFF_SIZE
) return -1;
276 if ( buf
->buf_size
< pw
) {
277 p
= LBER_REALLOC( buf
->buf_base
, pw
);
278 if ( p
== NULL
) return -1;
286 ber_pvt_sb_copy_out( Sockbuf_Buf
*sbb
, char *buf
, ber_len_t len
)
290 assert( buf
!= NULL
);
291 assert( sbb
!= NULL
);
293 assert( sbb
->buf_size
> 0 );
296 max
= sbb
->buf_end
- sbb
->buf_ptr
;
297 max
= ( max
< len
) ? max
: len
;
299 AC_MEMCPY( buf
, sbb
->buf_base
+ sbb
->buf_ptr
, max
);
301 if ( sbb
->buf_ptr
>= sbb
->buf_end
) {
302 sbb
->buf_ptr
= sbb
->buf_end
= 0;
309 ber_pvt_sb_do_write( Sockbuf_IO_Desc
*sbiod
, Sockbuf_Buf
*buf_out
)
314 assert( sbiod
!= NULL
);
315 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
317 to_go
= buf_out
->buf_end
- buf_out
->buf_ptr
;
321 ret
= LBER_SBIOD_WRITE_NEXT( sbiod
, buf_out
->buf_base
+
322 buf_out
->buf_ptr
, to_go
);
324 if ((ret
<0) && (errno
==EINTR
)) continue;
329 if ( ret
<= 0 ) return ret
;
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;
340 ber_pvt_socket_set_nonblock( ber_socket_t sd
, int nb
)
343 int flags
= fcntl( sd
, F_GETFL
);
347 flags
&= ~O_NONBLOCK
;
349 return fcntl( sd
, F_SETFL
, flags
);
351 #elif defined( FIONBIO )
352 ioctl_t status
= nb
? 1 : 0;
353 return ioctl( sd
, FIONBIO
, &status
);
358 ber_int_sb_init( Sockbuf
*sb
)
362 sb
->sb_valid
=LBER_VALID_SOCKBUF
;
364 sb
->sb_debug
= ber_int_debug
;
365 sb
->sb_fd
= AC_SOCKET_INVALID
;
367 sb
->sb_trans_needs_read
= 0;
368 sb
->sb_trans_needs_write
= 0;
370 assert( SOCKBUF_VALID( sb
) );
375 ber_int_sb_close( Sockbuf
*sb
)
383 if ( p
->sbiod_io
->sbi_close
&& p
->sbiod_io
->sbi_close( p
) < 0 ) {
389 sb
->sb_fd
= AC_SOCKET_INVALID
;
395 ber_int_sb_destroy( Sockbuf
*sb
)
400 assert( SOCKBUF_VALID( sb
) );
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
);
409 return ber_int_sb_init( sb
);
413 ber_int_sb_read( Sockbuf
*sb
, void *buf
, ber_len_t len
)
417 assert( buf
!= NULL
);
419 assert( sb
->sb_iod
!= NULL
);
420 assert( SOCKBUF_VALID( sb
) );
423 ret
= sb
->sb_iod
->sbiod_io
->sbi_read( sb
->sb_iod
, buf
, len
);
426 if ( ( ret
< 0 ) && ( errno
== EINTR
) ) continue;
435 ber_int_sb_write( Sockbuf
*sb
, void *buf
, ber_len_t len
)
439 assert( buf
!= NULL
);
441 assert( sb
->sb_iod
!= NULL
);
442 assert( SOCKBUF_VALID( sb
) );
445 ret
= sb
->sb_iod
->sbiod_io
->sbi_write( sb
->sb_iod
, buf
, len
);
448 if ( ( ret
< 0 ) && ( errno
== EINTR
) ) continue;
461 sb_stream_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
463 assert( sbiod
!= NULL
);
464 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
468 * MacTCP/OpenTransport
470 return tcpread( sbiod
->sbiod_sb
->sb_fd
, 0, (unsigned char *)buf
,
473 #elif defined( HAVE_PCNFS ) || \
474 defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
479 * Windows Socket API (under DOS/Windows 3.x)
482 * 32-bit Windows Socket API (under Windows NT or Windows 95)
484 return recv( sbiod
->sbiod_sb
->sb_fd
, buf
, len
, 0 );
486 #elif defined( HAVE_NCSA )
488 * NCSA Telnet TCP/IP stack (under DOS)
490 return nread( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
493 return read( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
498 sb_stream_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
500 assert( sbiod
!= NULL
);
501 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
505 * MacTCP/OpenTransport
507 #define MAX_WRITE 65535
508 return tcpwrite( sbiod
->sbiod_sb
->sb_fd
, (unsigned char *)buf
,
509 (len
<MAX_WRITE
) ? len
: MAX_WRITE
);
511 #elif defined( HAVE_PCNFS) \
512 || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
517 * Windows Socket API (under DOS/Windows 3.x)
520 * 32-bit Windows Socket API (under Windows NT or Windows 95)
522 return send( sbiod
->sbiod_sb
->sb_fd
, buf
, len
, 0 );
524 #elif defined(HAVE_NCSA)
525 return netwrite( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
529 * VMS -- each write must be 64K or smaller
531 #define MAX_WRITE 65535
532 return write( sbiod
->sbiod_sb
->sb_fd
, buf
,
533 (len
<MAX_WRITE
) ? len
: MAX_WRITE
);
535 return write( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
540 sb_stream_close( Sockbuf_IO_Desc
*sbiod
)
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
);
549 /* The argument is a pointer to the socket descriptor */
551 sb_stream_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
) {
552 assert( sbiod
!= NULL
);
555 sbiod
->sbiod_sb
->sb_fd
= *((int *)arg
);
561 sb_stream_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
) {
562 /* This is an end IO descriptor */
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 */
577 * Support for readahead (UDP needs it)
581 sb_rdahead_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
)
585 assert( sbiod
!= NULL
);
587 p
= LBER_MALLOC( sizeof( *p
) );
588 if ( p
== NULL
) return -1;
590 ber_pvt_sb_buf_init( p
);
593 ber_pvt_sb_grow_buffer( p
, LBER_DEFAULT_READAHEAD
);
595 ber_pvt_sb_grow_buffer( p
, *((int *)arg
) );
598 sbiod
->sbiod_pvt
= p
;
603 sb_rdahead_remove( Sockbuf_IO_Desc
*sbiod
)
607 assert( sbiod
!= NULL
);
609 p
= (Sockbuf_Buf
*)sbiod
->sbiod_pvt
;
611 if ( p
->buf_ptr
!= p
->buf_end
) return -1;
613 ber_pvt_sb_buf_destroy( (Sockbuf_Buf
*)(sbiod
->sbiod_pvt
) );
614 LBER_FREE( sbiod
->sbiod_pvt
);
615 sbiod
->sbiod_pvt
= NULL
;
621 sb_rdahead_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
624 ber_slen_t bufptr
= 0, ret
, max
;
626 assert( sbiod
!= NULL
);
627 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
628 assert( sbiod
->sbiod_next
!= NULL
);
630 p
= (Sockbuf_Buf
*)sbiod
->sbiod_pvt
;
632 assert( p
->buf_size
> 0 );
634 /* Are there anything left in the buffer? */
635 ret
= ber_pvt_sb_copy_out( p
, buf
, len
);
639 if ( len
== 0 ) return bufptr
;
641 max
= p
->buf_size
- p
->buf_end
;
644 ret
= LBER_SBIOD_READ_NEXT( sbiod
, p
->buf_base
+ p
->buf_end
,
647 if ( ( ret
< 0 ) && ( errno
== EINTR
) ) continue;
653 return ( bufptr
? bufptr
: ret
);
657 bufptr
+= ber_pvt_sb_copy_out( p
, (char *) buf
+ bufptr
, len
);
662 sb_rdahead_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
664 assert( sbiod
!= NULL
);
665 assert( sbiod
->sbiod_next
!= NULL
);
667 return LBER_SBIOD_WRITE_NEXT( sbiod
, buf
, len
);
671 sb_rdahead_close( Sockbuf_IO_Desc
*sbiod
)
673 assert( sbiod
!= NULL
);
675 /* Just erase the buffer */
676 ber_pvt_sb_buf_destroy((Sockbuf_Buf
*)sbiod
->sbiod_pvt
);
681 sb_rdahead_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
685 p
= (Sockbuf_Buf
*)sbiod
->sbiod_pvt
;
687 if ( opt
== LBER_SB_OPT_DATA_READY
) {
688 if ( p
->buf_ptr
!= p
->buf_end
) {
692 } else if ( opt
== LBER_SB_OPT_SET_READAHEAD
) {
693 if ( p
->buf_size
>= *((ber_len_t
*)arg
) ) {
696 return ( ber_pvt_sb_grow_buffer( p
, *((int *)arg
) ) ?
700 return LBER_SBIOD_CTRL_NEXT( sbiod
, opt
, arg
);
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 */
713 * Support for simple file IO
717 sb_fd_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
719 assert( sbiod
!= NULL
);
720 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
722 #ifdef LDAP_PF_LOCAL_SENDMSG
723 if ( sbiod
->sbiod_sb
->sb_ungetlen
) {
724 ber_len_t blen
= sbiod
->sbiod_sb
->sb_ungetlen
;
727 AC_MEMCPY( buf
, sbiod
->sbiod_sb
->sb_ungetbuf
, blen
);
728 buf
= (char *) buf
+ 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
);
740 return read( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
744 sb_fd_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
746 assert( sbiod
!= NULL
);
747 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
749 return write( sbiod
->sbiod_sb
->sb_fd
, buf
, len
);
753 sb_fd_close( Sockbuf_IO_Desc
*sbiod
)
755 assert( sbiod
!= NULL
);
756 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
758 if ( sbiod
->sbiod_sb
->sb_fd
!= AC_SOCKET_INVALID
)
759 close( sbiod
->sbiod_sb
->sb_fd
);
763 /* The argument is a pointer to the file descriptor */
765 sb_fd_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
) {
766 assert( sbiod
!= NULL
);
769 sbiod
->sbiod_sb
->sb_fd
= *((int *)arg
);
774 sb_fd_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
) {
775 /* This is an end IO descriptor */
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 */
793 sb_debug_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
)
795 assert( sbiod
!= NULL
);
797 if ( arg
== NULL
) arg
= "sockbuf_";
799 sbiod
->sbiod_pvt
= LBER_MALLOC( strlen( arg
) + 1 );
800 if ( sbiod
->sbiod_pvt
== NULL
) return -1;
802 strcpy( (char *)sbiod
->sbiod_pvt
, (char *)arg
);
807 sb_debug_remove( Sockbuf_IO_Desc
*sbiod
)
809 assert( sbiod
!= NULL
);
810 assert( sbiod
->sbiod_pvt
!= NULL
);
812 LBER_FREE( sbiod
->sbiod_pvt
);
813 sbiod
->sbiod_pvt
= NULL
;
818 sb_debug_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
820 return LBER_SBIOD_CTRL_NEXT( sbiod
, opt
, arg
);
824 sb_debug_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
829 ret
= LBER_SBIOD_READ_NEXT( sbiod
, buf
, len
);
830 if (sbiod
->sbiod_sb
->sb_debug
& LDAP_DEBUG_PACKETS
) {
831 int err
= sock_errno();
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
) );
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
);
849 sb_debug_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
854 ret
= LBER_SBIOD_WRITE_NEXT( sbiod
, buf
, len
);
855 if (sbiod
->sbiod_sb
->sb_debug
& LDAP_DEBUG_PACKETS
) {
856 int err
= sock_errno();
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
) );
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
);
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 */
884 #ifdef LDAP_CONNECTIONLESS
887 * Support for UDP (CLDAP)
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_storage containing the address of the remote entity. Upper levels
892 * must read and write this sockaddr_storage before doing the usual ber_printf/scanf
893 * operations on LDAP messages.
897 sb_dgram_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
)
899 assert( sbiod
!= NULL
);
900 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
902 if ( arg
!= NULL
) sbiod
->sbiod_sb
->sb_fd
= *((int *)arg
);
907 sb_dgram_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
910 ber_socklen_t addrlen
;
911 struct sockaddr
*src
;
913 assert( sbiod
!= NULL
);
914 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
915 assert( buf
!= NULL
);
917 addrlen
= sizeof( struct sockaddr_storage
);
919 buf
= (char *) buf
+ addrlen
;
921 rc
= recvfrom( sbiod
->sbiod_sb
->sb_fd
, buf
, len
, 0, src
, &addrlen
);
923 return rc
> 0 ? rc
+sizeof(struct sockaddr_storage
) : rc
;
927 sb_dgram_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
930 struct sockaddr
*dst
;
933 assert( sbiod
!= NULL
);
934 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
935 assert( buf
!= NULL
);
938 buf
= (char *) buf
+ sizeof( struct sockaddr_storage
);
939 len
-= sizeof( struct sockaddr_storage
);
940 dstsize
= dst
->sa_family
== AF_INET
? sizeof( struct sockaddr_in
)
942 : dst
->sa_family
== AF_INET6
? sizeof( struct sockaddr_in6
)
944 : sizeof( struct sockaddr_storage
);
945 rc
= sendto( sbiod
->sbiod_sb
->sb_fd
, buf
, len
, 0, dst
, dstsize
);
947 if ( rc
< 0 ) return -1;
949 /* fake error if write was not atomic */
956 rc
= len
+ sizeof(struct sockaddr_storage
);
961 sb_dgram_close( Sockbuf_IO_Desc
*sbiod
)
963 assert( sbiod
!= NULL
);
964 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
966 if ( sbiod
->sbiod_sb
->sb_fd
!= AC_SOCKET_INVALID
)
967 tcp_close( sbiod
->sbiod_sb
->sb_fd
);
972 sb_dgram_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
974 /* This is an end IO descriptor */
978 Sockbuf_IO ber_sockbuf_io_udp
=
980 sb_dgram_setup
, /* sbi_setup */
981 NULL
, /* sbi_remove */
982 sb_dgram_ctrl
, /* sbi_ctrl */
983 sb_dgram_read
, /* sbi_read */
984 sb_dgram_write
, /* sbi_write */
985 sb_dgram_close
/* sbi_close */
988 #endif /* LDAP_CONNECTIONLESS */