webrtc/signalling: Fix potential hang and FD leak

If a peer connects via TCP and never initiates TLS, then the server
will get stuck in the accept loop. Spawn a task when accepting a TLS
connection, and timeout if it doesn't complete in 5 seconds.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1412>
This commit is contained in:
Nirbheek Chauhan 2023-12-20 18:01:11 +05:30
parent d9397ef174
commit 63b568f4a0
2 changed files with 21 additions and 9 deletions

View file

@ -2,17 +2,20 @@
use clap::Parser; use clap::Parser;
use gst_plugin_webrtc_signalling::handlers::Handler; use gst_plugin_webrtc_signalling::handlers::Handler;
use gst_plugin_webrtc_signalling::server::Server; use gst_plugin_webrtc_signalling::server::{Server, ServerError};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::task; use tokio::task;
use tracing_subscriber::prelude::*; use tracing_subscriber::prelude::*;
use anyhow::Error; use anyhow::Error;
use std::time::Duration;
use tokio::fs; use tokio::fs;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio_native_tls::native_tls::TlsAcceptor; use tokio_native_tls::native_tls::TlsAcceptor;
use tracing::{info, warn}; use tracing::{info, warn};
const TLS_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(5);
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(about, version, author)] #[clap(about, version, author)]
/// Program arguments /// Program arguments
@ -94,15 +97,20 @@ async fn main() -> Result<(), Error> {
info!("Accepting connection from {}", address); info!("Accepting connection from {}", address);
if let Some(ref acceptor) = acceptor { if let Some(acceptor) = acceptor.clone() {
let stream = match acceptor.accept(stream).await { tokio::spawn(async move {
Ok(stream) => stream, match tokio::time::timeout(TLS_HANDSHAKE_TIMEOUT, acceptor.accept(stream)).await {
Err(err) => { Ok(Ok(stream)) => server_clone.accept_async(stream).await,
Ok(Err(err)) => {
warn!("Failed to accept TLS connection from {}: {}", address, err); warn!("Failed to accept TLS connection from {}: {}", address, err);
continue; Err(ServerError::TLSHandshake(err))
} }
}; Err(elapsed) => {
task::spawn(async move { server_clone.accept_async(stream).await }); warn!("TLS connection timed out {} after {}", address, elapsed);
Err(ServerError::TLSHandshakeTimeout(elapsed))
}
}
});
} else { } else {
task::spawn(async move { server_clone.accept_async(stream).await }); task::spawn(async move { server_clone.accept_async(stream).await });
} }

View file

@ -32,6 +32,10 @@ pub struct Server {
pub enum ServerError { pub enum ServerError {
#[error("error during handshake {0}")] #[error("error during handshake {0}")]
Handshake(#[from] async_tungstenite::tungstenite::Error), Handshake(#[from] async_tungstenite::tungstenite::Error),
#[error("error during TLS handshake {0}")]
TLSHandshake(#[from] tokio_native_tls::native_tls::Error),
#[error("timeout during TLS handshake {0}")]
TLSHandshakeTimeout(#[from] tokio::time::error::Elapsed),
} }
impl Server { impl Server {