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