Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

BIO — I/O Abstraction

Types

Bio — owned BIO

Bio is a reference-counted, owned wrapper around an OpenSSL BIO*. It supports synchronous I/O (read/write) and BIO chain management.

#![allow(unused)]
fn main() {
pub struct Bio { /* BIO* */ }

impl Bio {
    /// Create a linked in-memory BIO pair (for in-process TLS).
    pub fn new_pair() -> Result<(Bio, Bio), ErrorStack>;

    // ── I/O ──────────────────────────────────────────────────────────────────

    /// Read up to buf.len() bytes; returns bytes read.
    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>;

    /// Read with exact byte count reported via BIO_read_ex.
    pub fn read_ex(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>;

    /// Write buf; returns bytes written.
    pub fn write(&mut self, buf: &[u8]) -> Result<usize, ErrorStack>;

    // ── Read buffer inspection ───────────────────────────────────────────────

    /// Number of bytes available for reading (BIO_CTRL_PENDING).
    pub fn pending(&self) -> usize;

    /// Number of bytes pending in the write buffer (BIO_CTRL_WPENDING).
    pub fn wpending(&self) -> usize;

    // ── Chain management ─────────────────────────────────────────────────────

    /// Append `next` after `self`; takes ownership of `next`.
    pub fn push(self, next: Bio) -> Bio;

    /// Detach `self` from its chain; return the rest as `Some(Bio)`.
    pub fn pop(&mut self) -> Option<Bio>;

    /// Borrow the next BIO without consuming `self`.
    pub fn next(&self) -> Option<BorrowedBio<'_>>;

    /// Search the chain for the first BIO of the given OpenSSL type constant.
    pub fn find_type(&self, bio_type: c_int) -> Option<BorrowedBio<'_>>;
}
}

BorrowedBio<'a> — non-owning chain view

Returned by Bio::next and Bio::find_type. Does not free the underlying pointer on drop — ownership stays with the chain.

#![allow(unused)]
fn main() {
pub struct BorrowedBio<'a> { /* non-owning BIO* */ }

impl BorrowedBio<'_> {
    pub fn as_ptr(&self) -> *mut BIO;
}
}

MemBio — writable in-memory BIO

Wraps BIO_s_mem(). Data written with write() accumulates in an internal buffer; call data() for a zero-copy &[u8] view.

#![allow(unused)]
fn main() {
pub struct MemBio { /* BIO* */ }

impl MemBio {
    pub fn new() -> Result<Self, ErrorStack>;
    pub fn write(&mut self, data: &[u8]) -> Result<(), ErrorStack>;
    pub fn data(&self) -> &[u8];
    pub fn into_vec(self) -> Vec<u8>;
}
}

MemBioBuf<'a> — read-only view into a slice

Wraps BIO_new_mem_buf(). Zero-copy: OpenSSL reads directly from the caller’s slice. The lifetime 'a prevents the BIO from outliving the slice.

#![allow(unused)]
fn main() {
pub struct MemBioBuf<'a> { /* BIO* + PhantomData<&'a [u8]> */ }

impl<'a> MemBioBuf<'a> {
    pub fn new(data: &'a [u8]) -> Result<Self, ErrorStack>;
}
}

BIO chain ownership model

BIO_push in C transfers ownership of the appended BIO into the chain. In Rust, Bio::push consumes both self and next by value, preventing a double-free:

#![allow(unused)]
fn main() {
let bio1 = /* ... */;
let bio2 = /* ... */;
// bio2 is moved into the chain; do not free it separately.
let chain = bio1.push(bio2);
}

Bio::pop detaches the head from its successor and returns Option<Bio>; the detached tail is now an independent owner.

Bio::next and Bio::find_type return Option<BorrowedBio<'_>> — a borrowed, non-freeing view bounded by the lifetime of the chain head.

BIO_TYPE_* constants

find_type accepts the raw OpenSSL integer type constants, e.g.:

ConstantValueMeaning
BIO_TYPE_MEM8In-memory BIO (BIO_s_mem)
BIO_TYPE_BIO19BIO pair half
BIO_TYPE_SSL7SSL filter BIO

These are available as native_ossl_sys::BIO_TYPE_MEM etc. when using the sys crate directly.

Example

#![allow(unused)]
fn main() {
use native_ossl::bio::Bio;
use native_ossl_sys as sys;

// Create a mem BIO, write, then read back.
let raw = unsafe { sys::BIO_new(sys::BIO_s_mem()) };
let mut bio = unsafe { Bio::from_ptr_owned(raw) };

bio.write(b"hello").unwrap();
let mut buf = [0u8; 8];
let n = bio.read(&mut buf).unwrap();
assert_eq!(&buf[..n], b"hello");

// Chain two BIOs and inspect the link.
let ptr1 = unsafe { sys::BIO_new(sys::BIO_s_mem()) };
let ptr2 = unsafe { sys::BIO_new(sys::BIO_s_mem()) };
let bio1 = unsafe { Bio::from_ptr_owned(ptr1) };
let bio2 = unsafe { Bio::from_ptr_owned(ptr2) };
let raw2 = bio2.as_ptr();
let mut chain = bio1.push(bio2);
assert_eq!(chain.next().unwrap().as_ptr(), raw2);
let _tail = chain.pop(); // detach tail
}