Skip to content

Commit

Permalink
Disable consent if iceConsentTimeout: 0 and do Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
ibc committed Feb 16, 2024
1 parent 8a13f8f commit b9f1d92
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

### Next

- Add server side ICE consent checks to detect silent WebRTC disconnections ([PR #1332](https://github.com/versatica/mediasoup/pull/1332)).

### 3.13.19

- Node: Fix `router.createWebRtcTransport()` with `listenIps` ([PR #1330](https://github.com/versatica/mediasoup/pull/1330)).
Expand Down
49 changes: 47 additions & 2 deletions node/src/test/test-WebRtcTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,57 @@ test('webRtcTransport.connect() succeeds', async () => {
};

await expect(
webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })
webRtcTransport.connect({
dtlsParameters: dtlsRemoteParameters,
})
).resolves.toBeUndefined();

// Must fail if connected.
await expect(
webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters })
webRtcTransport.connect({
dtlsParameters: dtlsRemoteParameters,
})
).rejects.toThrow(Error);

expect(webRtcTransport.dtlsParameters.role).toBe('server');
}, 2000);

test('webRtcTransport.connect() with iceParameters succeeds', async () => {
const webRtcTransport = await ctx.router!.createWebRtcTransport({
listenInfos: [
{ protocol: 'udp', ip: '127.0.0.1', announcedAddress: '9.9.9.1' },
],
});

const iceRemoteParameters: mediasoup.types.IceParameters = {
usernameFragment: 'foo',
password: 'xxxx',
};

const dtlsRemoteParameters: mediasoup.types.DtlsParameters = {
fingerprints: [
{
algorithm: 'sha-256',
value:
'82:5A:68:3D:36:C3:0A:DE:AF:E7:32:43:D2:88:83:57:AC:2D:65:E5:80:C4:B6:FB:AF:1A:A0:21:9F:6D:0C:AD',
},
],
role: 'client',
};

await expect(
webRtcTransport.connect({
iceParameters: iceRemoteParameters,
dtlsParameters: dtlsRemoteParameters,
})
).resolves.toBeUndefined();

// Must fail if connected.
await expect(
webRtcTransport.connect({
iceParameters: iceRemoteParameters,
dtlsParameters: dtlsRemoteParameters,
})
).rejects.toThrow(Error);

expect(webRtcTransport.dtlsParameters.role).toBe('server');
Expand Down
10 changes: 8 additions & 2 deletions rust/examples/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,10 @@ impl Handler<ClientMessage> for EchoConnection {
// synchronous
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down Expand Up @@ -346,7 +349,10 @@ impl Handler<ClientMessage> for EchoConnection {
// The same as producer transport, but for consumer transport
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down
5 changes: 4 additions & 1 deletion rust/examples/multiopus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,10 @@ impl Handler<ClientMessage> for EchoConnection {
// The same as producer transport, but for consumer transport
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down
10 changes: 8 additions & 2 deletions rust/examples/svc-simulcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,10 @@ impl Handler<ClientMessage> for SvcSimulcastConnection {
// synchronous
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down Expand Up @@ -392,7 +395,10 @@ impl Handler<ClientMessage> for SvcSimulcastConnection {
// The same as producer transport, but for consumer transport
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down
10 changes: 8 additions & 2 deletions rust/examples/videoroom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,10 @@ mod participant {
// synchronous
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down Expand Up @@ -718,7 +721,10 @@ mod participant {
// The same as producer transport, but for consumer transport
actix::spawn(async move {
match transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters,
})
.await
{
Ok(_) => {
Expand Down
8 changes: 8 additions & 0 deletions rust/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ pub struct IceParameters {
}

impl IceParameters {
pub(crate) fn to_fbs(&self) -> web_rtc_transport::IceParameters {
web_rtc_transport::IceParameters {
username_fragment: self.username_fragment.to_string(),
password: self.password.to_string(),
ice_lite: self.ice_lite.unwrap_or(false),
}
}

pub(crate) fn from_fbs(parameters: web_rtc_transport::IceParameters) -> Self {
Self {
username_fragment: parameters.username_fragment.to_string(),
Expand Down
11 changes: 9 additions & 2 deletions rust/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ pub(crate) struct RouterCreateWebrtcTransportData {
enable_tcp: bool,
prefer_udp: bool,
prefer_tcp: bool,
ice_consent_timeout: u8,
enable_sctp: bool,
num_sctp_streams: NumSctpStreams,
max_sctp_message_size: u32,
Expand Down Expand Up @@ -701,6 +702,7 @@ impl RouterCreateWebrtcTransportData {
enable_tcp: webrtc_transport_options.enable_tcp,
prefer_udp: webrtc_transport_options.prefer_udp,
prefer_tcp: webrtc_transport_options.prefer_tcp,
ice_consent_timeout: webrtc_transport_options.ice_consent_timeout,
enable_sctp: webrtc_transport_options.enable_sctp,
num_sctp_streams: webrtc_transport_options.num_sctp_streams,
max_sctp_message_size: webrtc_transport_options.max_sctp_message_size,
Expand All @@ -726,6 +728,7 @@ impl RouterCreateWebrtcTransportData {
enable_tcp: self.enable_tcp,
prefer_udp: self.prefer_udp,
prefer_tcp: self.prefer_tcp,
ice_consent_timeout: self.ice_consent_timeout,
}
}
}
Expand Down Expand Up @@ -1405,6 +1408,7 @@ pub(crate) struct WebRtcTransportConnectResponse {

#[derive(Debug)]
pub(crate) struct WebRtcTransportConnectRequest {
pub(crate) ice_parameters: Option<IceParameters>,
pub(crate) dtls_parameters: DtlsParameters,
}

Expand All @@ -1415,8 +1419,11 @@ impl Request for WebRtcTransportConnectRequest {

fn into_bytes(self, id: u32, handler_id: Self::HandlerId) -> Vec<u8> {
let mut builder = Builder::new();
let data =
web_rtc_transport::ConnectRequest::create(&mut builder, self.dtls_parameters.to_fbs());
let data = web_rtc_transport::ConnectRequest::create(
&mut builder,
self.ice_parameters.map(|parameters| parameters.to_fbs()),
self.dtls_parameters.to_fbs(),
);
let request_body =
request::Body::create_web_rtc_transport_connect_request(&mut builder, data);
let request = request::Request::create(
Expand Down
16 changes: 15 additions & 1 deletion rust/src/router/webrtc_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ pub struct WebRtcTransportOptions {
/// Prefer TCP.
/// Default false.
pub prefer_tcp: bool,
/// ICE consent timeout (in seconds). If 0 it is disabled.
/// For it to be enabled, iceParameters must be given in connect() method.
/// Default 30.
pub ice_consent_timeout: u8,
/// Create a SCTP association.
/// Default false.
pub enable_sctp: bool,
Expand All @@ -155,6 +159,7 @@ impl WebRtcTransportOptions {
enable_tcp: false,
prefer_udp: false,
prefer_tcp: false,
ice_consent_timeout: 30,
enable_sctp: false,
num_sctp_streams: NumSctpStreams::default(),
max_sctp_message_size: 262_144,
Expand All @@ -172,6 +177,7 @@ impl WebRtcTransportOptions {
enable_tcp: true,
prefer_udp: false,
prefer_tcp: false,
ice_consent_timeout: 30,
enable_sctp: false,
num_sctp_streams: NumSctpStreams::default(),
max_sctp_message_size: 262_144,
Expand Down Expand Up @@ -384,6 +390,8 @@ impl WebRtcTransportStat {
#[derive(Debug, Clone, PartialOrd, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WebRtcTransportRemoteParameters {
/// Remote ICE parameters.
pub ice_parameters: Option<IceParameters>,
/// Remote DTLS parameters.
pub dtls_parameters: DtlsParameters,
}
Expand Down Expand Up @@ -920,7 +928,7 @@ impl WebRtcTransport {
///
/// # Example
/// ```rust
/// use mediasoup::data_structures::{DtlsParameters, DtlsRole, DtlsFingerprint};
/// use mediasoup::data_structures::{IceParameters, DtlsParameters, DtlsRole, DtlsFingerprint};
/// use mediasoup::webrtc_transport::WebRtcTransportRemoteParameters;
///
/// # async fn f(
Expand All @@ -929,6 +937,11 @@ impl WebRtcTransport {
/// // Calling connect() on a PlainTransport created with comedia and rtcp_mux set.
/// webrtc_transport
/// .connect(WebRtcTransportRemoteParameters {
/// ice_parameters: Some(IceParameters {
/// username_fragment: "foo".to_string(),
/// password: "xxxx".to_string(),
/// ice_lite: None,
/// }),
/// dtls_parameters: DtlsParameters {
/// role: DtlsRole::Server,
/// fingerprints: vec![
Expand Down Expand Up @@ -958,6 +971,7 @@ impl WebRtcTransport {
.request(
self.id(),
WebRtcTransportConnectRequest {
ice_parameters: remote_parameters.ice_parameters,
dtls_parameters: remote_parameters.dtls_parameters,
},
)
Expand Down
70 changes: 67 additions & 3 deletions rust/tests/integration/webrtc_transport.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use futures_lite::future;
use hash_hasher::HashedSet;
use mediasoup::data_structures::{
AppData, DtlsFingerprint, DtlsParameters, DtlsRole, DtlsState, IceCandidateType, IceRole,
IceState, ListenInfo, Protocol, SctpState,
AppData, DtlsFingerprint, DtlsParameters, DtlsRole, DtlsState, IceCandidateType, IceParameters,
IceRole, IceState, ListenInfo, Protocol, SctpState,
};
use mediasoup::prelude::*;
use mediasoup::router::{Router, RouterOptions};
Expand Down Expand Up @@ -418,6 +418,7 @@ fn connect_succeeds() {

transport
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters: dtls_parameters.clone(),
})
.await
Expand All @@ -426,7 +427,70 @@ fn connect_succeeds() {
// Must fail if connected.
assert!(matches!(
transport
.connect(WebRtcTransportRemoteParameters { dtls_parameters })
.connect(WebRtcTransportRemoteParameters {
ice_parameters: None,
dtls_parameters
})
.await,
Err(RequestError::Response { .. }),
));

assert_eq!(transport.dtls_parameters().role, DtlsRole::Server);
});
}

#[test]
fn connect_with_ice_parameters_succeeds() {
future::block_on(async move {
let (_worker, router) = init().await;

let transport = router
.create_webrtc_transport(WebRtcTransportOptions::new(
WebRtcTransportListenInfos::new(ListenInfo {
protocol: Protocol::Udp,
ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
announced_address: Some("9.9.9.1".to_string()),
port: None,
flags: None,
send_buffer_size: None,
recv_buffer_size: None,
}),
))
.await
.expect("Failed to create WebRTC transport");

let ice_parameters = IceParameters {
username_fragment: "foo".to_string(),
password: "xxxx".to_string(),
ice_lite: None,
};

let dtls_parameters = DtlsParameters {
role: DtlsRole::Client,
fingerprints: vec![DtlsFingerprint::Sha256 {
value: [
0x82, 0x5A, 0x68, 0x3D, 0x36, 0xC3, 0x0A, 0xDE, 0xAF, 0xE7, 0x32, 0x43, 0xD2,
0x88, 0x83, 0x57, 0xAC, 0x2D, 0x65, 0xE5, 0x80, 0xC4, 0xB6, 0xFB, 0xAF, 0x1A,
0xA0, 0x21, 0x9F, 0x6D, 0x0C, 0xAD,
],
}],
};

transport
.connect(WebRtcTransportRemoteParameters {
ice_parameters: Some(ice_parameters.clone()),
dtls_parameters: dtls_parameters.clone(),
})
.await
.expect("Failed to establish WebRTC transport connection");

// Must fail if connected.
assert!(matches!(
transport
.connect(WebRtcTransportRemoteParameters {
ice_parameters: Some(ice_parameters),
dtls_parameters
})
.await,
Err(RequestError::Response { .. }),
));
Expand Down
6 changes: 5 additions & 1 deletion worker/src/RTC/IceServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ namespace RTC
{
MS_TRACE();

if (consentTimeoutSec < ConsentCheckMinTimeoutSec)
if (consentTimeoutSec == 0u)
{
// 0 means disabled so it's a valid value.
}
else if (consentTimeoutSec < ConsentCheckMinTimeoutSec)
{
MS_WARN_TAG(
ice,
Expand Down

0 comments on commit b9f1d92

Please sign in to comment.