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.:
| Constant | Value | Meaning |
|---|---|---|
BIO_TYPE_MEM | 8 | In-memory BIO (BIO_s_mem) |
BIO_TYPE_BIO | 19 | BIO pair half |
BIO_TYPE_SSL | 7 | SSL 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
}