#![allow(clippy::missing_errors_doc, clippy::semicolon_if_nothing_returned)]
use core::ffi::c_void;
use std::ffi::{CStr, CString};
use crate::{
client::ContentContext,
error::NetworkError,
ffi,
quic::{QuicConnection, QuicOptions},
};
fn to_cstring(value: &str, field: &str) -> Result<CString, NetworkError> {
CString::new(value).map_err(|e| NetworkError::InvalidArgument(format!("{field} NUL byte: {e}")))
}
unsafe fn copied_string(ptr: *mut i8) -> Option<String> {
if ptr.is_null() {
return None;
}
let value = unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { ffi::nw_shim_free_buffer(ptr.cast()) };
Some(value)
}
pub struct SecurityProtocolOptions {
handle: *mut c_void,
}
unsafe impl Send for SecurityProtocolOptions {}
unsafe impl Sync for SecurityProtocolOptions {}
impl SecurityProtocolOptions {
#[must_use]
pub(crate) const unsafe fn from_raw(handle: *mut c_void) -> Self {
Self { handle }
}
}
impl Clone for SecurityProtocolOptions {
fn clone(&self) -> Self {
let handle = unsafe { ffi::nw_shim_sec_retain(self.handle) };
Self { handle }
}
}
impl Drop for SecurityProtocolOptions {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe { ffi::nw_shim_sec_release(self.handle) };
self.handle = core::ptr::null_mut();
}
}
}
pub struct SecurityProtocolMetadata {
handle: *mut c_void,
}
unsafe impl Send for SecurityProtocolMetadata {}
unsafe impl Sync for SecurityProtocolMetadata {}
impl SecurityProtocolMetadata {
#[must_use]
pub(crate) const unsafe fn from_raw(handle: *mut c_void) -> Self {
Self { handle }
}
}
impl Clone for SecurityProtocolMetadata {
fn clone(&self) -> Self {
let handle = unsafe { ffi::nw_shim_sec_retain(self.handle) };
Self { handle }
}
}
impl Drop for SecurityProtocolMetadata {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe { ffi::nw_shim_sec_release(self.handle) };
self.handle = core::ptr::null_mut();
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuicStreamType {
Unknown,
Bidirectional,
Unidirectional,
Datagram,
Other(i32),
}
impl QuicStreamType {
const fn from_raw(raw: i32) -> Self {
match raw {
0 => Self::Unknown,
1 => Self::Bidirectional,
2 => Self::Unidirectional,
3 => Self::Datagram,
other => Self::Other(other),
}
}
}
pub struct QuicMetadata {
handle: *mut c_void,
}
unsafe impl Send for QuicMetadata {}
unsafe impl Sync for QuicMetadata {}
impl QuicMetadata {
#[must_use]
pub(crate) const unsafe fn from_raw(handle: *mut c_void) -> Self {
Self { handle }
}
#[must_use]
pub(crate) const fn as_ptr(&self) -> *mut c_void {
self.handle
}
#[must_use]
pub fn is_quic(&self) -> bool {
unsafe { ffi::nw_shim_protocol_metadata_is_quic(self.handle) != 0 }
}
#[must_use]
pub fn security_metadata(&self) -> Option<SecurityProtocolMetadata> {
let handle = unsafe { ffi::nw_shim_quic_copy_sec_protocol_metadata(self.handle) };
(!handle.is_null()).then_some(unsafe { SecurityProtocolMetadata::from_raw(handle) })
}
#[must_use]
pub fn stream_id(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_stream_id(self.handle) }
}
#[must_use]
pub fn stream_type(&self) -> QuicStreamType {
QuicStreamType::from_raw(unsafe { ffi::nw_shim_quic_get_stream_type(self.handle) })
}
#[must_use]
pub fn stream_application_error(&self) -> Option<u64> {
let error = unsafe { ffi::nw_shim_quic_get_stream_application_error(self.handle) };
(error != u64::MAX).then_some(error)
}
pub fn set_stream_application_error(&mut self, application_error: u64) -> &mut Self {
unsafe { ffi::nw_shim_quic_set_stream_application_error(self.handle, application_error) };
self
}
#[must_use]
pub fn local_max_streams_bidirectional(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_local_max_streams_bidirectional(self.handle) }
}
pub fn set_local_max_streams_bidirectional(&mut self, max_streams_bidirectional: u64) -> &mut Self {
unsafe {
ffi::nw_shim_quic_set_local_max_streams_bidirectional(
self.handle,
max_streams_bidirectional,
)
};
self
}
#[must_use]
pub fn local_max_streams_unidirectional(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_local_max_streams_unidirectional(self.handle) }
}
pub fn set_local_max_streams_unidirectional(&mut self, max_streams_unidirectional: u64) -> &mut Self {
unsafe {
ffi::nw_shim_quic_set_local_max_streams_unidirectional(
self.handle,
max_streams_unidirectional,
)
};
self
}
#[must_use]
pub fn remote_max_streams_bidirectional(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_remote_max_streams_bidirectional(self.handle) }
}
#[must_use]
pub fn remote_max_streams_unidirectional(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_remote_max_streams_unidirectional(self.handle) }
}
#[must_use]
pub fn stream_usable_datagram_frame_size(&self) -> u16 {
unsafe { ffi::nw_shim_quic_get_stream_usable_datagram_frame_size(self.handle) }
}
#[must_use]
pub fn application_error(&self) -> Option<u64> {
let error = unsafe { ffi::nw_shim_quic_get_application_error(self.handle) };
(error != u64::MAX).then_some(error)
}
#[must_use]
pub fn application_error_reason(&self) -> Option<String> {
unsafe { copied_string(ffi::nw_shim_quic_copy_application_error_reason(self.handle)) }
}
pub fn set_application_error(
&mut self,
application_error: u64,
reason: Option<&str>,
) -> Result<&mut Self, NetworkError> {
let reason = reason.map(|reason| to_cstring(reason, "reason")).transpose()?;
unsafe {
ffi::nw_shim_quic_set_application_error(
self.handle,
application_error,
reason.as_ref().map_or(core::ptr::null(), |reason| reason.as_ptr()),
)
};
Ok(self)
}
#[must_use]
pub fn keepalive_interval(&self) -> u16 {
unsafe { ffi::nw_shim_quic_get_keepalive_interval(self.handle) }
}
pub fn set_keepalive_interval(&mut self, keepalive_interval: u16) -> &mut Self {
unsafe { ffi::nw_shim_quic_set_keepalive_interval(self.handle, keepalive_interval) };
self
}
#[must_use]
pub fn remote_idle_timeout(&self) -> u64 {
unsafe { ffi::nw_shim_quic_get_remote_idle_timeout(self.handle) }
}
}
impl Clone for QuicMetadata {
fn clone(&self) -> Self {
let handle = unsafe { ffi::nw_shim_retain_object(self.handle) };
Self { handle }
}
}
impl Drop for QuicMetadata {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe { ffi::nw_shim_release_object(self.handle) };
self.handle = core::ptr::null_mut();
}
}
}
impl QuicOptions {
#[must_use]
pub fn initial_max_streams_bidirectional(&self) -> u64 {
let options = self.protocol_options();
unsafe { ffi::nw_shim_quic_get_initial_max_streams_bidirectional(options.as_ptr()) }
}
pub fn set_initial_max_streams_bidirectional(
&mut self,
initial_max_streams_bidirectional: u64,
) -> &mut Self {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_set_initial_max_streams_bidirectional(
options.as_ptr(),
initial_max_streams_bidirectional,
)
};
self
}
#[must_use]
pub fn initial_max_streams_unidirectional(&self) -> u64 {
let options = self.protocol_options();
unsafe { ffi::nw_shim_quic_get_initial_max_streams_unidirectional(options.as_ptr()) }
}
pub fn set_initial_max_streams_unidirectional(
&mut self,
initial_max_streams_unidirectional: u64,
) -> &mut Self {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_set_initial_max_streams_unidirectional(
options.as_ptr(),
initial_max_streams_unidirectional,
)
};
self
}
#[must_use]
pub fn initial_max_stream_data_bidirectional_local(&self) -> u64 {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_get_initial_max_stream_data_bidirectional_local(options.as_ptr())
}
}
pub fn set_initial_max_stream_data_bidirectional_local(
&mut self,
initial_max_stream_data_bidirectional_local: u64,
) -> &mut Self {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_set_initial_max_stream_data_bidirectional_local(
options.as_ptr(),
initial_max_stream_data_bidirectional_local,
)
};
self
}
#[must_use]
pub fn initial_max_stream_data_bidirectional_remote(&self) -> u64 {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_get_initial_max_stream_data_bidirectional_remote(options.as_ptr())
}
}
pub fn set_initial_max_stream_data_bidirectional_remote(
&mut self,
initial_max_stream_data_bidirectional_remote: u64,
) -> &mut Self {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_set_initial_max_stream_data_bidirectional_remote(
options.as_ptr(),
initial_max_stream_data_bidirectional_remote,
)
};
self
}
#[must_use]
pub fn initial_max_stream_data_unidirectional(&self) -> u64 {
let options = self.protocol_options();
unsafe { ffi::nw_shim_quic_get_initial_max_stream_data_unidirectional(options.as_ptr()) }
}
pub fn set_initial_max_stream_data_unidirectional(
&mut self,
initial_max_stream_data_unidirectional: u64,
) -> &mut Self {
let options = self.protocol_options();
unsafe {
ffi::nw_shim_quic_set_initial_max_stream_data_unidirectional(
options.as_ptr(),
initial_max_stream_data_unidirectional,
)
};
self
}
#[must_use]
pub fn max_datagram_frame_size(&self) -> u16 {
let options = self.protocol_options();
unsafe { ffi::nw_shim_quic_get_max_datagram_frame_size(options.as_ptr()) }
}
pub fn set_max_datagram_frame_size(&mut self, max_datagram_frame_size: u16) -> &mut Self {
let options = self.protocol_options();
unsafe { ffi::nw_shim_quic_set_max_datagram_frame_size(options.as_ptr(), max_datagram_frame_size) };
self
}
#[must_use]
pub fn security_options(&self) -> Option<SecurityProtocolOptions> {
let options = self.protocol_options();
let handle = unsafe { ffi::nw_shim_quic_copy_sec_protocol_options(options.as_ptr()) };
(!handle.is_null()).then_some(unsafe { SecurityProtocolOptions::from_raw(handle) })
}
}
impl QuicConnection {
#[must_use]
pub fn metadata(&self) -> Option<QuicMetadata> {
let handle = unsafe { ffi::nw_shim_connection_copy_quic_metadata(self.as_ptr()) };
(!handle.is_null()).then_some(unsafe { QuicMetadata::from_raw(handle) })
}
}
impl ContentContext {
pub fn set_quic_metadata(&mut self, metadata: &QuicMetadata) -> &mut Self {
unsafe { ffi::nw_shim_content_context_set_protocol_metadata(self.as_ptr(), metadata.as_ptr()) };
self
}
#[must_use]
pub fn copy_quic_metadata(&self) -> Option<QuicMetadata> {
let handle = unsafe { ffi::nw_shim_content_context_copy_quic_metadata(self.as_ptr()) };
(!handle.is_null()).then_some(unsafe { QuicMetadata::from_raw(handle) })
}
}