192f3ab15Sopenharmony_ciuse cfg_if::cfg_if;
292f3ab15Sopenharmony_ciuse ffi::{
392f3ab15Sopenharmony_ci    self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO,
492f3ab15Sopenharmony_ci    BIO_CTRL_DGRAM_QUERY_MTU, BIO_CTRL_FLUSH,
592f3ab15Sopenharmony_ci};
692f3ab15Sopenharmony_ciuse libc::{c_char, c_int, c_long, c_void, strlen};
792f3ab15Sopenharmony_ciuse std::any::Any;
892f3ab15Sopenharmony_ciuse std::io;
992f3ab15Sopenharmony_ciuse std::io::prelude::*;
1092f3ab15Sopenharmony_ciuse std::panic::{catch_unwind, AssertUnwindSafe};
1192f3ab15Sopenharmony_ciuse std::ptr;
1292f3ab15Sopenharmony_ciuse std::slice;
1392f3ab15Sopenharmony_ci
1492f3ab15Sopenharmony_ciuse crate::cvt_p;
1592f3ab15Sopenharmony_ciuse crate::error::ErrorStack;
1692f3ab15Sopenharmony_ci
1792f3ab15Sopenharmony_cipub struct StreamState<S> {
1892f3ab15Sopenharmony_ci    pub stream: S,
1992f3ab15Sopenharmony_ci    pub error: Option<io::Error>,
2092f3ab15Sopenharmony_ci    pub panic: Option<Box<dyn Any + Send>>,
2192f3ab15Sopenharmony_ci    pub dtls_mtu_size: c_long,
2292f3ab15Sopenharmony_ci}
2392f3ab15Sopenharmony_ci
2492f3ab15Sopenharmony_ci/// Safe wrapper for `BIO_METHOD`
2592f3ab15Sopenharmony_cipub struct BioMethod(BIO_METHOD);
2692f3ab15Sopenharmony_ci
2792f3ab15Sopenharmony_ciimpl BioMethod {
2892f3ab15Sopenharmony_ci    fn new<S: Read + Write>() -> Result<BioMethod, ErrorStack> {
2992f3ab15Sopenharmony_ci        BIO_METHOD::new::<S>().map(BioMethod)
3092f3ab15Sopenharmony_ci    }
3192f3ab15Sopenharmony_ci}
3292f3ab15Sopenharmony_ci
3392f3ab15Sopenharmony_ciunsafe impl Sync for BioMethod {}
3492f3ab15Sopenharmony_ciunsafe impl Send for BioMethod {}
3592f3ab15Sopenharmony_ci
3692f3ab15Sopenharmony_cipub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
3792f3ab15Sopenharmony_ci    let method = BioMethod::new::<S>()?;
3892f3ab15Sopenharmony_ci
3992f3ab15Sopenharmony_ci    let state = Box::new(StreamState {
4092f3ab15Sopenharmony_ci        stream,
4192f3ab15Sopenharmony_ci        error: None,
4292f3ab15Sopenharmony_ci        panic: None,
4392f3ab15Sopenharmony_ci        dtls_mtu_size: 0,
4492f3ab15Sopenharmony_ci    });
4592f3ab15Sopenharmony_ci
4692f3ab15Sopenharmony_ci    unsafe {
4792f3ab15Sopenharmony_ci        let bio = cvt_p(BIO_new(method.0.get()))?;
4892f3ab15Sopenharmony_ci        BIO_set_data(bio, Box::into_raw(state) as *mut _);
4992f3ab15Sopenharmony_ci        BIO_set_init(bio, 1);
5092f3ab15Sopenharmony_ci
5192f3ab15Sopenharmony_ci        Ok((bio, method))
5292f3ab15Sopenharmony_ci    }
5392f3ab15Sopenharmony_ci}
5492f3ab15Sopenharmony_ci
5592f3ab15Sopenharmony_cipub unsafe fn take_error<S>(bio: *mut BIO) -> Option<io::Error> {
5692f3ab15Sopenharmony_ci    let state = state::<S>(bio);
5792f3ab15Sopenharmony_ci    state.error.take()
5892f3ab15Sopenharmony_ci}
5992f3ab15Sopenharmony_ci
6092f3ab15Sopenharmony_cipub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<dyn Any + Send>> {
6192f3ab15Sopenharmony_ci    let state = state::<S>(bio);
6292f3ab15Sopenharmony_ci    state.panic.take()
6392f3ab15Sopenharmony_ci}
6492f3ab15Sopenharmony_ci
6592f3ab15Sopenharmony_cipub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S {
6692f3ab15Sopenharmony_ci    let state = &*(BIO_get_data(bio) as *const StreamState<S>);
6792f3ab15Sopenharmony_ci    &state.stream
6892f3ab15Sopenharmony_ci}
6992f3ab15Sopenharmony_ci
7092f3ab15Sopenharmony_cipub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S {
7192f3ab15Sopenharmony_ci    &mut state(bio).stream
7292f3ab15Sopenharmony_ci}
7392f3ab15Sopenharmony_ci
7492f3ab15Sopenharmony_cipub unsafe fn set_dtls_mtu_size<S>(bio: *mut BIO, mtu_size: usize) {
7592f3ab15Sopenharmony_ci    if mtu_size as u64 > c_long::max_value() as u64 {
7692f3ab15Sopenharmony_ci        panic!(
7792f3ab15Sopenharmony_ci            "Given MTU size {} can't be represented in a positive `c_long` range",
7892f3ab15Sopenharmony_ci            mtu_size
7992f3ab15Sopenharmony_ci        )
8092f3ab15Sopenharmony_ci    }
8192f3ab15Sopenharmony_ci    state::<S>(bio).dtls_mtu_size = mtu_size as c_long;
8292f3ab15Sopenharmony_ci}
8392f3ab15Sopenharmony_ci
8492f3ab15Sopenharmony_ciunsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
8592f3ab15Sopenharmony_ci    &mut *(BIO_get_data(bio) as *mut _)
8692f3ab15Sopenharmony_ci}
8792f3ab15Sopenharmony_ci
8892f3ab15Sopenharmony_ciunsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
8992f3ab15Sopenharmony_ci    BIO_clear_retry_flags(bio);
9092f3ab15Sopenharmony_ci
9192f3ab15Sopenharmony_ci    let state = state::<S>(bio);
9292f3ab15Sopenharmony_ci    let buf = slice::from_raw_parts(buf as *const _, len as usize);
9392f3ab15Sopenharmony_ci
9492f3ab15Sopenharmony_ci    match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) {
9592f3ab15Sopenharmony_ci        Ok(Ok(len)) => len as c_int,
9692f3ab15Sopenharmony_ci        Ok(Err(err)) => {
9792f3ab15Sopenharmony_ci            if retriable_error(&err) {
9892f3ab15Sopenharmony_ci                BIO_set_retry_write(bio);
9992f3ab15Sopenharmony_ci            }
10092f3ab15Sopenharmony_ci            state.error = Some(err);
10192f3ab15Sopenharmony_ci            -1
10292f3ab15Sopenharmony_ci        }
10392f3ab15Sopenharmony_ci        Err(err) => {
10492f3ab15Sopenharmony_ci            state.panic = Some(err);
10592f3ab15Sopenharmony_ci            -1
10692f3ab15Sopenharmony_ci        }
10792f3ab15Sopenharmony_ci    }
10892f3ab15Sopenharmony_ci}
10992f3ab15Sopenharmony_ci
11092f3ab15Sopenharmony_ciunsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
11192f3ab15Sopenharmony_ci    BIO_clear_retry_flags(bio);
11292f3ab15Sopenharmony_ci
11392f3ab15Sopenharmony_ci    let state = state::<S>(bio);
11492f3ab15Sopenharmony_ci    let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize);
11592f3ab15Sopenharmony_ci
11692f3ab15Sopenharmony_ci    match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) {
11792f3ab15Sopenharmony_ci        Ok(Ok(len)) => len as c_int,
11892f3ab15Sopenharmony_ci        Ok(Err(err)) => {
11992f3ab15Sopenharmony_ci            if retriable_error(&err) {
12092f3ab15Sopenharmony_ci                BIO_set_retry_read(bio);
12192f3ab15Sopenharmony_ci            }
12292f3ab15Sopenharmony_ci            state.error = Some(err);
12392f3ab15Sopenharmony_ci            -1
12492f3ab15Sopenharmony_ci        }
12592f3ab15Sopenharmony_ci        Err(err) => {
12692f3ab15Sopenharmony_ci            state.panic = Some(err);
12792f3ab15Sopenharmony_ci            -1
12892f3ab15Sopenharmony_ci        }
12992f3ab15Sopenharmony_ci    }
13092f3ab15Sopenharmony_ci}
13192f3ab15Sopenharmony_ci
13292f3ab15Sopenharmony_ci#[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0
13392f3ab15Sopenharmony_cifn retriable_error(err: &io::Error) -> bool {
13492f3ab15Sopenharmony_ci    match err.kind() {
13592f3ab15Sopenharmony_ci        io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true,
13692f3ab15Sopenharmony_ci        _ => false,
13792f3ab15Sopenharmony_ci    }
13892f3ab15Sopenharmony_ci}
13992f3ab15Sopenharmony_ci
14092f3ab15Sopenharmony_ciunsafe extern "C" fn bputs<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int {
14192f3ab15Sopenharmony_ci    bwrite::<S>(bio, s, strlen(s) as c_int)
14292f3ab15Sopenharmony_ci}
14392f3ab15Sopenharmony_ci
14492f3ab15Sopenharmony_ciunsafe extern "C" fn ctrl<S: Write>(
14592f3ab15Sopenharmony_ci    bio: *mut BIO,
14692f3ab15Sopenharmony_ci    cmd: c_int,
14792f3ab15Sopenharmony_ci    _num: c_long,
14892f3ab15Sopenharmony_ci    _ptr: *mut c_void,
14992f3ab15Sopenharmony_ci) -> c_long {
15092f3ab15Sopenharmony_ci    let state = state::<S>(bio);
15192f3ab15Sopenharmony_ci
15292f3ab15Sopenharmony_ci    if cmd == BIO_CTRL_FLUSH {
15392f3ab15Sopenharmony_ci        match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) {
15492f3ab15Sopenharmony_ci            Ok(Ok(())) => 1,
15592f3ab15Sopenharmony_ci            Ok(Err(err)) => {
15692f3ab15Sopenharmony_ci                state.error = Some(err);
15792f3ab15Sopenharmony_ci                0
15892f3ab15Sopenharmony_ci            }
15992f3ab15Sopenharmony_ci            Err(err) => {
16092f3ab15Sopenharmony_ci                state.panic = Some(err);
16192f3ab15Sopenharmony_ci                0
16292f3ab15Sopenharmony_ci            }
16392f3ab15Sopenharmony_ci        }
16492f3ab15Sopenharmony_ci    } else if cmd == BIO_CTRL_DGRAM_QUERY_MTU {
16592f3ab15Sopenharmony_ci        state.dtls_mtu_size
16692f3ab15Sopenharmony_ci    } else {
16792f3ab15Sopenharmony_ci        0
16892f3ab15Sopenharmony_ci    }
16992f3ab15Sopenharmony_ci}
17092f3ab15Sopenharmony_ci
17192f3ab15Sopenharmony_ciunsafe extern "C" fn create(bio: *mut BIO) -> c_int {
17292f3ab15Sopenharmony_ci    BIO_set_init(bio, 0);
17392f3ab15Sopenharmony_ci    BIO_set_num(bio, 0);
17492f3ab15Sopenharmony_ci    BIO_set_data(bio, ptr::null_mut());
17592f3ab15Sopenharmony_ci    BIO_set_flags(bio, 0);
17692f3ab15Sopenharmony_ci    1
17792f3ab15Sopenharmony_ci}
17892f3ab15Sopenharmony_ci
17992f3ab15Sopenharmony_ciunsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
18092f3ab15Sopenharmony_ci    if bio.is_null() {
18192f3ab15Sopenharmony_ci        return 0;
18292f3ab15Sopenharmony_ci    }
18392f3ab15Sopenharmony_ci
18492f3ab15Sopenharmony_ci    let data = BIO_get_data(bio);
18592f3ab15Sopenharmony_ci    assert!(!data.is_null());
18692f3ab15Sopenharmony_ci    let _ = Box::<StreamState<S>>::from_raw(data as *mut _);
18792f3ab15Sopenharmony_ci    BIO_set_data(bio, ptr::null_mut());
18892f3ab15Sopenharmony_ci    BIO_set_init(bio, 0);
18992f3ab15Sopenharmony_ci    1
19092f3ab15Sopenharmony_ci}
19192f3ab15Sopenharmony_ci
19292f3ab15Sopenharmony_cicfg_if! {
19392f3ab15Sopenharmony_ci    if #[cfg(any(ossl110, libressl273))] {
19492f3ab15Sopenharmony_ci        use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init};
19592f3ab15Sopenharmony_ci        use crate::cvt;
19692f3ab15Sopenharmony_ci
19792f3ab15Sopenharmony_ci        #[allow(bad_style)]
19892f3ab15Sopenharmony_ci        unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
19992f3ab15Sopenharmony_ci
20092f3ab15Sopenharmony_ci        #[allow(bad_style, clippy::upper_case_acronyms)]
20192f3ab15Sopenharmony_ci        struct BIO_METHOD(*mut ffi::BIO_METHOD);
20292f3ab15Sopenharmony_ci
20392f3ab15Sopenharmony_ci        impl BIO_METHOD {
20492f3ab15Sopenharmony_ci            fn new<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
20592f3ab15Sopenharmony_ci                unsafe {
20692f3ab15Sopenharmony_ci                    let ptr = cvt_p(ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _))?;
20792f3ab15Sopenharmony_ci                    let method = BIO_METHOD(ptr);
20892f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_write__fixed_rust(method.0, Some(bwrite::<S>)))?;
20992f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_read__fixed_rust(method.0, Some(bread::<S>)))?;
21092f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_puts__fixed_rust(method.0, Some(bputs::<S>)))?;
21192f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_ctrl__fixed_rust(method.0, Some(ctrl::<S>)))?;
21292f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_create__fixed_rust(method.0, Some(create)))?;
21392f3ab15Sopenharmony_ci                    cvt(ffi::BIO_meth_set_destroy__fixed_rust(method.0, Some(destroy::<S>)))?;
21492f3ab15Sopenharmony_ci                    Ok(method)
21592f3ab15Sopenharmony_ci                }
21692f3ab15Sopenharmony_ci            }
21792f3ab15Sopenharmony_ci
21892f3ab15Sopenharmony_ci            fn get(&self) -> *mut ffi::BIO_METHOD {
21992f3ab15Sopenharmony_ci                self.0
22092f3ab15Sopenharmony_ci            }
22192f3ab15Sopenharmony_ci        }
22292f3ab15Sopenharmony_ci
22392f3ab15Sopenharmony_ci        impl Drop for BIO_METHOD {
22492f3ab15Sopenharmony_ci            fn drop(&mut self) {
22592f3ab15Sopenharmony_ci                unsafe {
22692f3ab15Sopenharmony_ci                    ffi::BIO_meth_free(self.0);
22792f3ab15Sopenharmony_ci                }
22892f3ab15Sopenharmony_ci            }
22992f3ab15Sopenharmony_ci        }
23092f3ab15Sopenharmony_ci    } else {
23192f3ab15Sopenharmony_ci        #[allow(bad_style, clippy::upper_case_acronyms)]
23292f3ab15Sopenharmony_ci        struct BIO_METHOD(*mut ffi::BIO_METHOD);
23392f3ab15Sopenharmony_ci
23492f3ab15Sopenharmony_ci        impl BIO_METHOD {
23592f3ab15Sopenharmony_ci            fn new<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
23692f3ab15Sopenharmony_ci                let ptr = Box::new(ffi::BIO_METHOD {
23792f3ab15Sopenharmony_ci                    type_: ffi::BIO_TYPE_NONE,
23892f3ab15Sopenharmony_ci                    name: b"rust\0".as_ptr() as *const _,
23992f3ab15Sopenharmony_ci                    bwrite: Some(bwrite::<S>),
24092f3ab15Sopenharmony_ci                    bread: Some(bread::<S>),
24192f3ab15Sopenharmony_ci                    bputs: Some(bputs::<S>),
24292f3ab15Sopenharmony_ci                    bgets: None,
24392f3ab15Sopenharmony_ci                    ctrl: Some(ctrl::<S>),
24492f3ab15Sopenharmony_ci                    create: Some(create),
24592f3ab15Sopenharmony_ci                    destroy: Some(destroy::<S>),
24692f3ab15Sopenharmony_ci                    callback_ctrl: None,
24792f3ab15Sopenharmony_ci                });
24892f3ab15Sopenharmony_ci
24992f3ab15Sopenharmony_ci                Ok(BIO_METHOD(Box::into_raw(ptr)))
25092f3ab15Sopenharmony_ci            }
25192f3ab15Sopenharmony_ci
25292f3ab15Sopenharmony_ci            fn get(&self) -> *mut ffi::BIO_METHOD {
25392f3ab15Sopenharmony_ci                self.0
25492f3ab15Sopenharmony_ci            }
25592f3ab15Sopenharmony_ci        }
25692f3ab15Sopenharmony_ci
25792f3ab15Sopenharmony_ci        impl Drop for BIO_METHOD {
25892f3ab15Sopenharmony_ci            fn drop(&mut self) {
25992f3ab15Sopenharmony_ci                unsafe {
26092f3ab15Sopenharmony_ci                    let _ = Box::<ffi::BIO_METHOD>::from_raw(self.0);
26192f3ab15Sopenharmony_ci                }
26292f3ab15Sopenharmony_ci            }
26392f3ab15Sopenharmony_ci        }
26492f3ab15Sopenharmony_ci
26592f3ab15Sopenharmony_ci        #[allow(bad_style)]
26692f3ab15Sopenharmony_ci        unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) {
26792f3ab15Sopenharmony_ci            (*bio).init = init;
26892f3ab15Sopenharmony_ci        }
26992f3ab15Sopenharmony_ci
27092f3ab15Sopenharmony_ci        #[allow(bad_style)]
27192f3ab15Sopenharmony_ci        unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) {
27292f3ab15Sopenharmony_ci            (*bio).flags = flags;
27392f3ab15Sopenharmony_ci        }
27492f3ab15Sopenharmony_ci
27592f3ab15Sopenharmony_ci        #[allow(bad_style)]
27692f3ab15Sopenharmony_ci        unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void {
27792f3ab15Sopenharmony_ci            (*bio).ptr
27892f3ab15Sopenharmony_ci        }
27992f3ab15Sopenharmony_ci
28092f3ab15Sopenharmony_ci        #[allow(bad_style)]
28192f3ab15Sopenharmony_ci        unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) {
28292f3ab15Sopenharmony_ci            (*bio).ptr = data;
28392f3ab15Sopenharmony_ci        }
28492f3ab15Sopenharmony_ci
28592f3ab15Sopenharmony_ci        #[allow(bad_style)]
28692f3ab15Sopenharmony_ci        unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) {
28792f3ab15Sopenharmony_ci            (*bio).num = num;
28892f3ab15Sopenharmony_ci        }
28992f3ab15Sopenharmony_ci    }
29092f3ab15Sopenharmony_ci}
291