From 5796adc0a06044e9e4f2020ad51f680bd0d071bc Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 27 Nov 2023 13:53:37 +0100 Subject: [PATCH] ffi: expose C API to handle PathEvent Motivation: There was no C api exposed to allow handling PathEvent. Modifications: Expose c functions to handle PathEvent Result: Be able to handle and consume PathEvent --- quiche/include/quiche.h | 48 ++++++++++++++ quiche/src/ffi.rs | 134 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/quiche/include/quiche.h b/quiche/include/quiche.h index 44ea77ea24..9a244182dd 100644 --- a/quiche/include/quiche.h +++ b/quiche/include/quiche.h @@ -714,6 +714,54 @@ uint64_t quiche_conn_new_scid(quiche_conn *conn, const uint8_t *scid, size_t scid_len, const uint8_t *reset_token, bool retire_if_needed); +enum quiche_path_event_type { + QUICHE_PATH_EVENT_NEW, + QUICHE_PATH_EVENT_VALIDATED, + QUICHE_PATH_EVENT_FAILED_VALIDATION, + QUICHE_PATH_EVENT_CLOSED, + QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID, + QUICHE_PATH_EVENT_PEER_MIGRATED, +}; + +typedef struct quiche_path_event quiche_path_event; + +// Retrieves the next event. Returns NULL if there is no event to process. +const quiche_path_event *quiche_conn_path_event_next(quiche_conn *conn); + +// Returns the type of the event. +enum quiche_path_event_type quiche_path_event_type(quiche_path_event *ev); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_NEW. +void quiche_path_event_new(quiche_path_event *ev, + struct sockaddr_storage *local, socklen_t *local_len, struct sockaddr_storage *peer, socklen_t *peer_len); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_VALIDATED. +void quiche_path_event_validated(quiche_path_event *ev, + struct sockaddr_storage *local, socklen_t *local_len, struct sockaddr_storage *peer, socklen_t *peer_len); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_FAILED_VALIDATION. +void quiche_path_event_failed_validation(quiche_path_event *ev, + struct sockaddr_storage *local, socklen_t *local_len, struct sockaddr_storage *peer, socklen_t *peer_len); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_CLOSED. +void quiche_path_event_closed(quiche_path_event *ev, + struct sockaddr_storage *local, socklen_t *local_len, struct sockaddr_storage *peer, socklen_t *peer_len); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID. +void quiche_path_event_reused_source_connection_id(quiche_path_event *ev, uint64_t *id, + struct sockaddr_storage *old_local, socklen_t *old_local_len, + struct sockaddr_storage *old_peer, socklen_t *old_peer_len, + struct sockaddr_storage *local, socklen_t *local_len, + struct sockaddr_storage *peer, socklen_t *peer_len); + +// Should be called if the quiche_path_event_type(...) returns QUICHE_PATH_EVENT_PEER_MIGRATED. +void quiche_path_event_peer_migrated(quiche_path_event *ev, + struct sockaddr_storage *local, socklen_t *local_len, + struct sockaddr_storage *peer, socklen_t *peer_len); + +// Frees the path event object. +void quiche_path_event_free(quiche_path_event *ev); + // Requests the retirement of the destination Connection ID used by the // host to reach its peer. int quiche_conn_retire_dcid(quiche_conn *conn, uint64_t dcid_seq); diff --git a/quiche/src/ffi.rs b/quiche/src/ffi.rs index b469134edc..a563763bee 100644 --- a/quiche/src/ffi.rs +++ b/quiche/src/ffi.rs @@ -1465,6 +1465,140 @@ pub extern fn quiche_conn_retired_scid_next( } } +#[no_mangle] +pub extern fn quiche_conn_path_event_next( + conn: &mut Connection, +) -> *const PathEvent { + match conn.path_event_next() { + Some(v) => Box::into_raw(Box::new(v)), + None => ptr::null(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_type(ev: &PathEvent) -> u32 { + match ev { + PathEvent::New { .. } => 0, + + PathEvent::Validated { .. } => 1, + + PathEvent::FailedValidation { .. } => 2, + + PathEvent::Closed { .. } => 3, + + PathEvent::ReusedSourceConnectionId { .. } => 4, + + PathEvent::PeerMigrated { .. } => 5, + } +} + +#[no_mangle] +pub extern fn quiche_path_event_new( + ev: &PathEvent, local_addr: &mut sockaddr_storage, + local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage, + peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::New(local, peer) => { + *local_addr_len = std_addr_to_c(local, local_addr); + *peer_addr_len = std_addr_to_c(peer, peer_addr) + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_validated( + ev: &PathEvent, local_addr: &mut sockaddr_storage, + local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage, + peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::Validated(local, peer) => { + *local_addr_len = std_addr_to_c(local, local_addr); + *peer_addr_len = std_addr_to_c(peer, peer_addr) + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_failed_validation( + ev: &PathEvent, local_addr: &mut sockaddr_storage, + local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage, + peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::FailedValidation(local, peer) => { + *local_addr_len = std_addr_to_c(local, local_addr); + *peer_addr_len = std_addr_to_c(peer, peer_addr) + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_closed( + ev: &PathEvent, local_addr: &mut sockaddr_storage, + local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage, + peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::Closed(local, peer) => { + *local_addr_len = std_addr_to_c(local, local_addr); + *peer_addr_len = std_addr_to_c(peer, peer_addr) + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_reused_source_connection_id( + ev: &PathEvent, cid_sequence_number: &mut u64, + old_local_addr: &mut sockaddr_storage, old_local_addr_len: &mut socklen_t, + old_peer_addr: &mut sockaddr_storage, old_peer_addr_len: &mut socklen_t, + local_addr: &mut sockaddr_storage, local_addr_len: &mut socklen_t, + peer_addr: &mut sockaddr_storage, peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::ReusedSourceConnectionId(id, old, new) => { + *cid_sequence_number = *id; + *old_local_addr_len = std_addr_to_c(&old.0, old_local_addr); + *old_peer_addr_len = std_addr_to_c(&old.1, old_peer_addr); + + *local_addr_len = std_addr_to_c(&new.0, local_addr); + *peer_addr_len = std_addr_to_c(&new.1, peer_addr) + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_peer_migrated( + ev: &PathEvent, local_addr: &mut sockaddr_storage, + local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage, + peer_addr_len: &mut socklen_t, +) { + match ev { + PathEvent::PeerMigrated(local, peer) => { + *local_addr_len = std_addr_to_c(local, local_addr); + *peer_addr_len = std_addr_to_c(peer, peer_addr); + }, + + _ => unreachable!(), + } +} + +#[no_mangle] +pub extern fn quiche_path_event_free(ev: *mut PathEvent) { + drop(unsafe { Box::from_raw(ev) }); +} + #[no_mangle] pub extern fn quiche_put_varint( buf: *mut u8, buf_len: size_t, val: u64,