From 71cd80f204ef0191edccf7a918d9fe7ad320f405 Mon Sep 17 00:00:00 2001 From: Tamas Levai Date: Fri, 10 May 2024 11:30:16 +0200 Subject: [PATCH] net/quinn: Enable client to keep QUIC conn alive Co-authored-by: Felician Nemeth Part-of: --- docs/plugins/gst_plugins_cache.json | 14 +++++++++++ net/quinn/src/quinnquicsink/imp.rs | 37 ++++++++++++++++++++++------- net/quinn/src/utils.rs | 24 +++++++++++++++---- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index 59f054a0..c7824c8b 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -3961,6 +3961,20 @@ "type": "guint", "writable": true }, + "keep-alive-interval": { + "blurb": "Keeps QUIC connection alive by periodically pinging the server. Value set in ms, 0 disables this feature", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + }, "private-key-file": { "blurb": "Path to a PKCS8 or RSA private key file", "conditionally-available": false, diff --git a/net/quinn/src/quinnquicsink/imp.rs b/net/quinn/src/quinnquicsink/imp.rs index fedcf3ad..5a2234e1 100644 --- a/net/quinn/src/quinnquicsink/imp.rs +++ b/net/quinn/src/quinnquicsink/imp.rs @@ -66,6 +66,7 @@ struct Settings { server_name: String, alpns: Vec, timeout: u32, + keep_alive_interval: u64, secure_conn: bool, use_datagram: bool, certificate_file: Option, @@ -82,6 +83,7 @@ impl Default for Settings { server_name: DEFAULT_SERVER_NAME.to_string(), alpns: vec![DEFAULT_ALPN.to_string()], timeout: DEFAULT_TIMEOUT, + keep_alive_interval: 0, secure_conn: DEFAULT_SECURE_CONNECTION, use_datagram: false, certificate_file: None, @@ -210,6 +212,12 @@ impl ObjectImpl for QuinnQuicSink { .default_value(DEFAULT_TIMEOUT) .readwrite() .build(), + glib::ParamSpecUInt64::builder("keep-alive-interval") + .nick("QUIC connection keep alive interval in ms") + .blurb("Keeps QUIC connection alive by periodically pinging the server. Value set in ms, 0 disables this feature") + .default_value(0) + .readwrite() + .build(), glib::ParamSpecBoolean::builder("secure-connection") .nick("Use secure connection") .blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.") @@ -269,6 +277,9 @@ impl ObjectImpl for QuinnQuicSink { "timeout" => { settings.timeout = value.get().expect("type checked upstream"); } + "keep-alive-interval" => { + settings.keep_alive_interval = value.get().expect("type checked upstream"); + } "secure-connection" => { settings.secure_conn = value.get().expect("type checked upstream"); } @@ -307,6 +318,7 @@ impl ObjectImpl for QuinnQuicSink { gst::Array::new(alpns).to_value() } "timeout" => settings.timeout.to_value(), + "keep-alive-interval" => settings.keep_alive_interval.to_value(), "secure-connection" => settings.secure_conn.to_value(), "certificate-file" => { let certfile = settings.certificate_file.as_ref(); @@ -512,6 +524,7 @@ impl QuinnQuicSink { let server_name; let alpns; let use_datagram; + let keep_alive_interval; let secure_conn; let cert_file; let private_key_file; @@ -529,20 +542,26 @@ impl QuinnQuicSink { server_name = settings.server_name.clone(); alpns = settings.alpns.clone(); use_datagram = settings.use_datagram; + keep_alive_interval = settings.keep_alive_interval; secure_conn = settings.secure_conn; cert_file = settings.certificate_file.clone(); private_key_file = settings.private_key_file.clone(); } - let endpoint = - client_endpoint(client_addr, secure_conn, alpns, cert_file, private_key_file).map_err( - |err| { - WaitError::FutureError(gst::error_msg!( - gst::ResourceError::Failed, - ["Failed to configure endpoint: {}", err] - )) - }, - )?; + let endpoint = client_endpoint( + client_addr, + secure_conn, + alpns, + cert_file, + private_key_file, + keep_alive_interval, + ) + .map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to configure endpoint: {}", err] + )) + })?; let connection = endpoint .connect(server_addr, &server_name) diff --git a/net/quinn/src/utils.rs b/net/quinn/src/utils.rs index ecd5792c..7d0f9192 100644 --- a/net/quinn/src/utils.rs +++ b/net/quinn/src/utils.rs @@ -13,7 +13,7 @@ use gst::ErrorMessage; use once_cell::sync::Lazy; use quinn::{ crypto::rustls::QuicClientConfig, crypto::rustls::QuicServerConfig, ClientConfig, Endpoint, - ServerConfig, + ServerConfig, TransportConfig, }; use std::error::Error; use std::fs::File; @@ -180,6 +180,7 @@ fn configure_client( certificate_file: Option, private_key_file: Option, alpns: Vec, + keep_alive_interval_ms: u64, ) -> Result> { let mut crypto = if secure_conn { let (certs, key) = read_certs_from_file(certificate_file, private_key_file)?; @@ -203,9 +204,15 @@ fn configure_client( crypto.alpn_protocols = alpn_protocols; crypto.key_log = Arc::new(rustls::KeyLogFile::new()); - Ok(ClientConfig::new(Arc::new(QuicClientConfig::try_from( - crypto, - )?))) + let mut client_config = ClientConfig::new(Arc::new(QuicClientConfig::try_from(crypto)?)); + + if keep_alive_interval_ms > 0 { + let mut transport_config = TransportConfig::default(); + transport_config.keep_alive_interval(Some(Duration::from_millis(keep_alive_interval_ms))); + client_config.transport_config(Arc::new(transport_config)); + } + + Ok(client_config) } fn read_certs_from_file( @@ -343,8 +350,15 @@ pub fn client_endpoint( alpns: Vec, certificate_file: Option, private_key_file: Option, + keep_alive_interval_ms: u64, ) -> Result> { - let client_cfg = configure_client(secure_conn, certificate_file, private_key_file, alpns)?; + let client_cfg = configure_client( + secure_conn, + certificate_file, + private_key_file, + alpns, + keep_alive_interval_ms, + )?; let mut endpoint = Endpoint::client(client_addr)?; endpoint.set_default_client_config(client_cfg);