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)]
486 #[path = "./media_type_tests.rs"]
487 mod media_type_tests;
488