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