1 /* sockbuf.c - i/o routines with support for adding i/o layers. */
4 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
12 #include <ac/stdlib.h>
16 #include <ac/socket.h>
17 #include <ac/string.h>
18 #include <ac/unistd.h>
22 #endif /* HAVE_IO_H */
24 #if defined( HAVE_FCNTL_H )
28 #if defined( HAVE_SYS_FILIO_H )
29 #include <sys/filio.h>
30 #elif defined( HAVE_SYS_IOCTL_H )
31 #include <sys/ioctl.h>
36 #define MIN_BUFF_SIZE 4096
37 #define MAX_BUFF_SIZE 65536
38 #define DEFAULT_READAHEAD 16384
41 ber_sockbuf_alloc( void )
45 ber_int_options.lbo_valid = LBER_INITIALIZED;
47 sb = LBER_CALLOC( 1, sizeof( Sockbuf ) );
49 if( sb == NULL ) return NULL;
51 ber_int_sb_init( sb );
56 ber_sockbuf_free( Sockbuf *sb )
59 assert( SOCKBUF_VALID( sb ) );
61 ber_int_sb_close( sb );
62 ber_int_sb_destroy( sb );
66 /* Return values: -1: error, 0: no operation performed or the answer is false,
67 * 1: successful operation or the answer is true
70 ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg )
78 case LBER_SB_OPT_HAS_IO:
80 while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) {
89 case LBER_SB_OPT_GET_FD:
91 *((int *)arg) = sb->sb_fd;
93 ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1);
96 case LBER_SB_OPT_SET_FD:
97 sb->sb_fd = *((int *)arg);
101 case LBER_SB_OPT_SET_NONBLOCK:
102 ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL)
106 case LBER_SB_OPT_DRAIN: {
107 /* Drain the data source to enable possible errors (e.g.
108 * TLS) to be propagated to the upper layers
110 char buf[MIN_BUFF_SIZE];
113 ret = ber_int_sb_read( sb, buf, sizeof( buf ) );
114 } while ( ret == sizeof( buf ) );
119 case LBER_SB_OPT_NEEDS_READ:
120 ret = ( sb->sb_trans_needs_read ? 1 : 0 );
123 case LBER_SB_OPT_NEEDS_WRITE:
124 ret = ( sb->sb_trans_needs_write ? 1 : 0 );
128 ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod,
137 ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg )
139 Sockbuf_IO_Desc *d, *p, **q;
141 assert( sb != NULL );
142 assert( SOCKBUF_VALID( sb ) );
144 if ( sbio == NULL ) {
150 while ( p && p->sbiod_level > layer ) {
155 d = LBER_MALLOC( sizeof( *d ) );
160 d->sbiod_level = layer;
163 memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) );
167 if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) {
175 ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer )
177 Sockbuf_IO_Desc *p, **q;
179 assert( sb != NULL );
180 assert( SOCKBUF_VALID( sb ) );
182 if ( sb->sb_iod == NULL ) {
187 while ( *q != NULL ) {
189 if ( layer == p->sbiod_level && p->sbiod_io == sbio ) {
190 if ( p->sbiod_io->sbi_remove != NULL &&
191 p->sbiod_io->sbi_remove( p ) < 0 )
206 ber_pvt_sb_buf_init( Sockbuf_Buf *buf )
208 buf->buf_base = NULL;
215 ber_pvt_sb_buf_destroy( Sockbuf_Buf *buf )
217 assert( buf != NULL);
220 LBER_FREE( buf->buf_base );
222 ber_pvt_sb_buf_init( buf );
226 ber_pvt_sb_grow_buffer( Sockbuf_Buf *buf, ber_len_t minsize )
231 assert( buf != NULL );
233 for ( pw = MIN_BUFF_SIZE; pw < minsize; pw <<= 1 ) {
234 if (pw > MAX_BUFF_SIZE) return -1;
237 if ( buf->buf_size < pw ) {
238 p = LBER_REALLOC( buf->buf_base, pw );
239 if ( p == NULL ) return -1;
247 ber_pvt_sb_copy_out( Sockbuf_Buf *sbb, char *buf, ber_len_t len )
251 assert( buf != NULL );
252 assert( sbb != NULL );
254 assert( sbb->buf_size > 0 );
257 max = sbb->buf_end - sbb->buf_ptr;
258 max = ( max < len) ? max : len;
260 AC_MEMCPY( buf, sbb->buf_base + sbb->buf_ptr, max );
262 if ( sbb->buf_ptr >= sbb->buf_end ) {
263 sbb->buf_ptr = sbb->buf_end = 0;
270 ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out )
275 assert( sbiod != NULL );
276 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
278 to_go = buf_out->buf_end - buf_out->buf_ptr;
282 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base +
283 buf_out->buf_ptr, to_go );
285 if ((ret<0) && (errno==EINTR)) continue;
290 if ( ret <= 0 ) return ret;
292 buf_out->buf_ptr += ret;
293 if (buf_out->buf_ptr == buf_out->buf_end) {
294 buf_out->buf_end = buf_out->buf_ptr = 0;
297 if ( (ber_len_t)ret < to_go ) {
298 /* not enough data, so pretend no data was sent. */
306 ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb )
309 int flags = fcntl( sd, F_GETFL);
313 flags &= ~O_NONBLOCK;
315 return fcntl( sd, F_SETFL, flags );
317 #elif defined( FIONBIO )
318 ioctl_t status = nb ? 1 : 0;
319 return ioctl( sd, FIONBIO, &status );
324 ber_int_sb_init( Sockbuf *sb )
328 sb->sb_valid=LBER_VALID_SOCKBUF;
330 sb->sb_debug = ber_int_debug;
331 sb->sb_fd = AC_SOCKET_INVALID;
333 sb->sb_trans_needs_read = 0;
334 sb->sb_trans_needs_write = 0;
336 assert( SOCKBUF_VALID( sb ) );
341 ber_int_sb_close( Sockbuf *sb )
349 if ( p->sbiod_io->sbi_close &&
350 p->sbiod_io->sbi_close( p ) < 0 )
357 sb->sb_fd = AC_SOCKET_INVALID;
363 ber_int_sb_destroy( Sockbuf *sb )
368 assert( SOCKBUF_VALID( sb ) );
370 while ( sb->sb_iod ) {
371 p = sb->sb_iod->sbiod_next;
372 ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io,
373 sb->sb_iod->sbiod_level );
377 return ber_int_sb_init( sb );
381 ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len )
385 assert( buf != NULL );
387 assert( sb->sb_iod != NULL );
388 assert( SOCKBUF_VALID( sb ) );
391 ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len );
394 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
403 ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len )
407 assert( buf != NULL );
409 assert( sb->sb_iod != NULL );
410 assert( SOCKBUF_VALID( sb ) );
413 ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len );
416 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
429 sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
431 assert( sbiod != NULL);
432 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
436 * MacTCP/OpenTransport
438 return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf,
441 #elif defined( HAVE_PCNFS ) || \
442 defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
447 * Windows Socket API (under DOS/Windows 3.x)
450 * 32-bit Windows Socket API (under Windows NT or Windows 95)
455 rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
461 err = WSAGetLastError();
469 #elif defined( HAVE_NCSA )
471 * NCSA Telnet TCP/IP stack (under DOS)
473 return nread( sbiod->sbiod_sb->sb_fd, buf, len );
476 return read( sbiod->sbiod_sb->sb_fd, buf, len );
481 sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
483 assert( sbiod != NULL);
484 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
488 * MacTCP/OpenTransport
490 #define MAX_WRITE 65535
491 return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf,
492 (len<MAX_WRITE) ? len : MAX_WRITE );
494 #elif defined( HAVE_PCNFS) \
495 || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
500 * Windows Socket API (under DOS/Windows 3.x)
503 * 32-bit Windows Socket API (under Windows NT or Windows 95)
506 int rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 );
511 err = WSAGetLastError();
518 #elif defined(HAVE_NCSA)
519 return netwrite( sbiod->sbiod_sb->sb_fd, buf, len );
523 * VMS -- each write must be 64K or smaller
525 #define MAX_WRITE 65535
526 return write( sbiod->sbiod_sb->sb_fd, buf,
527 (len<MAX_WRITE) ? len : MAX_WRITE);
529 return write( sbiod->sbiod_sb->sb_fd, buf, len );
534 sb_stream_close( Sockbuf_IO_Desc *sbiod )
536 assert( sbiod != NULL );
537 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
538 tcp_close( sbiod->sbiod_sb->sb_fd );
542 /* The argument is a pointer to the socket descriptor */
544 sb_stream_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
545 assert( sbiod != NULL );
548 sbiod->sbiod_sb->sb_fd = *((int *)arg);
554 sb_stream_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
555 /* This is an end IO descriptor */
559 Sockbuf_IO ber_sockbuf_io_tcp = {
560 sb_stream_setup, /* sbi_setup */
561 NULL, /* sbi_remove */
562 sb_stream_ctrl, /* sbi_ctrl */
563 sb_stream_read, /* sbi_read */
564 sb_stream_write, /* sbi_write */
565 sb_stream_close /* sbi_close */
570 * Support for readahead (UDP needs it)
574 sb_rdahead_setup( Sockbuf_IO_Desc *sbiod, void *arg )
578 assert( sbiod != NULL );
580 p = LBER_MALLOC( sizeof( *p ) );
581 if ( p == NULL ) return -1;
583 ber_pvt_sb_buf_init( p );
586 ber_pvt_sb_grow_buffer( p, DEFAULT_READAHEAD );
588 ber_pvt_sb_grow_buffer( p, *((int *)arg) );
591 sbiod->sbiod_pvt = p;
596 sb_rdahead_remove( Sockbuf_IO_Desc *sbiod )
600 assert( sbiod != NULL );
602 p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
604 if ( p->buf_ptr != p->buf_end ) return -1;
606 ber_pvt_sb_buf_destroy( (Sockbuf_Buf *)(sbiod->sbiod_pvt) );
607 LBER_FREE( sbiod->sbiod_pvt );
608 sbiod->sbiod_pvt = NULL;
614 sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
617 ber_slen_t bufptr = 0, ret, max;
619 assert( sbiod != NULL );
620 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
621 assert( sbiod->sbiod_next != NULL );
623 p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
625 assert( p->buf_size > 0 );
627 /* Are there anything left in the buffer? */
628 ret = ber_pvt_sb_copy_out( p, buf, len );
632 if ( len == 0 ) return bufptr;
634 max = p->buf_size - p->buf_end;
637 ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end,
640 if ( ( ret < 0 ) && ( errno == EINTR ) ) continue;
646 return ( bufptr ? bufptr : ret );
650 bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len );
655 sb_rdahead_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
657 assert( sbiod != NULL );
658 assert( sbiod->sbiod_next != NULL );
660 return LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
664 sb_rdahead_close( Sockbuf_IO_Desc *sbiod )
666 assert( sbiod != NULL );
668 /* Just erase the buffer */
669 ber_pvt_sb_buf_destroy((Sockbuf_Buf *)sbiod->sbiod_pvt);
674 sb_rdahead_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
678 p = (Sockbuf_Buf *)sbiod->sbiod_pvt;
680 if ( opt == LBER_SB_OPT_DATA_READY ) {
681 if ( p->buf_ptr != p->buf_end ) {
685 } else if ( opt == LBER_SB_OPT_SET_READAHEAD ) {
686 if ( p->buf_size >= *((ber_len_t *)arg) ) {
689 return ( ber_pvt_sb_grow_buffer( p, *((int *)arg) ) ?
693 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
696 Sockbuf_IO ber_sockbuf_io_readahead = {
697 sb_rdahead_setup, /* sbi_setup */
698 sb_rdahead_remove, /* sbi_remove */
699 sb_rdahead_ctrl, /* sbi_ctrl */
700 sb_rdahead_read, /* sbi_read */
701 sb_rdahead_write, /* sbi_write */
702 sb_rdahead_close /* sbi_close */
706 * Support for simple file IO
710 sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
712 assert( sbiod != NULL);
713 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
715 return read( sbiod->sbiod_sb->sb_fd, buf, len );
719 sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
721 assert( sbiod != NULL);
722 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
724 return write( sbiod->sbiod_sb->sb_fd, buf, len );
728 sb_fd_close( Sockbuf_IO_Desc *sbiod )
730 assert( sbiod != NULL );
731 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
733 close( sbiod->sbiod_sb->sb_fd );
737 /* The argument is a pointer to the file descriptor */
739 sb_fd_setup( Sockbuf_IO_Desc *sbiod, void *arg ) {
740 assert( sbiod != NULL );
743 sbiod->sbiod_sb->sb_fd = *((int *)arg);
748 sb_fd_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) {
749 /* This is an end IO descriptor */
753 Sockbuf_IO ber_sockbuf_io_fd = {
754 sb_fd_setup, /* sbi_setup */
755 NULL, /* sbi_remove */
756 sb_fd_ctrl, /* sbi_ctrl */
757 sb_fd_read, /* sbi_read */
758 sb_fd_write, /* sbi_write */
759 sb_fd_close /* sbi_close */
767 sb_debug_setup( Sockbuf_IO_Desc *sbiod, void *arg )
769 assert( sbiod != NULL );
771 if ( arg == NULL ) arg = "sockbuf_";
773 sbiod->sbiod_pvt = LBER_MALLOC( strlen( arg ) + 1 );
774 if ( sbiod->sbiod_pvt == NULL ) return -1;
776 strcpy( (char *)sbiod->sbiod_pvt, (char *)arg );
781 sb_debug_remove( Sockbuf_IO_Desc *sbiod )
783 assert( sbiod != NULL );
784 assert( sbiod->sbiod_pvt != NULL );
786 LBER_FREE( sbiod->sbiod_pvt );
787 sbiod->sbiod_pvt = NULL;
792 sb_debug_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
794 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
798 sb_debug_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
802 ret = LBER_SBIOD_READ_NEXT( sbiod, buf, len );
804 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
805 "%sread: want=%ld error=%s\n", (char *)sbiod->sbiod_pvt,
806 (long)len, STRERROR( errno ) );
809 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
810 "%sread: want=%ld, got=%ld\n", (char *)sbiod->sbiod_pvt,
811 (long)len, (long)ret );
812 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
813 (const char *)buf, ret );
819 sb_debug_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
823 ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf, len );
825 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
826 "%swrite: want=%ld error=%s\n",
827 (char *)sbiod->sbiod_pvt, (long)len,
831 ber_log_printf( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
832 "%swrite: want=%ld, written=%ld\n",
833 (char *)sbiod->sbiod_pvt, (long)len, (long)ret );
834 ber_log_bprint( LDAP_DEBUG_PACKETS, sbiod->sbiod_sb->sb_debug,
835 (const char *)buf, ret );
841 Sockbuf_IO ber_sockbuf_io_debug = {
842 sb_debug_setup, /* sbi_setup */
843 sb_debug_remove, /* sbi_remove */
844 sb_debug_ctrl, /* sbi_ctrl */
845 sb_debug_read, /* sbi_read */
846 sb_debug_write, /* sbi_write */