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 anonymizer::{AnonymizingClone, StatefulSdpAnonymizer};
6 use attribute_type::{
7     maybe_print_param, SdpAttribute, SdpAttributeRtpmap, SdpAttributeSctpmap, SdpAttributeType,
8 };
9 use error::{SdpParserError, SdpParserInternalError};
10 use std::fmt;
11 use {SdpBandwidth, SdpConnection, SdpLine, SdpType};
12 
13 /*
14  * RFC4566
15  * media-field =         %x6d "=" media SP port ["/" integer]
16  *                       SP proto 1*(SP fmt) CRLF
17  */
18 #[derive(Clone)]
19 #[cfg_attr(feature = "serialize", derive(Serialize))]
20 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
21 pub struct SdpMediaLine {
22     pub media: SdpMediaValue,
23     pub port: u32,
24     pub port_count: u32,
25     pub proto: SdpProtocolValue,
26     pub formats: SdpFormatList,
27 }
28 
29 impl fmt::Display for SdpMediaLine {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result30     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31         write!(
32             f,
33             "{media} {port}{pcount} {proto} {formats}",
34             media = self.media,
35             port = self.port,
36             pcount = maybe_print_param("/", self.port_count, 0),
37             proto = self.proto,
38             formats = self.formats
39         )
40     }
41 }
42 
43 #[derive(Debug, PartialEq, Clone)]
44 #[cfg_attr(feature = "serialize", derive(Serialize))]
45 pub enum SdpMediaValue {
46     Audio,
47     Video,
48     Application,
49 }
50 
51 impl fmt::Display for SdpMediaValue {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result52     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53         match *self {
54             SdpMediaValue::Audio => "audio",
55             SdpMediaValue::Video => "video",
56             SdpMediaValue::Application => "application",
57         }
58         .fmt(f)
59     }
60 }
61 
62 #[derive(Debug, PartialEq, Clone)]
63 #[cfg_attr(feature = "serialize", derive(Serialize))]
64 pub enum SdpProtocolValue {
65     RtpAvp,          /* RTP/AVP [RFC4566] */
66     RtpAvpf,         /* RTP/AVPF [RFC4585] */
67     RtpSavp,         /* RTP/SAVP [RFC3711] */
68     RtpSavpf,        /* RTP/SAVPF [RFC5124] */
69     TcpDtlsRtpSavp,  /* TCP/DTLS/RTP/SAVP [RFC7850] */
70     TcpDtlsRtpSavpf, /* TCP/DTLS/RTP/SAVPF [RFC7850] */
71     UdpTlsRtpSavp,   /* UDP/TLS/RTP/SAVP [RFC5764] */
72     UdpTlsRtpSavpf,  /* UDP/TLS/RTP/SAVPF [RFC5764] */
73     DtlsSctp,        /* DTLS/SCTP [draft-ietf-mmusic-sctp-sdp-07] */
74     UdpDtlsSctp,     /* UDP/DTLS/SCTP [draft-ietf-mmusic-sctp-sdp-26] */
75     TcpDtlsSctp,     /* TCP/DTLS/SCTP [draft-ietf-mmusic-sctp-sdp-26] */
76 }
77 
78 impl fmt::Display for SdpProtocolValue {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result79     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80         match *self {
81             SdpProtocolValue::RtpAvp => "RTP/AVP",
82             SdpProtocolValue::RtpAvpf => "RTP/AVPF",
83             SdpProtocolValue::RtpSavp => "RTP/SAVP",
84             SdpProtocolValue::RtpSavpf => "RTP/SAVPF",
85             SdpProtocolValue::TcpDtlsRtpSavp => "TCP/DTLS/RTP/SAVP",
86             SdpProtocolValue::TcpDtlsRtpSavpf => "TCP/DTLS/RTP/SAVPF",
87             SdpProtocolValue::UdpTlsRtpSavp => "UDP/TLS/RTP/SAVP",
88             SdpProtocolValue::UdpTlsRtpSavpf => "UDP/TLS/RTP/SAVPF",
89             SdpProtocolValue::DtlsSctp => "DTLS/SCTP",
90             SdpProtocolValue::UdpDtlsSctp => "UDP/DTLS/SCTP",
91             SdpProtocolValue::TcpDtlsSctp => "TCP/DTLS/SCTP",
92         }
93         .fmt(f)
94     }
95 }
96 
97 #[derive(Clone)]
98 #[cfg_attr(feature = "serialize", derive(Serialize))]
99 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
100 pub enum SdpFormatList {
101     Integers(Vec<u32>),
102     Strings(Vec<String>),
103 }
104 
105 impl fmt::Display for SdpFormatList {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107         match *self {
108             SdpFormatList::Integers(ref x) => maybe_vector_to_string!("{}", x, " "),
109             SdpFormatList::Strings(ref x) => x.join(" "),
110         }
111         .fmt(f)
112     }
113 }
114 
115 /*
116  * RFC4566
117  * media-descriptions =  *( media-field
118  *                       information-field
119  *                       *connection-field
120  *                       bandwidth-fields
121  *                       key-field
122  *                       attribute-fields )
123  */
124 #[derive(Clone)]
125 #[cfg_attr(feature = "serialize", derive(Serialize))]
126 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
127 pub struct SdpMedia {
128     media: SdpMediaLine,
129     connection: Option<SdpConnection>,
130     bandwidth: Vec<SdpBandwidth>,
131     attribute: Vec<SdpAttribute>,
132     // unsupported values:
133     // information: Option<String>,
134     // key: Option<String>,
135 }
136 
137 impl fmt::Display for SdpMedia {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result138     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139         write!(
140             f,
141             "m={mline}\r\n{bw}{connection}{attributes}",
142             mline = self.media,
143             bw = maybe_vector_to_string!("b={}\r\n", self.bandwidth, "\r\nb="),
144             connection = option_to_string!("c={}\r\n", self.connection),
145             attributes = maybe_vector_to_string!("a={}\r\n", self.attribute, "\r\na=")
146         )
147     }
148 }
149 
150 impl SdpMedia {
new(media: SdpMediaLine) -> SdpMedia151     pub fn new(media: SdpMediaLine) -> SdpMedia {
152         SdpMedia {
153             media,
154             connection: None,
155             bandwidth: Vec::new(),
156             attribute: Vec::new(),
157         }
158     }
159 
get_type(&self) -> &SdpMediaValue160     pub fn get_type(&self) -> &SdpMediaValue {
161         &self.media.media
162     }
163 
set_port(&mut self, port: u32)164     pub fn set_port(&mut self, port: u32) {
165         self.media.port = port;
166     }
167 
get_port(&self) -> u32168     pub fn get_port(&self) -> u32 {
169         self.media.port
170     }
171 
get_port_count(&self) -> u32172     pub fn get_port_count(&self) -> u32 {
173         self.media.port_count
174     }
175 
get_proto(&self) -> &SdpProtocolValue176     pub fn get_proto(&self) -> &SdpProtocolValue {
177         &self.media.proto
178     }
179 
get_formats(&self) -> &SdpFormatList180     pub fn get_formats(&self) -> &SdpFormatList {
181         &self.media.formats
182     }
183 
get_bandwidth(&self) -> &Vec<SdpBandwidth>184     pub fn get_bandwidth(&self) -> &Vec<SdpBandwidth> {
185         &self.bandwidth
186     }
187 
add_bandwidth(&mut self, bw: SdpBandwidth)188     pub fn add_bandwidth(&mut self, bw: SdpBandwidth) {
189         self.bandwidth.push(bw)
190     }
191 
get_attributes(&self) -> &Vec<SdpAttribute>192     pub fn get_attributes(&self) -> &Vec<SdpAttribute> {
193         &self.attribute
194     }
195 
add_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError>196     pub fn add_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError> {
197         if !attr.allowed_at_media_level() {
198             return Err(SdpParserInternalError::Generic(format!(
199                 "{} not allowed at media level",
200                 attr
201             )));
202         }
203         self.attribute.push(attr);
204         Ok(())
205     }
206 
get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute>207     pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
208         self.attribute
209             .iter()
210             .find(|a| SdpAttributeType::from(*a) == t)
211     }
212 
remove_attribute(&mut self, t: SdpAttributeType)213     pub fn remove_attribute(&mut self, t: SdpAttributeType) {
214         self.attribute.retain(|a| SdpAttributeType::from(a) != t);
215     }
216 
set_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError>217     pub fn set_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError> {
218         self.remove_attribute(SdpAttributeType::from(&attr));
219         self.add_attribute(attr)
220     }
221 
remove_codecs(&mut self)222     pub fn remove_codecs(&mut self) {
223         match self.media.formats {
224             SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
225             SdpFormatList::Strings(_) => self.media.formats = SdpFormatList::Strings(Vec::new()),
226         }
227 
228         self.attribute.retain({
229             |x| {
230                 !matches!(
231                     *x,
232                     SdpAttribute::Rtpmap(_)
233                         | SdpAttribute::Fmtp(_)
234                         | SdpAttribute::Rtcpfb(_)
235                         | SdpAttribute::Sctpmap(_)
236                         | SdpAttribute::SctpPort(_)
237                 )
238             }
239         });
240     }
241 
add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(), SdpParserInternalError>242     pub fn add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(), SdpParserInternalError> {
243         match self.media.formats {
244             SdpFormatList::Integers(ref mut x) => x.push(u32::from(rtpmap.payload_type)),
245             SdpFormatList::Strings(ref mut x) => x.push(rtpmap.payload_type.to_string()),
246         }
247 
248         self.add_attribute(SdpAttribute::Rtpmap(rtpmap))?;
249         Ok(())
250     }
251 
get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute>252     pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
253         self.attribute
254             .iter()
255             .filter(|a| SdpAttributeType::from(*a) == t)
256             .collect()
257     }
258 
get_connection(&self) -> &Option<SdpConnection>259     pub fn get_connection(&self) -> &Option<SdpConnection> {
260         &self.connection
261     }
262 
set_connection(&mut self, c: SdpConnection)263     pub fn set_connection(&mut self, c: SdpConnection) {
264         self.connection = Some(c)
265     }
266 
add_datachannel( &mut self, name: String, port: u16, streams: u16, msg_size: u32, ) -> Result<(), SdpParserInternalError>267     pub fn add_datachannel(
268         &mut self,
269         name: String,
270         port: u16,
271         streams: u16,
272         msg_size: u32,
273     ) -> Result<(), SdpParserInternalError> {
274         // Only one allowed, for now. This may change as the specs (and deployments) evolve.
275         match self.media.proto {
276             SdpProtocolValue::UdpDtlsSctp | SdpProtocolValue::TcpDtlsSctp => {
277                 // new data channel format according to draft 21
278                 self.media.formats = SdpFormatList::Strings(vec![name]);
279                 self.set_attribute(SdpAttribute::SctpPort(u64::from(port)))?;
280             }
281             _ => {
282                 // old data channels format according to draft 05
283                 self.media.formats = SdpFormatList::Integers(vec![u32::from(port)]);
284                 self.set_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
285                     port,
286                     channels: u32::from(streams),
287                 }))?;
288             }
289         }
290         if msg_size > 0 {
291             self.set_attribute(SdpAttribute::MaxMessageSize(u64::from(msg_size)))?;
292         }
293         self.media.media = SdpMediaValue::Application;
294 
295         Ok(())
296     }
297 }
298 
299 impl AnonymizingClone for SdpMedia {
masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self300     fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
301         let mut masked = SdpMedia {
302             media: self.media.clone(),
303             bandwidth: self.bandwidth.clone(),
304             connection: self.connection.clone(),
305             attribute: Vec::new(),
306         };
307         for i in &self.attribute {
308             masked.attribute.push(i.masked_clone(anon));
309         }
310         masked
311     }
312 }
313 
parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserInternalError>314 fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserInternalError> {
315     Ok(match value.to_lowercase().as_ref() {
316         "audio" => SdpMediaValue::Audio,
317         "video" => SdpMediaValue::Video,
318         "application" => SdpMediaValue::Application,
319         _ => {
320             return Err(SdpParserInternalError::Unsupported(format!(
321                 "unsupported media value: {}",
322                 value
323             )));
324         }
325     })
326 }
327 
parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserInternalError>328 fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserInternalError> {
329     Ok(match value.to_uppercase().as_ref() {
330         "RTP/AVP" => SdpProtocolValue::RtpAvp,
331         "RTP/AVPF" => SdpProtocolValue::RtpAvpf,
332         "RTP/SAVP" => SdpProtocolValue::RtpSavp,
333         "RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
334         "TCP/DTLS/RTP/SAVP" => SdpProtocolValue::TcpDtlsRtpSavp,
335         "TCP/DTLS/RTP/SAVPF" => SdpProtocolValue::TcpDtlsRtpSavpf,
336         "UDP/TLS/RTP/SAVP" => SdpProtocolValue::UdpTlsRtpSavp,
337         "UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
338         "DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
339         "UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
340         "TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
341         _ => {
342             return Err(SdpParserInternalError::Unsupported(format!(
343                 "unsupported protocol value: {}",
344                 value
345             )));
346         }
347     })
348 }
349 
parse_media(value: &str) -> Result<SdpType, SdpParserInternalError>350 pub fn parse_media(value: &str) -> Result<SdpType, SdpParserInternalError> {
351     let mv: Vec<&str> = value.split_whitespace().collect();
352     if mv.len() < 4 {
353         return Err(SdpParserInternalError::Generic(
354             "media attribute must have at least four tokens".to_string(),
355         ));
356     }
357     let media = parse_media_token(mv[0])?;
358     let mut ptokens = mv[1].split('/');
359     let port = match ptokens.next() {
360         None => {
361             return Err(SdpParserInternalError::Generic(
362                 "missing port token".to_string(),
363             ));
364         }
365         Some(p) => p.parse::<u32>()?,
366     };
367     if port > 65535 {
368         return Err(SdpParserInternalError::Generic(
369             "media port token is too big".to_string(),
370         ));
371     }
372     let port_count = match ptokens.next() {
373         None => 0,
374         Some(c) => c.parse::<u32>()?,
375     };
376     let proto = parse_protocol_token(mv[2])?;
377     let fmt_slice: &[&str] = &mv[3..];
378     let formats = match media {
379         SdpMediaValue::Audio | SdpMediaValue::Video => {
380             let mut fmt_vec: Vec<u32> = vec![];
381             for num in fmt_slice {
382                 let fmt_num = num.parse::<u32>()?;
383                 match fmt_num {
384                     0  |  // PCMU
385                     8  |  // PCMA
386                     9  |  // G722
387                     13 |  // Comfort Noise
388                     35 ..= 63 | 96 ..= 127 => (),  // dynamic range
389                     _ => return Err(SdpParserInternalError::Generic(
390                           "format number in media line is out of range".to_string()))
391                 };
392                 fmt_vec.push(fmt_num);
393             }
394             SdpFormatList::Integers(fmt_vec)
395         }
396         SdpMediaValue::Application => {
397             let mut fmt_vec: Vec<String> = vec![];
398             // TODO enforce length == 1 and content 'webrtc-datachannel' only?
399             for token in fmt_slice {
400                 fmt_vec.push(String::from(*token));
401             }
402             SdpFormatList::Strings(fmt_vec)
403         }
404     };
405     let m = SdpMediaLine {
406         media,
407         port,
408         port_count,
409         proto,
410         formats,
411     };
412     trace!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
413     Ok(SdpType::Media(m))
414 }
415 
parse_media_vector(lines: &mut Vec<SdpLine>) -> Result<Vec<SdpMedia>, SdpParserError>416 pub fn parse_media_vector(lines: &mut Vec<SdpLine>) -> Result<Vec<SdpMedia>, SdpParserError> {
417     let mut media_sections: Vec<SdpMedia> = Vec::new();
418 
419     let media_line = lines.remove(0);
420     let mut sdp_media = match media_line.sdp_type {
421         SdpType::Media(v) => SdpMedia::new(v),
422         _ => {
423             return Err(SdpParserError::Sequence {
424                 message: "first line in media section needs to be a media line".to_string(),
425                 line_number: media_line.line_number,
426             });
427         }
428     };
429 
430     while !lines.is_empty() {
431         let line = lines.remove(0);
432         let _line_number = line.line_number;
433         match line.sdp_type {
434             SdpType::Connection(c) => {
435                 if sdp_media.connection.is_some() {
436                     return Err(SdpParserError::Sequence {
437                         message: "connection type already exists at this media level".to_string(),
438                         line_number: _line_number,
439                     });
440                 }
441 
442                 sdp_media.set_connection(c);
443             }
444             SdpType::Bandwidth(b) => sdp_media.add_bandwidth(b),
445             SdpType::Attribute(a) => {
446                 match a {
447                     SdpAttribute::DtlsMessage(_) => {
448                         // Ignore this attribute on media level
449                         Ok(())
450                     }
451                     SdpAttribute::Rtpmap(rtpmap) => {
452                         sdp_media.add_attribute(SdpAttribute::Rtpmap(SdpAttributeRtpmap {
453                             payload_type: rtpmap.payload_type,
454                             codec_name: rtpmap.codec_name.clone(),
455                             frequency: rtpmap.frequency,
456                             channels: rtpmap.channels,
457                         }))
458                     }
459                     _ => sdp_media.add_attribute(a),
460                 }
461                 .map_err(|e: SdpParserInternalError| SdpParserError::Sequence {
462                     message: format!("{}", e),
463                     line_number: _line_number,
464                 })?
465             }
466             SdpType::Media(v) => {
467                 media_sections.push(sdp_media);
468                 sdp_media = SdpMedia::new(v);
469             }
470 
471             SdpType::Origin(_) | SdpType::Session(_) | SdpType::Timing(_) | SdpType::Version(_) => {
472                 return Err(SdpParserError::Sequence {
473                     message: "invalid type in media section".to_string(),
474                     line_number: line.line_number,
475                 });
476             }
477         };
478     }
479 
480     media_sections.push(sdp_media);
481 
482     Ok(media_sections)
483 }
484 
485 #[cfg(test)]
create_dummy_media_section() -> SdpMedia486 pub fn create_dummy_media_section() -> SdpMedia {
487     let media_line = SdpMediaLine {
488         media: SdpMediaValue::Audio,
489         port: 9,
490         port_count: 0,
491         proto: SdpProtocolValue::RtpSavpf,
492         formats: SdpFormatList::Integers(Vec::new()),
493     };
494     SdpMedia::new(media_line)
495 }
496 
497 #[cfg(test)]
498 mod tests {
499     use super::*;
500     use address::{AddressType, ExplicitlyTypedAddress};
501     use attribute_type::{
502         SdpAttributeFmtp, SdpAttributeFmtpParameters, SdpAttributePayloadType, SdpAttributeRtcpFb,
503         SdpAttributeRtcpFbType,
504     };
505     use std::convert::TryFrom;
506 
507     // TODO is this useful outside of tests?
508     impl SdpFormatList {
len(&self) -> usize509         fn len(&self) -> usize {
510             match *self {
511                 SdpFormatList::Integers(ref x) => x.len(),
512                 SdpFormatList::Strings(ref x) => x.len(),
513             }
514         }
515     }
516 
add_dummy_attributes(media: &mut SdpMedia)517     pub fn add_dummy_attributes(media: &mut SdpMedia) {
518         assert!(media
519             .add_attribute(SdpAttribute::Rtcpfb(SdpAttributeRtcpFb {
520                 payload_type: SdpAttributePayloadType::Wildcard,
521                 feedback_type: SdpAttributeRtcpFbType::Ack,
522                 parameter: "".to_string(),
523                 extra: "".to_string(),
524             },))
525             .is_ok());
526         assert!(media
527             .add_attribute(SdpAttribute::Fmtp(SdpAttributeFmtp {
528                 payload_type: 1,
529                 parameters: SdpAttributeFmtpParameters {
530                     packetization_mode: 0,
531                     level_asymmetry_allowed: false,
532                     profile_level_id: 0x0042_0010,
533                     max_fs: 0,
534                     max_cpb: 0,
535                     max_dpb: 0,
536                     max_br: 0,
537                     max_mbps: 0,
538                     usedtx: false,
539                     stereo: false,
540                     useinbandfec: false,
541                     cbr: false,
542                     max_fr: 0,
543                     maxplaybackrate: 48000,
544                     maxaveragebitrate: 0,
545                     ptime: 0,
546                     minptime: 0,
547                     maxptime: 0,
548                     encodings: Vec::new(),
549                     dtmf_tones: "".to_string(),
550                     rtx: None,
551                     unknown_tokens: Vec::new()
552                 }
553             },))
554             .is_ok());
555         assert!(media
556             .add_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
557                 port: 5000,
558                 channels: 2,
559             }))
560             .is_ok());
561         assert!(media.add_attribute(SdpAttribute::BundleOnly).is_ok());
562         assert!(media.add_attribute(SdpAttribute::SctpPort(5000)).is_ok());
563 
564         assert!(media.get_attribute(SdpAttributeType::Rtpmap).is_some());
565         assert!(media.get_attribute(SdpAttributeType::Rtcpfb).is_some());
566         assert!(media.get_attribute(SdpAttributeType::Fmtp).is_some());
567         assert!(media.get_attribute(SdpAttributeType::Sctpmap).is_some());
568         assert!(media.get_attribute(SdpAttributeType::SctpPort).is_some());
569         assert!(media.get_attribute(SdpAttributeType::BundleOnly).is_some());
570     }
571 
check_parse(media_line_str: &str) -> SdpMediaLine572     fn check_parse(media_line_str: &str) -> SdpMediaLine {
573         if let Ok(SdpType::Media(media_line)) = parse_media(media_line_str) {
574             media_line
575         } else {
576             unreachable!()
577         }
578     }
579 
check_parse_and_serialize(media_line_str: &str)580     fn check_parse_and_serialize(media_line_str: &str) {
581         let parsed = check_parse(media_line_str);
582         assert_eq!(parsed.to_string(), media_line_str.to_string());
583     }
584 
585     #[test]
test_get_set_port()586     fn test_get_set_port() {
587         let mut msection = create_dummy_media_section();
588         assert_eq!(msection.get_port(), 9);
589         msection.set_port(2048);
590         assert_eq!(msection.get_port(), 2048);
591     }
592 
593     #[test]
test_add_codec() -> Result<(), SdpParserInternalError>594     fn test_add_codec() -> Result<(), SdpParserInternalError> {
595         let mut msection = create_dummy_media_section();
596         msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
597         assert_eq!(msection.get_formats().len(), 1);
598         assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
599 
600         let mut msection = create_dummy_media_section();
601         msection.media.formats = SdpFormatList::Strings(Vec::new());
602         msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
603         assert_eq!(msection.get_formats().len(), 1);
604         assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
605         Ok(())
606     }
607 
608     #[test]
test_remove_codecs() -> Result<(), SdpParserInternalError>609     fn test_remove_codecs() -> Result<(), SdpParserInternalError> {
610         let mut msection = create_dummy_media_section();
611         msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
612         assert_eq!(msection.get_formats().len(), 1);
613         assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
614         msection.remove_codecs();
615         assert_eq!(msection.get_formats().len(), 0);
616         assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
617 
618         let mut msection = create_dummy_media_section();
619         msection.media.formats = SdpFormatList::Strings(Vec::new());
620         msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
621         assert_eq!(msection.get_formats().len(), 1);
622 
623         add_dummy_attributes(&mut msection);
624 
625         msection.remove_codecs();
626         assert_eq!(msection.get_formats().len(), 0);
627         assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
628         assert!(msection.get_attribute(SdpAttributeType::Rtcpfb).is_none());
629         assert!(msection.get_attribute(SdpAttributeType::Fmtp).is_none());
630         assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
631         assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
632         Ok(())
633     }
634 
635     #[test]
test_add_datachannel() -> Result<(), SdpParserInternalError>636     fn test_add_datachannel() -> Result<(), SdpParserInternalError> {
637         let mut msection = create_dummy_media_section();
638         msection.add_datachannel("foo".to_string(), 5000, 256, 0)?;
639         assert_eq!(*msection.get_type(), SdpMediaValue::Application);
640         assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
641         assert!(msection
642             .get_attribute(SdpAttributeType::MaxMessageSize)
643             .is_none());
644         assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_some());
645         match *msection.get_attribute(SdpAttributeType::Sctpmap).unwrap() {
646             SdpAttribute::Sctpmap(ref s) => {
647                 assert_eq!(s.port, 5000);
648                 assert_eq!(s.channels, 256);
649             }
650             _ => unreachable!(),
651         }
652 
653         let mut msection = create_dummy_media_section();
654         msection.add_datachannel("foo".to_string(), 5000, 256, 1234)?;
655         assert_eq!(*msection.get_type(), SdpMediaValue::Application);
656         assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
657         assert!(msection
658             .get_attribute(SdpAttributeType::MaxMessageSize)
659             .is_some());
660         match *msection
661             .get_attribute(SdpAttributeType::MaxMessageSize)
662             .unwrap()
663         {
664             SdpAttribute::MaxMessageSize(m) => {
665                 assert_eq!(m, 1234);
666             }
667             _ => unreachable!(),
668         }
669 
670         let mut msection = create_dummy_media_section();
671         msection.media.proto = SdpProtocolValue::UdpDtlsSctp;
672         msection.add_datachannel("foo".to_string(), 5000, 256, 5678)?;
673         assert_eq!(*msection.get_type(), SdpMediaValue::Application);
674         assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
675         assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_some());
676         match *msection.get_attribute(SdpAttributeType::SctpPort).unwrap() {
677             SdpAttribute::SctpPort(s) => {
678                 assert_eq!(s, 5000);
679             }
680             _ => unreachable!(),
681         }
682         assert!(msection
683             .get_attribute(SdpAttributeType::MaxMessageSize)
684             .is_some());
685         match *msection
686             .get_attribute(SdpAttributeType::MaxMessageSize)
687             .unwrap()
688         {
689             SdpAttribute::MaxMessageSize(m) => {
690                 assert_eq!(m, 5678);
691             }
692             _ => unreachable!(),
693         }
694         Ok(())
695     }
696 
697     #[test]
test_parse_media_token() -> Result<(), SdpParserInternalError>698     fn test_parse_media_token() -> Result<(), SdpParserInternalError> {
699         let audio = parse_media_token("audio")?;
700         assert_eq!(audio, SdpMediaValue::Audio);
701         let video = parse_media_token("VIDEO")?;
702         assert_eq!(video, SdpMediaValue::Video);
703         let app = parse_media_token("aPplIcatIOn")?;
704         assert_eq!(app, SdpMediaValue::Application);
705 
706         assert!(parse_media_token("").is_err());
707         assert!(parse_media_token("foobar").is_err());
708         Ok(())
709     }
710 
711     #[test]
test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError>712     fn test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError> {
713         fn parse_and_serialize_protocol_token(
714             token: &str,
715             result: SdpProtocolValue,
716         ) -> Result<(), SdpParserInternalError> {
717             let rtps = parse_protocol_token(token)?;
718             assert_eq!(rtps, result);
719             assert_eq!(rtps.to_string(), token.to_uppercase());
720             Ok(())
721         }
722         parse_and_serialize_protocol_token("rtp/avp", SdpProtocolValue::RtpAvp)?;
723         parse_and_serialize_protocol_token("rtp/avpf", SdpProtocolValue::RtpAvpf)?;
724         parse_and_serialize_protocol_token("rtp/savp", SdpProtocolValue::RtpSavp)?;
725         parse_and_serialize_protocol_token("rtp/savpf", SdpProtocolValue::RtpSavpf)?;
726         parse_and_serialize_protocol_token("udp/tls/rtp/savp", SdpProtocolValue::UdpTlsRtpSavp)?;
727         parse_and_serialize_protocol_token("udp/tls/rtp/savpf", SdpProtocolValue::UdpTlsRtpSavpf)?;
728         parse_and_serialize_protocol_token("TCP/dtls/rtp/savp", SdpProtocolValue::TcpDtlsRtpSavp)?;
729         parse_and_serialize_protocol_token(
730             "tcp/DTLS/rtp/savpf",
731             SdpProtocolValue::TcpDtlsRtpSavpf,
732         )?;
733 
734         assert!(parse_protocol_token("").is_err());
735         assert!(parse_protocol_token("foobar").is_err());
736         Ok(())
737     }
738 
739     #[test]
test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError>740     fn test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError> {
741         fn parse_and_serialize_protocol_token(
742             token: &str,
743             result: SdpProtocolValue,
744         ) -> Result<(), SdpParserInternalError> {
745             let rtps = parse_protocol_token(token)?;
746             assert_eq!(rtps, result);
747             assert_eq!(rtps.to_string(), token.to_uppercase());
748             Ok(())
749         }
750         parse_and_serialize_protocol_token("dtLs/ScTP", SdpProtocolValue::DtlsSctp)?;
751         parse_and_serialize_protocol_token("udp/DTLS/sctp", SdpProtocolValue::UdpDtlsSctp)?;
752         parse_and_serialize_protocol_token("tcp/dtls/SCTP", SdpProtocolValue::TcpDtlsSctp)?;
753         Ok(())
754     }
755 
756     #[test]
test_media_works()757     fn test_media_works() {
758         check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109");
759         check_parse_and_serialize("video 9 UDP/TLS/RTP/SAVPF 126");
760         check_parse_and_serialize("application 9 DTLS/SCTP 5000");
761         check_parse_and_serialize("application 9 UDP/DTLS/SCTP webrtc-datachannel");
762 
763         check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8");
764         check_parse_and_serialize("audio 0 UDP/TLS/RTP/SAVPF 8");
765         check_parse_and_serialize("audio 9/2 UDP/TLS/RTP/SAVPF 8");
766     }
767 
768     #[test]
test_media_missing_token()769     fn test_media_missing_token() {
770         assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
771     }
772 
773     #[test]
test_media_invalid_port_number()774     fn test_media_invalid_port_number() {
775         assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
776     }
777 
778     #[test]
test_media_invalid_type()779     fn test_media_invalid_type() {
780         assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
781     }
782 
783     #[test]
test_media_invalid_port()784     fn test_media_invalid_port() {
785         assert!(parse_media("audio / UDP/TLS/RTP/SAVPF 8").is_err());
786     }
787 
788     #[test]
test_media_invalid_transport()789     fn test_media_invalid_transport() {
790         assert!(parse_media("audio 9 invalid/invalid 8").is_err());
791     }
792 
793     #[test]
test_media_invalid_payload()794     fn test_media_invalid_payload() {
795         assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
796     }
797 
798     #[test]
test_media_vector_first_line_failure()799     fn test_media_vector_first_line_failure() {
800         let mut sdp_lines: Vec<SdpLine> = Vec::new();
801         let line = SdpLine {
802             line_number: 0,
803             sdp_type: SdpType::Session("hello".to_string()),
804             text: "".to_owned(),
805         };
806         sdp_lines.push(line);
807         assert!(parse_media_vector(&mut sdp_lines).is_err());
808     }
809 
810     #[test]
test_media_vector_multiple_connections()811     fn test_media_vector_multiple_connections() {
812         let mut sdp_lines: Vec<SdpLine> = Vec::new();
813         let media_line = SdpMediaLine {
814             media: SdpMediaValue::Audio,
815             port: 9,
816             port_count: 0,
817             proto: SdpProtocolValue::RtpSavpf,
818             formats: SdpFormatList::Integers(Vec::new()),
819         };
820         let media = SdpLine {
821             line_number: 0,
822             sdp_type: SdpType::Media(media_line),
823             text: "".to_owned(),
824         };
825         sdp_lines.push(media);
826         let c = SdpConnection {
827             address: ExplicitlyTypedAddress::try_from((AddressType::IpV4, "127.0.0.1")).unwrap(),
828             ttl: None,
829             amount: None,
830         };
831         let c1 = SdpLine {
832             line_number: 1,
833             sdp_type: SdpType::Connection(c.clone()),
834             text: "".to_owned(),
835         };
836         sdp_lines.push(c1);
837         let c2 = SdpLine {
838             line_number: 2,
839             sdp_type: SdpType::Connection(c),
840             text: "".to_owned(),
841         };
842         sdp_lines.push(c2);
843         assert!(parse_media_vector(&mut sdp_lines).is_err());
844     }
845 
846     #[test]
test_media_vector_invalid_types()847     fn test_media_vector_invalid_types() {
848         let mut sdp_lines: Vec<SdpLine> = Vec::new();
849         let media_line = SdpMediaLine {
850             media: SdpMediaValue::Audio,
851             port: 9,
852             port_count: 0,
853             proto: SdpProtocolValue::RtpSavpf,
854             formats: SdpFormatList::Integers(Vec::new()),
855         };
856         let media = SdpLine {
857             line_number: 0,
858             sdp_type: SdpType::Media(media_line),
859             text: "".to_owned(),
860         };
861         sdp_lines.push(media);
862         use SdpTiming;
863         let t = SdpTiming { start: 0, stop: 0 };
864         let tline = SdpLine {
865             line_number: 1,
866             sdp_type: SdpType::Timing(t),
867             text: "".to_owned(),
868         };
869         sdp_lines.push(tline);
870         assert!(parse_media_vector(&mut sdp_lines).is_err());
871     }
872 
873     #[test]
test_media_vector_invalid_media_level_attribute()874     fn test_media_vector_invalid_media_level_attribute() {
875         let mut sdp_lines: Vec<SdpLine> = Vec::new();
876         let media_line = SdpMediaLine {
877             media: SdpMediaValue::Audio,
878             port: 9,
879             port_count: 0,
880             proto: SdpProtocolValue::RtpSavpf,
881             formats: SdpFormatList::Integers(Vec::new()),
882         };
883         let media = SdpLine {
884             line_number: 0,
885             sdp_type: SdpType::Media(media_line),
886             text: "".to_owned(),
887         };
888         sdp_lines.push(media);
889         let a = SdpAttribute::IceLite;
890         let aline = SdpLine {
891             line_number: 1,
892             sdp_type: SdpType::Attribute(a),
893             text: "".to_owned(),
894         };
895         sdp_lines.push(aline);
896         assert!(parse_media_vector(&mut sdp_lines).is_err());
897     }
898 }
899