#![allow(dead_code)]
use std::ptr::NonNull;
#[derive(Debug)]
pub struct SslCtx(NonNull<aws_lc_sys::SSL_CTX>);
impl SslCtx {
pub unsafe fn from_raw(ptr: *mut aws_lc_sys::SSL_CTX) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub fn as_ptr(&self) -> *mut aws_lc_sys::SSL_CTX {
self.0.as_ptr()
}
}
impl Clone for SslCtx {
fn clone(&self) -> Self {
let ok = unsafe { aws_lc_sys::SSL_CTX_up_ref(self.0.as_ptr()) };
assert_eq!(ok, 1, "SSL_CTX_up_ref failed");
Self(self.0)
}
}
impl Drop for SslCtx {
fn drop(&mut self) {
unsafe {
aws_lc_sys::SSL_CTX_free(self.0.as_ptr());
}
}
}
unsafe impl Send for SslCtx {}
#[derive(Debug)]
pub struct Ssl(NonNull<aws_lc_sys::SSL>);
impl Ssl {
pub unsafe fn from_raw(ptr: *mut aws_lc_sys::SSL) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub fn as_ptr(&self) -> *mut aws_lc_sys::SSL {
self.0.as_ptr()
}
}
impl Drop for Ssl {
fn drop(&mut self) {
unsafe {
aws_lc_sys::SSL_free(self.0.as_ptr());
}
}
}
unsafe impl Send for Ssl {}
#[derive(Debug)]
pub struct Bio(NonNull<aws_lc_sys::BIO>);
impl Bio {
pub unsafe fn from_raw(ptr: *mut aws_lc_sys::BIO) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub fn as_ptr(&self) -> *mut aws_lc_sys::BIO {
self.0.as_ptr()
}
#[must_use]
pub fn into_raw(self) -> *mut aws_lc_sys::BIO {
let ptr = self.0.as_ptr();
std::mem::forget(self);
ptr
}
}
impl Drop for Bio {
fn drop(&mut self) {
unsafe {
aws_lc_sys::BIO_free(self.0.as_ptr());
}
}
}
unsafe impl Send for Bio {}
#[derive(Debug)]
pub struct EvpPkey(NonNull<aws_lc_sys::EVP_PKEY>);
impl EvpPkey {
pub unsafe fn from_raw(ptr: *mut aws_lc_sys::EVP_PKEY) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub fn as_ptr(&self) -> *mut aws_lc_sys::EVP_PKEY {
self.0.as_ptr()
}
}
impl Drop for EvpPkey {
fn drop(&mut self) {
unsafe {
aws_lc_sys::EVP_PKEY_free(self.0.as_ptr());
}
}
}
unsafe impl Send for EvpPkey {}
#[derive(Debug)]
pub struct X509(NonNull<aws_lc_sys::X509>);
impl X509 {
pub unsafe fn from_raw(ptr: *mut aws_lc_sys::X509) -> Option<Self> {
NonNull::new(ptr).map(Self)
}
#[must_use]
pub fn as_ptr(&self) -> *mut aws_lc_sys::X509 {
self.0.as_ptr()
}
}
impl Drop for X509 {
fn drop(&mut self) {
unsafe {
aws_lc_sys::X509_free(self.0.as_ptr());
}
}
}
unsafe impl Send for X509 {}
#[cfg(test)]
mod tests {
use super::*;
fn new_server_ctx() -> SslCtx {
let raw = unsafe { aws_lc_sys::SSL_CTX_new(aws_lc_sys::TLS_server_method()) };
unsafe { SslCtx::from_raw(raw) }.expect("SSL_CTX_new (server) returned null")
}
fn new_client_ctx() -> SslCtx {
let raw = unsafe { aws_lc_sys::SSL_CTX_new(aws_lc_sys::TLS_client_method()) };
unsafe { SslCtx::from_raw(raw) }.expect("SSL_CTX_new (client) returned null")
}
#[test]
fn server_ctx_constructs_and_drops() {
let ctx = new_server_ctx();
assert!(!ctx.as_ptr().is_null());
}
#[test]
fn client_ctx_constructs_and_drops() {
let ctx = new_client_ctx();
assert!(!ctx.as_ptr().is_null());
}
#[test]
fn ssl_handle_round_trips_through_ctx() {
let ctx = new_server_ctx();
let raw = unsafe { aws_lc_sys::SSL_new(ctx.as_ptr()) };
let ssl = unsafe { Ssl::from_raw(raw) }.expect("SSL_new returned null");
assert!(!ssl.as_ptr().is_null());
}
#[test]
fn from_raw_null_returns_none() {
assert!(unsafe { SslCtx::from_raw(std::ptr::null_mut()) }.is_none());
assert!(unsafe { Ssl::from_raw(std::ptr::null_mut()) }.is_none());
assert!(unsafe { Bio::from_raw(std::ptr::null_mut()) }.is_none());
}
#[test]
fn bio_mem_constructs_and_drops() {
let raw = unsafe { aws_lc_sys::BIO_new(aws_lc_sys::BIO_s_mem()) };
let bio = unsafe { Bio::from_raw(raw) }.expect("BIO_new returned null");
assert!(!bio.as_ptr().is_null());
}
#[test]
fn bio_into_raw_releases_ownership() {
let raw = unsafe { aws_lc_sys::BIO_new(aws_lc_sys::BIO_s_mem()) };
let bio = unsafe { Bio::from_raw(raw) }.expect("BIO_new returned null");
let leaked = bio.into_raw();
assert_eq!(leaked, raw);
let _retaken = unsafe { Bio::from_raw(leaked) }.expect("non-null");
}
#[test]
fn many_contexts_do_not_leak_under_repeated_construction() {
for _ in 0..1024 {
let _ = new_server_ctx();
}
}
#[test]
fn ssl_ctx_clone_shares_underlying_handle() {
let ctx = new_server_ctx();
let raw = ctx.as_ptr();
let cloned = ctx.clone();
assert_eq!(cloned.as_ptr(), raw, "Clone must alias the same SSL_CTX");
drop(ctx);
let ssl_raw = unsafe { aws_lc_sys::SSL_new(cloned.as_ptr()) };
let _ssl = unsafe { Ssl::from_raw(ssl_raw) }.expect("SSL_new after clone+drop");
}
#[test]
fn ssl_ctx_clone_then_drop_all_does_not_leak() {
for _ in 0..512 {
let ctx = new_server_ctx();
let a = ctx.clone();
let b = ctx.clone();
drop(ctx);
drop(a);
drop(b);
}
}
}