mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-26 21:41:03 +00:00
net/quic: Allow setting multiple ALPN transport parameters
For reference, see https://datatracker.ietf.org/doc/html/rfc9000#section-7.4 https://datatracker.ietf.org/doc/html/rfc7301 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1036>
This commit is contained in:
parent
75b25d011f
commit
ce930eab5f
3 changed files with 85 additions and 32 deletions
|
@ -22,6 +22,14 @@ use std::sync::Mutex;
|
||||||
static DEFAULT_SERVER_NAME: &str = "localhost";
|
static DEFAULT_SERVER_NAME: &str = "localhost";
|
||||||
static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000";
|
static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000";
|
||||||
static DEFAULT_CLIENT_ADDR: &str = "127.0.0.1:5001";
|
static DEFAULT_CLIENT_ADDR: &str = "127.0.0.1:5001";
|
||||||
|
/*
|
||||||
|
* For QUIC transport parameters
|
||||||
|
* <https://datatracker.ietf.org/doc/html/rfc9000#section-7.4>
|
||||||
|
*
|
||||||
|
* A HTTP client might specify "http/1.1" and/or "h2" or "h3".
|
||||||
|
* Other well-known values are listed in the at IANA registry at
|
||||||
|
* <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>.
|
||||||
|
*/
|
||||||
const DEFAULT_ALPN: &str = "h3";
|
const DEFAULT_ALPN: &str = "h3";
|
||||||
const DEFAULT_TIMEOUT: u32 = 15;
|
const DEFAULT_TIMEOUT: u32 = 15;
|
||||||
const DEFAULT_SECURE_CONNECTION: bool = true;
|
const DEFAULT_SECURE_CONNECTION: bool = true;
|
||||||
|
@ -47,7 +55,7 @@ struct Settings {
|
||||||
client_address: SocketAddr,
|
client_address: SocketAddr,
|
||||||
server_address: SocketAddr,
|
server_address: SocketAddr,
|
||||||
server_name: String,
|
server_name: String,
|
||||||
alpn: String,
|
alpns: Vec<String>,
|
||||||
timeout: u32,
|
timeout: u32,
|
||||||
secure_conn: bool,
|
secure_conn: bool,
|
||||||
use_datagram: bool,
|
use_datagram: bool,
|
||||||
|
@ -59,7 +67,7 @@ impl Default for Settings {
|
||||||
client_address: DEFAULT_CLIENT_ADDR.parse::<SocketAddr>().unwrap(),
|
client_address: DEFAULT_CLIENT_ADDR.parse::<SocketAddr>().unwrap(),
|
||||||
server_address: DEFAULT_SERVER_ADDR.parse::<SocketAddr>().unwrap(),
|
server_address: DEFAULT_SERVER_ADDR.parse::<SocketAddr>().unwrap(),
|
||||||
server_name: DEFAULT_SERVER_NAME.to_string(),
|
server_name: DEFAULT_SERVER_NAME.to_string(),
|
||||||
alpn: DEFAULT_ALPN.to_string(),
|
alpns: vec![DEFAULT_ALPN.to_string()],
|
||||||
timeout: DEFAULT_TIMEOUT,
|
timeout: DEFAULT_TIMEOUT,
|
||||||
secure_conn: DEFAULT_SECURE_CONNECTION,
|
secure_conn: DEFAULT_SECURE_CONNECTION,
|
||||||
use_datagram: false,
|
use_datagram: false,
|
||||||
|
@ -135,9 +143,10 @@ impl ObjectImpl for QuicSink {
|
||||||
.nick("QUIC client address")
|
.nick("QUIC client address")
|
||||||
.blurb("Address to be used by this QUIC client e.g. 127.0.0.1:5001")
|
.blurb("Address to be used by this QUIC client e.g. 127.0.0.1:5001")
|
||||||
.build(),
|
.build(),
|
||||||
glib::ParamSpecString::builder("alpn")
|
gst::ParamSpecArray::builder("alpn-protocols")
|
||||||
.nick("QUIC ALPN value")
|
.nick("QUIC ALPN values")
|
||||||
.blurb("QUIC connection Application-Layer Protocol Negotiation (ALPN) value")
|
.blurb("QUIC connection Application-Layer Protocol Negotiation (ALPN) values")
|
||||||
|
.element_spec(&glib::ParamSpecString::builder("alpn-protocol").build())
|
||||||
.build(),
|
.build(),
|
||||||
glib::ParamSpecUInt::builder("timeout")
|
glib::ParamSpecUInt::builder("timeout")
|
||||||
.nick("Timeout")
|
.nick("Timeout")
|
||||||
|
@ -198,9 +207,19 @@ impl ObjectImpl for QuicSink {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"alpn" => {
|
"alpn-protocols" => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.alpn = value.get::<String>().expect("type checked upstream");
|
settings.alpns = value
|
||||||
|
.get::<gst::ArrayRef>()
|
||||||
|
.expect("type checked upstream")
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|alpn| {
|
||||||
|
alpn.get::<&str>()
|
||||||
|
.expect("type checked upstream")
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
}
|
}
|
||||||
"timeout" => {
|
"timeout" => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
|
@ -232,9 +251,10 @@ impl ObjectImpl for QuicSink {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
settings.client_address.to_string().to_value()
|
settings.client_address.to_string().to_value()
|
||||||
}
|
}
|
||||||
"alpn" => {
|
"alpn-protocols" => {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
settings.alpn.to_value()
|
let alpns = settings.alpns.iter().map(|v| v.as_str());
|
||||||
|
gst::Array::new(alpns).to_value()
|
||||||
}
|
}
|
||||||
"timeout" => {
|
"timeout" => {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
|
@ -439,7 +459,7 @@ impl QuicSink {
|
||||||
let client_addr;
|
let client_addr;
|
||||||
let server_addr;
|
let server_addr;
|
||||||
let server_name;
|
let server_name;
|
||||||
let alpn;
|
let alpns;
|
||||||
let use_datagram;
|
let use_datagram;
|
||||||
let secure_conn;
|
let secure_conn;
|
||||||
|
|
||||||
|
@ -448,12 +468,12 @@ impl QuicSink {
|
||||||
client_addr = settings.client_address;
|
client_addr = settings.client_address;
|
||||||
server_addr = settings.server_address;
|
server_addr = settings.server_address;
|
||||||
server_name = settings.server_name.clone();
|
server_name = settings.server_name.clone();
|
||||||
alpn = settings.alpn.clone();
|
alpns = settings.alpns.clone();
|
||||||
use_datagram = settings.use_datagram;
|
use_datagram = settings.use_datagram;
|
||||||
secure_conn = settings.secure_conn;
|
secure_conn = settings.secure_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
let endpoint = client_endpoint(client_addr, secure_conn, &alpn).map_err(|err| {
|
let endpoint = client_endpoint(client_addr, secure_conn, alpns).map_err(|err| {
|
||||||
WaitError::FutureError(gst::error_msg!(
|
WaitError::FutureError(gst::error_msg!(
|
||||||
gst::ResourceError::Failed,
|
gst::ResourceError::Failed,
|
||||||
["Failed to configure endpoint: {}", err]
|
["Failed to configure endpoint: {}", err]
|
||||||
|
|
|
@ -25,6 +25,14 @@ use std::sync::Mutex;
|
||||||
|
|
||||||
static DEFAULT_SERVER_NAME: &str = "localhost";
|
static DEFAULT_SERVER_NAME: &str = "localhost";
|
||||||
static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000";
|
static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000";
|
||||||
|
/*
|
||||||
|
* For QUIC transport parameters
|
||||||
|
* <https://datatracker.ietf.org/doc/html/rfc9000#section-7.4>
|
||||||
|
*
|
||||||
|
* A HTTP client might specify "http/1.1" and/or "h2" or "h3".
|
||||||
|
* Other well-known values are listed in the at IANA registry at
|
||||||
|
* <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>.
|
||||||
|
*/
|
||||||
const DEFAULT_ALPN: &str = "h3";
|
const DEFAULT_ALPN: &str = "h3";
|
||||||
const DEFAULT_TIMEOUT: u32 = 15;
|
const DEFAULT_TIMEOUT: u32 = 15;
|
||||||
const DEFAULT_PRIVATE_KEY_TYPE: QuicPrivateKeyType = QuicPrivateKeyType::Pkcs8;
|
const DEFAULT_PRIVATE_KEY_TYPE: QuicPrivateKeyType = QuicPrivateKeyType::Pkcs8;
|
||||||
|
@ -54,7 +62,7 @@ enum State {
|
||||||
struct Settings {
|
struct Settings {
|
||||||
server_address: SocketAddr,
|
server_address: SocketAddr,
|
||||||
server_name: String,
|
server_name: String,
|
||||||
alpn: String,
|
alpns: Vec<String>,
|
||||||
timeout: u32,
|
timeout: u32,
|
||||||
secure_conn: bool,
|
secure_conn: bool,
|
||||||
caps: gst::Caps,
|
caps: gst::Caps,
|
||||||
|
@ -68,7 +76,7 @@ impl Default for Settings {
|
||||||
Settings {
|
Settings {
|
||||||
server_address: DEFAULT_SERVER_ADDR.parse::<SocketAddr>().unwrap(),
|
server_address: DEFAULT_SERVER_ADDR.parse::<SocketAddr>().unwrap(),
|
||||||
server_name: DEFAULT_SERVER_NAME.to_string(),
|
server_name: DEFAULT_SERVER_NAME.to_string(),
|
||||||
alpn: DEFAULT_ALPN.to_string(),
|
alpns: vec![DEFAULT_ALPN.to_string()],
|
||||||
timeout: DEFAULT_TIMEOUT,
|
timeout: DEFAULT_TIMEOUT,
|
||||||
secure_conn: DEFAULT_SECURE_CONNECTION,
|
secure_conn: DEFAULT_SECURE_CONNECTION,
|
||||||
caps: gst::Caps::new_any(),
|
caps: gst::Caps::new_any(),
|
||||||
|
@ -170,9 +178,10 @@ impl ObjectImpl for QuicSrc {
|
||||||
.nick("QUIC server address")
|
.nick("QUIC server address")
|
||||||
.blurb("Address of the QUIC server to connect to e.g. 127.0.0.1:5000")
|
.blurb("Address of the QUIC server to connect to e.g. 127.0.0.1:5000")
|
||||||
.build(),
|
.build(),
|
||||||
glib::ParamSpecString::builder("alpn")
|
gst::ParamSpecArray::builder("alpn-protocols")
|
||||||
.nick("QUIC ALPN value")
|
.nick("QUIC ALPN values")
|
||||||
.blurb("QUIC connection Application-Layer Protocol Negotiation (ALPN) value")
|
.blurb("QUIC connection Application-Layer Protocol Negotiation (ALPN) values")
|
||||||
|
.element_spec(&glib::ParamSpecString::builder("alpn-protocol").build())
|
||||||
.build(),
|
.build(),
|
||||||
glib::ParamSpecUInt::builder("timeout")
|
glib::ParamSpecUInt::builder("timeout")
|
||||||
.nick("Timeout")
|
.nick("Timeout")
|
||||||
|
@ -230,9 +239,19 @@ impl ObjectImpl for QuicSrc {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"alpn" => {
|
"alpn-protocols" => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.alpn = value.get::<String>().expect("type checked upstream");
|
settings.alpns = value
|
||||||
|
.get::<gst::ArrayRef>()
|
||||||
|
.expect("type checked upstream")
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|alpn| {
|
||||||
|
alpn.get::<&str>()
|
||||||
|
.expect("type checked upstream")
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
}
|
}
|
||||||
"caps" => {
|
"caps" => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
|
@ -281,9 +300,10 @@ impl ObjectImpl for QuicSrc {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
settings.server_address.to_string().to_value()
|
settings.server_address.to_string().to_value()
|
||||||
}
|
}
|
||||||
"alpn" => {
|
"alpn-protocols" => {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
settings.alpn.to_value()
|
let alpns = settings.alpns.iter().map(|v| v.as_str());
|
||||||
|
gst::Array::new(alpns).to_value()
|
||||||
}
|
}
|
||||||
"caps" => {
|
"caps" => {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
|
@ -535,7 +555,7 @@ impl QuicSrc {
|
||||||
async fn wait_for_connection(&self) -> Result<(Connection, Option<RecvStream>), WaitError> {
|
async fn wait_for_connection(&self) -> Result<(Connection, Option<RecvStream>), WaitError> {
|
||||||
let server_addr;
|
let server_addr;
|
||||||
let server_name;
|
let server_name;
|
||||||
let alpn;
|
let alpns;
|
||||||
let use_datagram;
|
let use_datagram;
|
||||||
let secure_conn;
|
let secure_conn;
|
||||||
let cert_path;
|
let cert_path;
|
||||||
|
@ -545,7 +565,7 @@ impl QuicSrc {
|
||||||
let settings = self.settings.lock().unwrap();
|
let settings = self.settings.lock().unwrap();
|
||||||
server_addr = settings.server_address;
|
server_addr = settings.server_address;
|
||||||
server_name = settings.server_name.clone();
|
server_name = settings.server_name.clone();
|
||||||
alpn = settings.alpn.clone();
|
alpns = settings.alpns.clone();
|
||||||
use_datagram = settings.use_datagram;
|
use_datagram = settings.use_datagram;
|
||||||
secure_conn = settings.secure_conn;
|
secure_conn = settings.secure_conn;
|
||||||
cert_path = settings.certificate_path.clone();
|
cert_path = settings.certificate_path.clone();
|
||||||
|
@ -556,7 +576,7 @@ impl QuicSrc {
|
||||||
server_addr,
|
server_addr,
|
||||||
&server_name,
|
&server_name,
|
||||||
secure_conn,
|
secure_conn,
|
||||||
&alpn,
|
alpns,
|
||||||
cert_path,
|
cert_path,
|
||||||
private_key_type,
|
private_key_type,
|
||||||
)
|
)
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl rustls::client::ServerCertVerifier for SkipServerVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_client(secure_conn: bool, alpn: &str) -> Result<ClientConfig, Box<dyn Error>> {
|
fn configure_client(secure_conn: bool, alpns: Vec<String>) -> Result<ClientConfig, Box<dyn Error>> {
|
||||||
if secure_conn {
|
if secure_conn {
|
||||||
Ok(ClientConfig::with_native_roots())
|
Ok(ClientConfig::with_native_roots())
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,7 +139,11 @@ fn configure_client(secure_conn: bool, alpn: &str) -> Result<ClientConfig, Box<d
|
||||||
.with_safe_defaults()
|
.with_safe_defaults()
|
||||||
.with_custom_certificate_verifier(SkipServerVerification::new())
|
.with_custom_certificate_verifier(SkipServerVerification::new())
|
||||||
.with_no_client_auth();
|
.with_no_client_auth();
|
||||||
crypto.alpn_protocols = vec![alpn.as_bytes().to_vec()];
|
let alpn_protocols: Vec<Vec<u8>> = alpns
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.as_bytes().to_vec())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
crypto.alpn_protocols = alpn_protocols;
|
||||||
|
|
||||||
Ok(ClientConfig::new(Arc::new(crypto)))
|
Ok(ClientConfig::new(Arc::new(crypto)))
|
||||||
}
|
}
|
||||||
|
@ -202,8 +206,8 @@ fn read_certs_from_file(
|
||||||
fn configure_server(
|
fn configure_server(
|
||||||
server_name: &str,
|
server_name: &str,
|
||||||
secure_conn: bool,
|
secure_conn: bool,
|
||||||
alpn: &str,
|
|
||||||
certificate_path: Option<PathBuf>,
|
certificate_path: Option<PathBuf>,
|
||||||
|
alpns: Vec<String>,
|
||||||
private_key_type: QuicPrivateKeyType,
|
private_key_type: QuicPrivateKeyType,
|
||||||
) -> Result<(ServerConfig, Vec<rustls::Certificate>), Box<dyn Error>> {
|
) -> Result<(ServerConfig, Vec<rustls::Certificate>), Box<dyn Error>> {
|
||||||
let (cert, key) = if secure_conn {
|
let (cert, key) = if secure_conn {
|
||||||
|
@ -225,7 +229,11 @@ fn configure_server(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_no_client_auth()
|
.with_no_client_auth()
|
||||||
.with_single_cert(cert.clone(), key)?;
|
.with_single_cert(cert.clone(), key)?;
|
||||||
crypto.alpn_protocols = vec![alpn.as_bytes().to_vec()];
|
let alpn_protocols: Vec<Vec<u8>> = alpns
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.as_bytes().to_vec())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
crypto.alpn_protocols = alpn_protocols;
|
||||||
let mut server_config = ServerConfig::with_crypto(Arc::new(crypto));
|
let mut server_config = ServerConfig::with_crypto(Arc::new(crypto));
|
||||||
|
|
||||||
Arc::get_mut(&mut server_config.transport)
|
Arc::get_mut(&mut server_config.transport)
|
||||||
|
@ -240,12 +248,17 @@ pub fn server_endpoint(
|
||||||
server_addr: SocketAddr,
|
server_addr: SocketAddr,
|
||||||
server_name: &str,
|
server_name: &str,
|
||||||
secure_conn: bool,
|
secure_conn: bool,
|
||||||
alpn: &str,
|
alpns: Vec<String>,
|
||||||
certificate_path: Option<PathBuf>,
|
certificate_path: Option<PathBuf>,
|
||||||
private_key_type: QuicPrivateKeyType,
|
private_key_type: QuicPrivateKeyType,
|
||||||
) -> Result<Endpoint, Box<dyn Error>> {
|
) -> Result<Endpoint, Box<dyn Error>> {
|
||||||
let (server_config, _) =
|
let (server_config, _) = configure_server(
|
||||||
configure_server(server_name, secure_conn, alpn, certificate_path, private_key_type)?;
|
server_name,
|
||||||
|
secure_conn,
|
||||||
|
certificate_path,
|
||||||
|
alpns,
|
||||||
|
private_key_type,
|
||||||
|
)?;
|
||||||
let endpoint = Endpoint::server(server_config, server_addr)?;
|
let endpoint = Endpoint::server(server_config, server_addr)?;
|
||||||
|
|
||||||
Ok(endpoint)
|
Ok(endpoint)
|
||||||
|
@ -254,7 +267,7 @@ pub fn server_endpoint(
|
||||||
pub fn client_endpoint(
|
pub fn client_endpoint(
|
||||||
client_addr: SocketAddr,
|
client_addr: SocketAddr,
|
||||||
secure_conn: bool,
|
secure_conn: bool,
|
||||||
alpn: &str,
|
alpn: Vec<String>,
|
||||||
) -> Result<Endpoint, Box<dyn Error>> {
|
) -> Result<Endpoint, Box<dyn Error>> {
|
||||||
let client_cfg = configure_client(secure_conn, alpn)?;
|
let client_cfg = configure_client(secure_conn, alpn)?;
|
||||||
let mut endpoint = Endpoint::client(client_addr)?;
|
let mut endpoint = Endpoint::client(client_addr)?;
|
||||||
|
|
Loading…
Reference in a new issue