diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f90a1..aa577f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## unreleased + +* warn when connecting via TCP to a known-broken live555 server version. + ## `v0.3.0` (2021-08-31) * BREAKING CHANGE: [#30](https://github.com/scottlamb/retina/issues/30): diff --git a/src/client/mod.rs b/src/client/mod.rs index 18a4e64..e91417a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -216,6 +216,9 @@ pub struct Presentation { base_url: Url, pub control: Url, pub accept_dynamic_rate: bool, + + /// Session-level `a:tool` from SDP. + tool: Option>, } /// Information about a stream offered within a presentation. @@ -908,6 +911,17 @@ impl Session { "must SETUP before PLAY".into() )) })?; + if let Some(tool) = inner.presentation.tool.as_deref() { + if matches!(inner.options.transport, Transport::Tcp) && has_live555_tcp_bug(tool) { + warn!( + "Connecting via TCP to known-broken RTSP server {:?}. \ + See . \ + Consider using UDP instead!", + tool + ); + } + } + trace!("PLAY with channel mappings: {:#?}", &inner.conn.channels); let (msg_ctx, cseq, response) = inner .conn @@ -1022,6 +1036,17 @@ impl Session { } } +/// Checks if the `tool` entry refers to a live555 version affected by +/// [#17](https://github.com/scottlamb/retina/issues/17). +fn has_live555_tcp_bug(tool: &str) -> bool { + const PREFIX: &str = "LIVE555 Streaming Media v"; + if !tool.starts_with(PREFIX) { + return false; + } + let version = &tool[PREFIX.len()..]; + version > "0000.00.00" && version < "2017.06.04" +} + /// Sends dummy RTP and RTCP packets to punch a hole in connection-tracking /// firewalls. /// @@ -1748,4 +1773,13 @@ mod tests { println!("{:-40} {:4}", name, size); } } + + #[test] + fn check_live555_tcp_bug() { + assert!(!has_live555_tcp_bug("not live555")); + assert!(!has_live555_tcp_bug("LIVE555 Streaming Media v")); + assert!(has_live555_tcp_bug("LIVE555 Streaming Media v2013.04.08")); + assert!(!has_live555_tcp_bug("LIVE555 Streaming Media v2017.06.04")); + assert!(!has_live555_tcp_bug("LIVE555 Streaming Media v2020.01.01")); + } } diff --git a/src/client/parse.rs b/src/client/parse.rs index 2ad1a9e..4082de2 100644 --- a/src/client/parse.rs +++ b/src/client/parse.rs @@ -417,6 +417,7 @@ pub(crate) fn parse_describe( .unwrap_or(Ok(request_url.clone()))?; let mut control = None; + let mut tool = None; for a in &sdp.attributes { if a.key == "control" { control = a @@ -425,6 +426,8 @@ pub(crate) fn parse_describe( .map(|c| join_control(&base_url, c)) .transpose()?; break; + } else if a.key == "tool" { + tool = a.value.as_deref().map(Into::into); } } let control = control.unwrap_or(request_url); @@ -447,6 +450,7 @@ pub(crate) fn parse_describe( base_url, control, accept_dynamic_rate, + tool, }) } @@ -825,6 +829,10 @@ mod tests { let base = "rtsp://192.168.5.206/h264Preview_01_main/"; assert_eq!(p.control.as_str(), base); assert!(!p.accept_dynamic_rate); + assert_eq!( + p.tool.as_deref(), + Some("LIVE555 Streaming Media v2013.04.08") + ); assert_eq!(p.streams.len(), 2); @@ -967,6 +975,10 @@ mod tests { let p = parse_describe(prefix, include_bytes!("testdata/foscam_describe.txt")).unwrap(); assert_eq!(p.control.as_str(), &(prefix.to_string() + "/")); assert!(!p.accept_dynamic_rate); + assert_eq!( + p.tool.as_deref(), + Some("LIVE555 Streaming Media v2014.02.10") + ); assert_eq!(p.streams.len(), 2);