int ber_sockbuf_remove_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer ) { Sockbuf_IO_Desc *p, **q; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); if ( sb->sb_iod == NULL ) { return -1; } q = &sb->sb_iod; while ( *q != NULL ) { p = *q; if ( layer == p->sbiod_level && p->sbiod_io == sbio ) { if ( p->sbiod_io->sbi_remove != NULL && p->sbiod_io->sbi_remove( p ) < 0 ) { return -1; } *q = p->sbiod_next; LBER_FREE( p ); break; } q = &p->sbiod_next; } return 0; }
static ber_slen_t sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; struct sockaddr *dst; socklen_t dstsize; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); dst = buf; buf = (char *) buf + sizeof( struct sockaddr_storage ); len -= sizeof( struct sockaddr_storage ); dstsize = dst->sa_family == AF_INET ? sizeof( struct sockaddr_in ) #ifdef LDAP_PF_INET6 : dst->sa_family == AF_INET6 ? sizeof( struct sockaddr_in6 ) #endif : sizeof( struct sockaddr_storage ); rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, dstsize ); if ( rc < 0 ) return -1; /* fake error if write was not atomic */ if (rc < len) { # ifdef EMSGSIZE errno = EMSGSIZE; # endif return -1; } rc = len + sizeof(struct sockaddr_storage); return rc; }
static ber_slen_t tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = gnutls_record_recv ( p->session->session, buf, len ); switch (ret) { case GNUTLS_E_INTERRUPTED: case GNUTLS_E_AGAIN: sbiod->sbiod_sb->sb_trans_needs_read = 1; sock_errset(EWOULDBLOCK); ret = 0; break; case GNUTLS_E_REHANDSHAKE: for ( ret = gnutls_handshake ( p->session->session ); ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN; ret = gnutls_handshake ( p->session->session ) ); sbiod->sbiod_sb->sb_trans_needs_read = 1; ret = 0; break; default: sbiod->sbiod_sb->sb_trans_needs_read = 0; } return ret; }
ber_slen_t ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) { ber_slen_t ret; assert( buf != NULL ); assert( sb != NULL); assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); for (;;) { ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); #ifdef EINTR if ( ret < 0 ) { #ifdef HAVE_WINSOCK // on Windows, errno is NOT set by send call automatically. if ( (errno = sock_errno()) == WSAEINTR) { errno = EINTR; } #endif if( errno == EINTR ) continue; } #endif break; } return ret; }
static ber_slen_t sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #ifdef LDAP_PF_LOCAL_SENDMSG if ( sbiod->sbiod_sb->sb_ungetlen ) { ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; if ( blen > len ) blen = len; AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); buf = (char *) buf + blen; len -= blen; sbiod->sbiod_sb->sb_ungetlen -= blen; if ( sbiod->sbiod_sb->sb_ungetlen ) { AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, sbiod->sbiod_sb->sb_ungetbuf+blen, sbiod->sbiod_sb->sb_ungetlen ); } if ( len == 0 ) return blen; } #endif return read( sbiod->sbiod_sb->sb_fd, buf, len ); }
static ber_slen_t sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #ifdef LDAP_PF_LOCAL_SENDMSG if ( sbiod->sbiod_sb->sb_ungetlen ) { ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; if ( blen > len ) blen = len; AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); buf = (char *) buf + blen; len -= blen; sbiod->sbiod_sb->sb_ungetlen -= blen; if ( sbiod->sbiod_sb->sb_ungetlen ) { AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, sbiod->sbiod_sb->sb_ungetbuf+blen, sbiod->sbiod_sb->sb_ungetlen ); } if ( len == 0 ) return blen; } #endif return _read( (int)sbiod->sbiod_sb->sb_fd, buf, (unsigned int)len ); // This should be safe, as ret will not exceed 2G. }
ber_slen_t ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out ) { ber_len_t to_go; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); to_go = buf_out->buf_end - buf_out->buf_ptr; assert( to_go > 0 ); for(;;) { ret = LBER_SBIOD_WRITE_NEXT( sbiod, buf_out->buf_base + buf_out->buf_ptr, to_go ); #ifdef EINTR if ((ret<0) && (errno==EINTR)) continue; #endif break; } if ( ret <= 0 ) return ret; buf_out->buf_ptr += ret; if (buf_out->buf_ptr == buf_out->buf_end) { buf_out->buf_end = buf_out->buf_ptr = 0; } return ret; }
static ber_slen_t tlso_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; int err; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = SSL_write( p->session, (char *)buf, len ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif err = SSL_get_error( p->session, ret ); if (err == SSL_ERROR_WANT_WRITE ) { sbiod->sbiod_sb->sb_trans_needs_write = 1; sock_errset(EWOULDBLOCK); } else { sbiod->sbiod_sb->sb_trans_needs_write = 0; } return ret; }
static ber_slen_t sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; struct sockaddr *dst; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); dst = buf; buf = (char *) buf + sizeof( struct sockaddr ); len -= sizeof( struct sockaddr ); rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, sizeof( struct sockaddr ) ); if ( rc < 0 ) return -1; /* fake error if write was not atomic */ if (rc < len) { # ifdef EMSGSIZE errno = EMSGSIZE; # endif return -1; } rc = len + sizeof(struct sockaddr); return rc; }
static int sb_stream_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; }
static ber_slen_t sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); return _write( (int)sbiod->sbiod_sb->sb_fd, buf, (unsigned int)len ); // This should be safe, as ret will not exceed 2G. }
static ber_slen_t sb_fd_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); return write( sbiod->sbiod_sb->sb_fd, buf, len ); }
static int sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( arg != NULL ) sbiod->sbiod_sb->sb_fd = *((int *)arg); return 0; }
void ber_sockbuf_free( Sockbuf *sb ) { assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); ber_int_sb_close( sb ); ber_int_sb_destroy( sb ); LBER_FREE( sb ); }
static int sb_dgram_close( Sockbuf_IO_Desc *sbiod ) { assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); if ( sbiod->sbiod_sb->sb_fd != AC_SOCKET_INVALID ) tcp_close( sbiod->sbiod_sb->sb_fd ); return 0; }
static ber_slen_t sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ #define MAX_WRITE 65535 return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf, (len<MAX_WRITE) ? len : MAX_WRITE ); #elif defined( HAVE_PCNFS) \ || defined( HAVE_WINSOCK) || defined ( __BEOS__ ) /* * PCNFS (under DOS) */ /* * Windows Socket API (under DOS/Windows 3.x) */ /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ { int rc = send( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); #ifdef HAVE_WINSOCK if ( rc < 0 ) { int err; err = WSAGetLastError(); errno = err; } #endif return rc; } #elif defined(HAVE_NCSA) return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); #elif defined(VMS) /* * VMS -- each write must be 64K or smaller */ #define MAX_WRITE 65535 return write( sbiod->sbiod_sb->sb_fd, buf, (len<MAX_WRITE) ? len : MAX_WRITE); #else return write( sbiod->sbiod_sb->sb_fd, buf, len ); #endif }
static ber_slen_t sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, len, NULL ); #elif defined( HAVE_PCNFS ) || \ defined( HAVE_WINSOCK ) || defined ( __BEOS__ ) /* * PCNFS (under DOS) */ /* * Windows Socket API (under DOS/Windows 3.x) */ /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ { int rc; rc = recv( sbiod->sbiod_sb->sb_fd, buf, len, 0 ); #ifdef HAVE_WINSOCK if ( rc < 0 ) { int err; err = WSAGetLastError(); errno = err; } #endif return rc; } #elif defined( HAVE_NCSA ) /* * NCSA Telnet TCP/IP stack (under DOS) */ return nread( sbiod->sbiod_sb->sb_fd, buf, len ); #else return read( sbiod->sbiod_sb->sb_fd, buf, len ); #endif }
int ber_int_sb_init( Sockbuf *sb ) { assert( sb != NULL); sb->sb_valid=LBER_VALID_SOCKBUF; sb->sb_options = 0; sb->sb_debug = ber_int_debug; sb->sb_fd = AC_SOCKET_INVALID; sb->sb_iod = NULL; sb->sb_trans_needs_read = 0; sb->sb_trans_needs_write = 0; assert( SOCKBUF_VALID( sb ) ); return 0; }
int ber_int_sb_destroy( Sockbuf *sb ) { Sockbuf_IO_Desc *p; assert( sb != NULL); assert( SOCKBUF_VALID( sb ) ); while ( sb->sb_iod ) { p = sb->sb_iod->sbiod_next; ber_sockbuf_remove_io( sb, sb->sb_iod->sbiod_io, sb->sb_iod->sbiod_level ); sb->sb_iod = p; } return ber_int_sb_init( sb ); }
ber_slen_t ber_int_sb_read( Sockbuf *sb, void *buf, ber_len_t len ) { ber_slen_t ret; assert( buf != NULL ); assert( sb != NULL); assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); for (;;) { ret = sb->sb_iod->sbiod_io->sbi_read( sb->sb_iod, buf, len ); #ifdef EINTR if ( ret < 0 ) { #ifdef HAVE_WINSOCK // on Windows, errno is NOT set by recv call automatically. if ( (errno = sock_errno()) == WSAEINTR) { errno = EINTR; } #endif if( errno == EINTR ) continue; } #endif break; } #ifdef _WIN32 if (ret <= 0) { DWORD dwLastError = WSAGetLastError(); DWORD dwLevel = LDAP_DEBUG_ANY; if ( dwLastError == WSAETIMEDOUT ) { dwLevel = LDAP_DEBUG_CONNS; } VmLberLog( dwLevel, "sockbuf read return (%d)(%d)", ret, dwLastError); } #endif return ret; }
int ber_flush2( Sockbuf *sb, BerElement *ber, int freeit ) { ber_len_t towrite; ber_slen_t rc; assert( sb != NULL ); assert( ber != NULL ); assert( SOCKBUF_VALID( sb ) ); assert( LBER_VALID( ber ) ); if ( ber->ber_rwptr == NULL ) { ber->ber_rwptr = ber->ber_buf; } towrite = ber->ber_ptr - ber->ber_rwptr; if ( sb->sb_debug ) { ber_log_printf( LDAP_DEBUG_TRACE, sb->sb_debug, "ber_flush2: %ld bytes to sd %ld%s\n", towrite, (long) sb->sb_fd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" ); ber_log_bprint( LDAP_DEBUG_BER, sb->sb_debug, ber->ber_rwptr, towrite ); } while ( towrite > 0 ) { #ifdef LBER_TRICKLE sleep(1); rc = ber_int_sb_write( sb, ber->ber_rwptr, 1 ); #else rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite ); #endif if ( rc <= 0 ) { if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 ); return -1; } towrite -= rc; ber->ber_rwptr += rc; } if ( freeit & LBER_FLUSH_FREE_ON_SUCCESS ) ber_free( ber, 1 ); return 0; }
static ber_slen_t sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; ber_socklen_t addrlen; struct sockaddr *src; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( buf != NULL ); addrlen = sizeof( struct sockaddr ); src = buf; buf = (char *) buf + addrlen; len -= addrlen; rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen ); return rc > 0 ? rc+sizeof(struct sockaddr) : rc; }
static ber_slen_t sb_stream_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ #define MAX_WRITE 65535 return tcpwrite( sbiod->sbiod_sb->sb_fd, (unsigned char *)buf, (len<MAX_WRITE) ? len : MAX_WRITE ); #elif defined( HAVE_PCNFS) \ || defined( HAVE_WINSOCK) || defined ( __BEOS__ ) /* * PCNFS (under DOS) */ /* * Windows Socket API (under DOS/Windows 3.x) */ /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ return send( sbiod->sbiod_sb->sb_fd, (char*)buf, (int)len, 0 );// This should be safe, as ret will not exceed 2G. #elif defined(HAVE_NCSA) return netwrite( sbiod->sbiod_sb->sb_fd, buf, len ); #elif defined(VMS) /* * VMS -- each write must be 64K or smaller */ #define MAX_WRITE 65535 return write( sbiod->sbiod_sb->sb_fd, buf, (len<MAX_WRITE) ? len : MAX_WRITE); #else return write( sbiod->sbiod_sb->sb_fd, buf, len ); #endif }
ber_slen_t ber_int_sb_write( Sockbuf *sb, void *buf, ber_len_t len ) { ber_slen_t ret; assert( buf != NULL ); assert( sb != NULL); assert( sb->sb_iod != NULL ); assert( SOCKBUF_VALID( sb ) ); for (;;) { ret = sb->sb_iod->sbiod_io->sbi_write( sb->sb_iod, buf, len ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif break; } return ret; }
static ber_slen_t sb_rdahead_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { Sockbuf_Buf *p; ber_slen_t bufptr = 0, ret, max; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); assert( sbiod->sbiod_next != NULL ); p = (Sockbuf_Buf *)sbiod->sbiod_pvt; assert( p->buf_size > 0 ); /* Are there anything left in the buffer? */ ret = ber_pvt_sb_copy_out( p, buf, len ); bufptr += ret; len -= ret; if ( len == 0 ) return bufptr; max = p->buf_size - p->buf_end; ret = 0; while ( max > 0 ) { ret = LBER_SBIOD_READ_NEXT( sbiod, p->buf_base + p->buf_end, max ); #ifdef EINTR if ( ( ret < 0 ) && ( errno == EINTR ) ) continue; #endif break; } if ( ret < 0 ) { return ( bufptr ? bufptr : ret ); } p->buf_end += ret; bufptr += ber_pvt_sb_copy_out( p, (char *) buf + bufptr, len ); return bufptr; }
static ber_slen_t tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct tls_data *p; ber_slen_t ret; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct tls_data *)sbiod->sbiod_pvt; ret = gnutls_record_send ( p->session->session, (char *)buf, len ); if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) { sbiod->sbiod_sb->sb_trans_needs_write = 1; sock_errset(EWOULDBLOCK); ret = 0; } else { sbiod->sbiod_sb->sb_trans_needs_write = 0; } return ret; }
int ber_sockbuf_add_io( Sockbuf *sb, Sockbuf_IO *sbio, int layer, void *arg ) { Sockbuf_IO_Desc *d, *p, **q; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); if ( sbio == NULL ) { return -1; } q = &sb->sb_iod; p = *q; while ( p && p->sbiod_level > layer ) { q = &p->sbiod_next; p = *q; } d = LBER_MALLOC( sizeof( *d ) ); if ( d == NULL ) { return -1; } d->sbiod_level = layer; d->sbiod_sb = sb; d->sbiod_io = sbio; memset( &d->sbiod_pvt, '\0', sizeof( d->sbiod_pvt ) ); d->sbiod_next = p; *q = d; if ( sbio->sbi_setup != NULL && ( sbio->sbi_setup( d, arg ) < 0 ) ) { return -1; } return 0; }
static ber_slen_t sb_stream_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); #if defined(MACOS) /* * MacTCP/OpenTransport */ return tcpread( sbiod->sbiod_sb->sb_fd, 0, (unsigned char *)buf, len, NULL ); #elif defined( HAVE_PCNFS ) || \ defined( HAVE_WINSOCK ) || defined ( __BEOS__ ) /* * PCNFS (under DOS) */ /* * Windows Socket API (under DOS/Windows 3.x) */ /* * 32-bit Windows Socket API (under Windows NT or Windows 95) */ return recv( sbiod->sbiod_sb->sb_fd, (char*)buf, (int)len, 0 ); // This should be safe, as ret will not exceed 2G. #elif defined( HAVE_NCSA ) /* * NCSA Telnet TCP/IP stack (under DOS) */ return nread( sbiod->sbiod_sb->sb_fd, buf, len ); #else return read( sbiod->sbiod_sb->sb_fd, buf, len ); #endif }
/* Return values: -1: error, 0: no operation performed or the answer is false, * 1: successful operation or the answer is true */ int ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) { Sockbuf_IO_Desc *p; int ret = 0; assert( sb != NULL ); assert( SOCKBUF_VALID( sb ) ); switch ( opt ) { case LBER_SB_OPT_HAS_IO: p = sb->sb_iod; while ( p && p->sbiod_io != (Sockbuf_IO *)arg ) { p = p->sbiod_next; } if ( p ) { ret = 1; } break; case LBER_SB_OPT_GET_FD: if ( arg != NULL ) { *((ber_socket_t *)arg) = sb->sb_fd; } ret = ( sb->sb_fd == AC_SOCKET_INVALID ? -1 : 1); break; case LBER_SB_OPT_SET_FD: sb->sb_fd = *((ber_socket_t *)arg); ret = 1; break; case LBER_SB_OPT_SET_NONBLOCK: ret = ber_pvt_socket_set_nonblock( sb->sb_fd, arg != NULL) ? -1 : 1; break; case LBER_SB_OPT_DRAIN: { /* Drain the data source to enable possible errors (e.g. * TLS) to be propagated to the upper layers */ char buf[LBER_MIN_BUFF_SIZE]; do { ret = ber_int_sb_read( sb, buf, sizeof( buf ) ); } while ( ret == sizeof( buf ) ); ret = 1; } break; case LBER_SB_OPT_NEEDS_READ: ret = ( sb->sb_trans_needs_read ? 1 : 0 ); break; case LBER_SB_OPT_NEEDS_WRITE: ret = ( sb->sb_trans_needs_write ? 1 : 0 ); break; case LBER_SB_OPT_GET_MAX_INCOMING: if ( arg != NULL ) { *((ber_len_t *)arg) = sb->sb_max_incoming; } ret = 1; break; case LBER_SB_OPT_SET_MAX_INCOMING: sb->sb_max_incoming = *((ber_len_t *)arg); ret = 1; break; case LBER_SB_OPT_UNGET_BUF: #ifdef LDAP_PF_LOCAL_SENDMSG sb->sb_ungetlen = ((struct berval *)arg)->bv_len; if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) { AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val, sb->sb_ungetlen ); ret = 1; } else { sb->sb_ungetlen = 0; ret = -1; } #endif break; default: ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg ); break; } return ret; }
static ber_slen_t sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct sb_sasl_generic_data *p; int ret; ber_len_t len2; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; /* Is there anything left in the buffer? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); if ( ret < 0 ) return ret; /* Still have something left?? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { sock_errset(EAGAIN); return -1; } } len2 = p->max_send - 100; /* For safety margin */ len2 = len > len2 ? len2 : len; /* If we're just retrying a partial write, tell the * caller it's done. Let them call again if there's * still more left to write. */ if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) { p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE; return len2; } /* now encode the next packet. */ p->ops->reset_buf( p, &p->buf_out ); ret = p->ops->encode( p, buf, len2, &p->buf_out ); if ( ret != 0 ) { ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, "sb_sasl_generic_write: failed to encode packet\n" ); sock_errset(EIO); return -1; } ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); if ( ret < 0 ) { /* error? */ int err = sock_errno(); /* caller can retry this */ if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR ) p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; return ret; } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { /* partial write? pretend nothing got written */ p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; sock_errset(EAGAIN); len2 = -1; } /* return number of bytes encoded, not written, to ensure * no byte is encoded twice (even if only sent once). */ return len2; }