From 398010860e76c3060bab6ae2967e9ca578cae70e Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 21 Nov 2023 08:54:17 +0100 Subject: [PATCH] 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 | 64 ++++++++++++++++--- quiche/src/ffi.rs | 134 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+), 8 deletions(-) diff --git a/quiche/include/quiche.h b/quiche/include/quiche.h index 713cd5ace7..230a2e2b91 100644 --- a/quiche/include/quiche.h +++ b/quiche/include/quiche.h @@ -268,15 +268,15 @@ typedef struct quiche_conn quiche_conn; // Creates a new server-side connection. quiche_conn *quiche_accept(const uint8_t *scid, size_t scid_len, const uint8_t *odcid, size_t odcid_len, - const struct sockaddr *local, size_t local_len, - const struct sockaddr *peer, size_t peer_len, + const struct sockaddr *local, socklen_t local_len, + const struct sockaddr *peer, socklen_t peer_len, quiche_config *config); // Creates a new client-side connection. quiche_conn *quiche_connect(const char *server_name, const uint8_t *scid, size_t scid_len, - const struct sockaddr *local, size_t local_len, - const struct sockaddr *peer, size_t peer_len, + const struct sockaddr *local, socklen_t local_len, + const struct sockaddr *peer, socklen_t peer_len, quiche_config *config); // Writes a version negotiation packet. @@ -296,8 +296,8 @@ bool quiche_version_is_supported(uint32_t version); quiche_conn *quiche_conn_new_with_tls(const uint8_t *scid, size_t scid_len, const uint8_t *odcid, size_t odcid_len, - const struct sockaddr *local, size_t local_len, - const struct sockaddr *peer, size_t peer_len, + const struct sockaddr *local, socklen_t local_len, + const struct sockaddr *peer, socklen_t peer_len, const quiche_config *config, void *ssl, bool is_server); @@ -675,8 +675,56 @@ ssize_t quiche_conn_send_ack_eliciting(quiche_conn *conn); // Schedule an ack-eliciting packet on the specified path. ssize_t quiche_conn_send_ack_eliciting_on_path(quiche_conn *conn, - const struct sockaddr *local, size_t local_len, - const struct sockaddr *peer, size_t peer_len); + const struct sockaddr *local, socklen_t local_len, + const struct sockaddr *peer, socklen_t peer_len); + +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_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_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); // Frees the connection object. void quiche_conn_free(quiche_conn *conn); diff --git a/quiche/src/ffi.rs b/quiche/src/ffi.rs index d18193c53c..e2405c68ab 100644 --- a/quiche/src/ffi.rs +++ b/quiche/src/ffi.rs @@ -1351,6 +1351,140 @@ pub extern fn quiche_conn_send_quantum(conn: &Connection) -> size_t { conn.send_quantum() as size_t } +#[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,