1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use super::*;
6 use address::{AddressType, ExplicitlyTypedAddress};
7 use attribute_type::{
8     SdpAttributeFmtp, SdpAttributeFmtpParameters, SdpAttributePayloadType, SdpAttributeRtcpFb,
9     SdpAttributeRtcpFbType,
10 };
11 use std::convert::TryFrom;
12 
create_dummy_media_section() -> SdpMedia13 pub fn create_dummy_media_section() -> SdpMedia {
14     let media_line = SdpMediaLine {
15         media: SdpMediaValue::Audio,
16         port: 9,
17         port_count: 0,
18         proto: SdpProtocolValue::RtpSavpf,
19         formats: SdpFormatList::Integers(Vec::new()),
20     };
21     SdpMedia::new(media_line)
22 }
23 
24 // TODO is this useful outside of tests?
25 impl SdpFormatList {
len(&self) -> usize26     fn len(&self) -> usize {
27         match *self {
28             SdpFormatList::Integers(ref x) => x.len(),
29             SdpFormatList::Strings(ref x) => x.len(),
30         }
31     }
32 }
33 
add_dummy_attributes(media: &mut SdpMedia)34 pub fn add_dummy_attributes(media: &mut SdpMedia) {
35     assert!(media
36         .add_attribute(SdpAttribute::Rtcpfb(SdpAttributeRtcpFb {
37             payload_type: SdpAttributePayloadType::Wildcard,
38             feedback_type: SdpAttributeRtcpFbType::Ack,
39             parameter: "".to_string(),
40             extra: "".to_string(),
41         },))
42         .is_ok());
43     assert!(media
44         .add_attribute(SdpAttribute::Fmtp(SdpAttributeFmtp {
45             payload_type: 1,
46             parameters: SdpAttributeFmtpParameters {
47                 packetization_mode: 0,
48                 level_asymmetry_allowed: false,
49                 profile_level_id: 0x0042_0010,
50                 max_fs: 0,
51                 max_cpb: 0,
52                 max_dpb: 0,
53                 max_br: 0,
54                 max_mbps: 0,
55                 usedtx: false,
56                 stereo: false,
57                 useinbandfec: false,
58                 cbr: false,
59                 max_fr: 0,
60                 maxplaybackrate: 48000,
61                 maxaveragebitrate: 0,
62                 ptime: 0,
63                 minptime: 0,
64                 maxptime: 0,
65                 encodings: Vec::new(),
66                 dtmf_tones: "".to_string(),
67                 rtx: None,
68                 unknown_tokens: Vec::new()
69             }
70         },))
71         .is_ok());
72     assert!(media
73         .add_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
74             port: 5000,
75             channels: 2,
76         }))
77         .is_ok());
78     assert!(media.add_attribute(SdpAttribute::BundleOnly).is_ok());
79     assert!(media.add_attribute(SdpAttribute::SctpPort(5000)).is_ok());
80 
81     assert!(media.get_attribute(SdpAttributeType::Rtpmap).is_some());
82     assert!(media.get_attribute(SdpAttributeType::Rtcpfb).is_some());
83     assert!(media.get_attribute(SdpAttributeType::Fmtp).is_some());
84     assert!(media.get_attribute(SdpAttributeType::Sctpmap).is_some());
85     assert!(media.get_attribute(SdpAttributeType::SctpPort).is_some());
86     assert!(media.get_attribute(SdpAttributeType::BundleOnly).is_some());
87 }
88 
check_parse(media_line_str: &str) -> SdpMediaLine89 fn check_parse(media_line_str: &str) -> SdpMediaLine {
90     if let Ok(SdpType::Media(media_line)) = parse_media(media_line_str) {
91         media_line
92     } else {
93         unreachable!()
94     }
95 }
96 
check_parse_and_serialize(media_line_str: &str)97 fn check_parse_and_serialize(media_line_str: &str) {
98     let parsed = check_parse(media_line_str);
99     assert_eq!(parsed.to_string(), media_line_str.to_string());
100 }
101 
102 #[test]
test_get_set_port()103 fn test_get_set_port() {
104     let mut msection = create_dummy_media_section();
105     assert_eq!(msection.get_port(), 9);
106     msection.set_port(2048);
107     assert_eq!(msection.get_port(), 2048);
108 }
109 
110 #[test]
test_add_codec() -> Result<(), SdpParserInternalError>111 fn test_add_codec() -> Result<(), SdpParserInternalError> {
112     let mut msection = create_dummy_media_section();
113     msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
114     assert_eq!(msection.get_formats().len(), 1);
115     assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
116 
117     let mut msection = create_dummy_media_section();
118     msection.media.formats = SdpFormatList::Strings(Vec::new());
119     msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
120     assert_eq!(msection.get_formats().len(), 1);
121     assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
122     Ok(())
123 }
124 
125 #[test]
test_remove_codecs() -> Result<(), SdpParserInternalError>126 fn test_remove_codecs() -> Result<(), SdpParserInternalError> {
127     let mut msection = create_dummy_media_section();
128     msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
129     assert_eq!(msection.get_formats().len(), 1);
130     assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
131     msection.remove_codecs();
132     assert_eq!(msection.get_formats().len(), 0);
133     assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
134 
135     let mut msection = create_dummy_media_section();
136     msection.media.formats = SdpFormatList::Strings(Vec::new());
137     msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
138     assert_eq!(msection.get_formats().len(), 1);
139 
140     add_dummy_attributes(&mut msection);
141 
142     msection.remove_codecs();
143     assert_eq!(msection.get_formats().len(), 0);
144     assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
145     assert!(msection.get_attribute(SdpAttributeType::Rtcpfb).is_none());
146     assert!(msection.get_attribute(SdpAttributeType::Fmtp).is_none());
147     assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
148     assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
149     Ok(())
150 }
151 
152 #[test]
test_add_datachannel() -> Result<(), SdpParserInternalError>153 fn test_add_datachannel() -> Result<(), SdpParserInternalError> {
154     let mut msection = create_dummy_media_section();
155     msection.add_datachannel("foo".to_string(), 5000, 256, 0)?;
156     assert_eq!(*msection.get_type(), SdpMediaValue::Application);
157     assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
158     assert!(msection
159         .get_attribute(SdpAttributeType::MaxMessageSize)
160         .is_none());
161     assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_some());
162     match *msection.get_attribute(SdpAttributeType::Sctpmap).unwrap() {
163         SdpAttribute::Sctpmap(ref s) => {
164             assert_eq!(s.port, 5000);
165             assert_eq!(s.channels, 256);
166         }
167         _ => unreachable!(),
168     }
169 
170     let mut msection = create_dummy_media_section();
171     msection.add_datachannel("foo".to_string(), 5000, 256, 1234)?;
172     assert_eq!(*msection.get_type(), SdpMediaValue::Application);
173     assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
174     assert!(msection
175         .get_attribute(SdpAttributeType::MaxMessageSize)
176         .is_some());
177     match *msection
178         .get_attribute(SdpAttributeType::MaxMessageSize)
179         .unwrap()
180     {
181         SdpAttribute::MaxMessageSize(m) => {
182             assert_eq!(m, 1234);
183         }
184         _ => unreachable!(),
185     }
186 
187     let mut msection = create_dummy_media_section();
188     msection.media.proto = SdpProtocolValue::UdpDtlsSctp;
189     msection.add_datachannel("foo".to_string(), 5000, 256, 5678)?;
190     assert_eq!(*msection.get_type(), SdpMediaValue::Application);
191     assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
192     assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_some());
193     match *msection.get_attribute(SdpAttributeType::SctpPort).unwrap() {
194         SdpAttribute::SctpPort(s) => {
195             assert_eq!(s, 5000);
196         }
197         _ => unreachable!(),
198     }
199     assert!(msection
200         .get_attribute(SdpAttributeType::MaxMessageSize)
201         .is_some());
202     match *msection
203         .get_attribute(SdpAttributeType::MaxMessageSize)
204         .unwrap()
205     {
206         SdpAttribute::MaxMessageSize(m) => {
207             assert_eq!(m, 5678);
208         }
209         _ => unreachable!(),
210     }
211     Ok(())
212 }
213 
214 #[test]
test_parse_media_token() -> Result<(), SdpParserInternalError>215 fn test_parse_media_token() -> Result<(), SdpParserInternalError> {
216     let audio = parse_media_token("audio")?;
217     assert_eq!(audio, SdpMediaValue::Audio);
218     let video = parse_media_token("VIDEO")?;
219     assert_eq!(video, SdpMediaValue::Video);
220     let app = parse_media_token("aPplIcatIOn")?;
221     assert_eq!(app, SdpMediaValue::Application);
222 
223     assert!(parse_media_token("").is_err());
224     assert!(parse_media_token("foobar").is_err());
225     Ok(())
226 }
227 
228 #[test]
test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError>229 fn test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError> {
230     fn parse_and_serialize_protocol_token(
231         token: &str,
232         result: SdpProtocolValue,
233     ) -> Result<(), SdpParserInternalError> {
234         let rtps = parse_protocol_token(token)?;
235         assert_eq!(rtps, result);
236         assert_eq!(rtps.to_string(), token.to_uppercase());
237         Ok(())
238     }
239     parse_and_serialize_protocol_token("rtp/avp", SdpProtocolValue::RtpAvp)?;
240     parse_and_serialize_protocol_token("rtp/avpf", SdpProtocolValue::RtpAvpf)?;
241     parse_and_serialize_protocol_token("rtp/savp", SdpProtocolValue::RtpSavp)?;
242     parse_and_serialize_protocol_token("rtp/savpf", SdpProtocolValue::RtpSavpf)?;
243     parse_and_serialize_protocol_token("udp/tls/rtp/savp", SdpProtocolValue::UdpTlsRtpSavp)?;
244     parse_and_serialize_protocol_token("udp/tls/rtp/savpf", SdpProtocolValue::UdpTlsRtpSavpf)?;
245     parse_and_serialize_protocol_token("TCP/dtls/rtp/savp", SdpProtocolValue::TcpDtlsRtpSavp)?;
246     parse_and_serialize_protocol_token("tcp/DTLS/rtp/savpf", SdpProtocolValue::TcpDtlsRtpSavpf)?;
247 
248     assert!(parse_protocol_token("").is_err());
249     assert!(parse_protocol_token("foobar").is_err());
250     Ok(())
251 }
252 
253 #[test]
test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError>254 fn test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError> {
255     fn parse_and_serialize_protocol_token(
256         token: &str,
257         result: SdpProtocolValue,
258     ) -> Result<(), SdpParserInternalError> {
259         let rtps = parse_protocol_token(token)?;
260         assert_eq!(rtps, result);
261         assert_eq!(rtps.to_string(), token.to_uppercase());
262         Ok(())
263     }
264     parse_and_serialize_protocol_token("dtLs/ScTP", SdpProtocolValue::DtlsSctp)?;
265     parse_and_serialize_protocol_token("udp/DTLS/sctp", SdpProtocolValue::UdpDtlsSctp)?;
266     parse_and_serialize_protocol_token("tcp/dtls/SCTP", SdpProtocolValue::TcpDtlsSctp)?;
267     Ok(())
268 }
269 
270 #[test]
test_media_works()271 fn test_media_works() {
272     check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109");
273     check_parse_and_serialize("video 9 UDP/TLS/RTP/SAVPF 126");
274     check_parse_and_serialize("application 9 DTLS/SCTP 5000");
275     check_parse_and_serialize("application 9 UDP/DTLS/SCTP webrtc-datachannel");
276 
277     check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8");
278     check_parse_and_serialize("audio 0 UDP/TLS/RTP/SAVPF 8");
279     check_parse_and_serialize("audio 9/2 UDP/TLS/RTP/SAVPF 8");
280 }
281 
282 #[test]
test_media_missing_token()283 fn test_media_missing_token() {
284     assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
285 }
286 
287 #[test]
test_media_invalid_port_number()288 fn test_media_invalid_port_number() {
289     assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
290 }
291 
292 #[test]
test_media_invalid_type()293 fn test_media_invalid_type() {
294     assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
295 }
296 
297 #[test]
test_media_invalid_port()298 fn test_media_invalid_port() {
299     assert!(parse_media("audio / UDP/TLS/RTP/SAVPF 8").is_err());
300 }
301 
302 #[test]
test_media_invalid_transport()303 fn test_media_invalid_transport() {
304     assert!(parse_media("audio 9 invalid/invalid 8").is_err());
305 }
306 
307 #[test]
test_media_invalid_payload()308 fn test_media_invalid_payload() {
309     assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
310 }
311 
312 #[test]
test_media_vector_first_line_failure()313 fn test_media_vector_first_line_failure() {
314     let mut sdp_lines: Vec<SdpLine> = Vec::new();
315     let line = SdpLine {
316         line_number: 0,
317         sdp_type: SdpType::Session("hello".to_string()),
318         text: "".to_owned(),
319     };
320     sdp_lines.push(line);
321     assert!(parse_media_vector(&mut sdp_lines).is_err());
322 }
323 
324 #[test]
test_media_vector_multiple_connections()325 fn test_media_vector_multiple_connections() {
326     let mut sdp_lines: Vec<SdpLine> = Vec::new();
327     let media_line = SdpMediaLine {
328         media: SdpMediaValue::Audio,
329         port: 9,
330         port_count: 0,
331         proto: SdpProtocolValue::RtpSavpf,
332         formats: SdpFormatList::Integers(Vec::new()),
333     };
334     let media = SdpLine {
335         line_number: 0,
336         sdp_type: SdpType::Media(media_line),
337         text: "".to_owned(),
338     };
339     sdp_lines.push(media);
340     let c = SdpConnection {
341         address: ExplicitlyTypedAddress::try_from((AddressType::IpV4, "127.0.0.1")).unwrap(),
342         ttl: None,
343         amount: None,
344     };
345     let c1 = SdpLine {
346         line_number: 1,
347         sdp_type: SdpType::Connection(c.clone()),
348         text: "".to_owned(),
349     };
350     sdp_lines.push(c1);
351     let c2 = SdpLine {
352         line_number: 2,
353         sdp_type: SdpType::Connection(c),
354         text: "".to_owned(),
355     };
356     sdp_lines.push(c2);
357     assert!(parse_media_vector(&mut sdp_lines).is_err());
358 }
359 
360 #[test]
test_media_vector_invalid_types()361 fn test_media_vector_invalid_types() {
362     let mut sdp_lines: Vec<SdpLine> = Vec::new();
363     let media_line = SdpMediaLine {
364         media: SdpMediaValue::Audio,
365         port: 9,
366         port_count: 0,
367         proto: SdpProtocolValue::RtpSavpf,
368         formats: SdpFormatList::Integers(Vec::new()),
369     };
370     let media = SdpLine {
371         line_number: 0,
372         sdp_type: SdpType::Media(media_line),
373         text: "".to_owned(),
374     };
375     sdp_lines.push(media);
376     use SdpTiming;
377     let t = SdpTiming { start: 0, stop: 0 };
378     let tline = SdpLine {
379         line_number: 1,
380         sdp_type: SdpType::Timing(t),
381         text: "".to_owned(),
382     };
383     sdp_lines.push(tline);
384     assert!(parse_media_vector(&mut sdp_lines).is_err());
385 }
386 
387 #[test]
test_media_vector_invalid_media_level_attribute()388 fn test_media_vector_invalid_media_level_attribute() {
389     let mut sdp_lines: Vec<SdpLine> = Vec::new();
390     let media_line = SdpMediaLine {
391         media: SdpMediaValue::Audio,
392         port: 9,
393         port_count: 0,
394         proto: SdpProtocolValue::RtpSavpf,
395         formats: SdpFormatList::Integers(Vec::new()),
396     };
397     let media = SdpLine {
398         line_number: 0,
399         sdp_type: SdpType::Media(media_line),
400         text: "".to_owned(),
401     };
402     sdp_lines.push(media);
403     let a = SdpAttribute::IceLite;
404     let aline = SdpLine {
405         line_number: 1,
406         sdp_type: SdpType::Attribute(a),
407         text: "".to_owned(),
408     };
409     sdp_lines.push(aline);
410     assert!(parse_media_vector(&mut sdp_lines).is_err());
411 }
412