Skip to content

Commit

Permalink
add ffi listener event wrapper (#4831)
Browse files Browse the repository at this point in the history
  • Loading branch information
youyuanwu authored Feb 20, 2025
1 parent 7da6fea commit 2c81e07
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 69 deletions.
58 changes: 1 addition & 57 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod error;
pub mod ffi;
pub use error::{Status, StatusCode};
mod types;
pub use types::{ConnectionEvent, StreamEvent};
pub use types::{ConnectionEvent, ListenerEvent, NewConnectionInfo, StreamEvent};

//
// The following starts the C interop layer of MsQuic API.
Expand Down Expand Up @@ -364,22 +364,6 @@ pub struct Buffer {
pub buffer: *mut u8,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct NewConnectionInfo {
pub quic_version: u32,
pub local_address: *const Addr,
pub remote_address: *const Addr,
pub crypto_buffer_length: u32,
pub client_alpn_list_length: u16,
pub server_name_length: u16,
pub negotiated_alpn_length: u8,
pub crypto_buffer: *const u8,
pub client_alpn_list: *const u8,
pub negotiated_alpn: *const u8,
pub server_name: *const i8,
}

pub type TlsProtocolVersion = u32;
pub const TLS_PROTOCOL_UNKNOWN: TlsProtocolVersion = 0;
pub const TLS_PROTOCOL_1_3: TlsProtocolVersion = 12288;
Expand Down Expand Up @@ -764,46 +748,6 @@ pub const PARAM_STREAM_0RTT_LENGTH: u32 = 0x08000001;
pub const PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE: u32 = 0x08000002;
pub const PARAM_STREAM_PRIORITY: u32 = 0x08000003;

pub type ListenerEventType = u32;
pub const LISTENER_EVENT_NEW_CONNECTION: ListenerEventType = 0;
pub const LISTENER_EVENT_STOP_COMPLETE: ListenerEventType = 1;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ListenerEventNewConnection {
pub info: *const NewConnectionInfo,
pub connection: HQUIC,
}

bitfield! {
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ListenerEventStopCompleteBitfields(u8);
// The fields default to u8
pub app_close_in_progress, _: 0, 0;
_reserved, _: 7, 1;
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ListenerEventStopComplete {
pub bit_flags: ListenerEventStopCompleteBitfields,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub union ListenerEventPayload {
pub new_connection: ListenerEventNewConnection,
pub stop_complete: ListenerEventStopComplete,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ListenerEvent {
pub event_type: ListenerEventType,
pub payload: ListenerEventPayload,
}

#[link(name = "msquic")]
unsafe extern "C" {
unsafe fn MsQuicOpenVersion(version: u32, api: *mut *const QUIC_API_TABLE) -> u32;
Expand Down
98 changes: 86 additions & 12 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,77 @@
use crate::ffi::QUIC_CONNECTION_EVENT;
use std::ffi::c_void;

/// Listener event converted from ffi type.
pub enum ListenerEvent<'a> {
NewConnection {
info: NewConnectionInfo<'a>,
connection: crate::Connection,
},
StopComplete {
app_close_in_progress: bool,
},
}

pub struct NewConnectionInfo<'a> {
pub quic_version: u32,
pub local_address: &'a crate::Addr,
pub remote_address: &'a crate::Addr,
pub crypto_buffer: &'a [u8],
pub client_alpn_list: &'a [u8],
pub server_name: &'a [u8],
pub negotiated_alpn: &'a [u8],
}

impl<'a> From<&'a crate::ffi::QUIC_NEW_CONNECTION_INFO> for NewConnectionInfo<'a> {
fn from(value: &crate::ffi::QUIC_NEW_CONNECTION_INFO) -> Self {
Self {
quic_version: value.QuicVersion,
local_address: unsafe { (value.LocalAddress as *const crate::Addr).as_ref().unwrap() },
remote_address: unsafe {
(value.RemoteAddress as *const crate::Addr)
.as_ref()
.unwrap()
},
crypto_buffer: unsafe {
slice_conv(value.CryptoBuffer, value.CryptoBufferLength as usize)
},
client_alpn_list: unsafe {
slice_conv(value.ClientAlpnList, value.ClientAlpnListLength as usize)
},
server_name: unsafe {
slice_conv(
value.ServerName as *const u8,
value.ServerNameLength as usize,
)
},
negotiated_alpn: unsafe {
slice_conv(value.NegotiatedAlpn, value.NegotiatedAlpnLength as usize)
},
}
}
}

impl<'a> From<&'a crate::ffi::QUIC_LISTENER_EVENT> for ListenerEvent<'a> {
fn from(value: &'a crate::ffi::QUIC_LISTENER_EVENT) -> Self {
match value.Type {
crate::ffi::QUIC_LISTENER_EVENT_TYPE_QUIC_LISTENER_EVENT_NEW_CONNECTION => {
let ev = unsafe { &value.__bindgen_anon_1.NEW_CONNECTION };
Self::NewConnection {
info: NewConnectionInfo::from(unsafe { ev.Info.as_ref().unwrap() }),
connection: unsafe { crate::Connection::from_raw(ev.Connection) },
}
}
crate::ffi::QUIC_LISTENER_EVENT_TYPE_QUIC_LISTENER_EVENT_STOP_COMPLETE => {
let ev = unsafe { &value.__bindgen_anon_1.STOP_COMPLETE };
Self::StopComplete {
app_close_in_progress: ev.AppCloseInProgress() != 0,
}
}
_ => panic!("unknown listener event {}", value.Type),
}
}
}

/// Connection callback events.
/// TODO: derive Debug once all enums are safe.
pub enum ConnectionEvent<'a> {
Expand Down Expand Up @@ -89,11 +160,7 @@ impl<'a> From<&'a QUIC_CONNECTION_EVENT> for ConnectionEvent<'a> {
match value.Type {
crate::ffi::QUIC_CONNECTION_EVENT_TYPE_QUIC_CONNECTION_EVENT_CONNECTED => {
let ev = unsafe { value.__bindgen_anon_1.CONNECTED };
let alpn = if ev.NegotiatedAlpnLength > 0{
unsafe { std::slice::from_raw_parts(ev.NegotiatedAlpn, ev.NegotiatedAlpnLength as usize)}
}else{
&[]
};
let alpn = unsafe { slice_conv(ev.NegotiatedAlpn, ev.NegotiatedAlpnLength as usize) };
Self::Connected { session_resumed: ev.SessionResumed != 0, negotiated_alpn: alpn }
}
crate::ffi::QUIC_CONNECTION_EVENT_TYPE_QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT => {
Expand Down Expand Up @@ -150,16 +217,14 @@ impl<'a> From<&'a QUIC_CONNECTION_EVENT> for ConnectionEvent<'a> {
}
crate::ffi::QUIC_CONNECTION_EVENT_TYPE_QUIC_CONNECTION_EVENT_RESUMED =>{
let ev = unsafe { value.__bindgen_anon_1.RESUMED };
// TODO: may need to check 0 len.
Self::Resumed {
resumption_state: unsafe { std::slice::from_raw_parts(ev.ResumptionState, ev.ResumptionStateLength as usize) }
resumption_state: unsafe { slice_conv(ev.ResumptionState, ev.ResumptionStateLength as usize) }
}
}
crate::ffi::QUIC_CONNECTION_EVENT_TYPE_QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED =>{
let ev = unsafe { value.__bindgen_anon_1.RESUMPTION_TICKET_RECEIVED };
// TODO: may need to check 0 len.
Self::ResumptionTicketReceived {
resumption_ticket: unsafe { std::slice::from_raw_parts(ev.ResumptionTicket, ev.ResumptionTicketLength as usize) }
resumption_ticket: unsafe {slice_conv(ev.ResumptionTicket, ev.ResumptionTicketLength as usize) }
}
}
crate::ffi::QUIC_CONNECTION_EVENT_TYPE_QUIC_CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED => {
Expand Down Expand Up @@ -238,9 +303,7 @@ impl<'b> From<&'b mut crate::ffi::QUIC_STREAM_EVENT> for StreamEvent<'b> {
Self::Receive {
absolute_offset: ev.AbsoluteOffset,
total_buffer_length: &mut ev.TotalBufferLength,
buffers: unsafe {
std::slice::from_raw_parts(ev.Buffers, ev.BufferCount as usize)
},
buffers: unsafe { slice_conv(ev.Buffers, ev.BufferCount as usize) },
flags: ev.Flags,
}
}
Expand Down Expand Up @@ -304,3 +367,14 @@ impl<'b> From<&'b mut crate::ffi::QUIC_STREAM_EVENT> for StreamEvent<'b> {
}
}
}

/// Convert array pointer to slice.
/// Allows empty buffer. slice::from_raw_parts does not allow empty buffer.
#[inline]
unsafe fn slice_conv<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
if len == 0 {
&[]
} else {
std::slice::from_raw_parts(ptr, len)
}
}

0 comments on commit 2c81e07

Please sign in to comment.