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 #![warn(clippy::all)]
6 #![forbid(unsafe_code)]
7 
8 #[macro_use]
9 extern crate log;
10 #[cfg(feature = "serialize")]
11 #[macro_use]
12 extern crate serde_derive;
13 #[cfg(feature = "serialize")]
14 extern crate serde;
15 use std::convert::TryFrom;
16 use std::fmt;
17 
18 #[macro_use]
19 pub mod attribute_type;
20 pub mod address;
21 pub mod anonymizer;
22 pub mod error;
23 pub mod media_type;
24 pub mod network;
25 
26 use address::{AddressTyped, ExplicitlyTypedAddress};
27 use anonymizer::{AnonymizingClone, StatefulSdpAnonymizer};
28 use attribute_type::{
29     parse_attribute, SdpAttribute, SdpAttributeRid, SdpAttributeSimulcastVersion, SdpAttributeType,
30     SdpSingleDirection,
31 };
32 use error::{SdpParserError, SdpParserInternalError};
33 use media_type::{
34     parse_media, parse_media_vector, SdpFormatList, SdpMedia, SdpMediaLine, SdpMediaValue,
35     SdpProtocolValue,
36 };
37 use network::{parse_address_type, parse_network_type};
38 
39 /*
40  * RFC4566
41  * bandwidth-fields =    *(%x62 "=" bwtype ":" bandwidth CRLF)
42  */
43 #[derive(Clone)]
44 #[cfg_attr(feature = "serialize", derive(Serialize))]
45 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
46 pub enum SdpBandwidth {
47     As(u32),
48     Ct(u32),
49     Tias(u32),
50     Unknown(String, u32),
51 }
52 
53 impl fmt::Display for SdpBandwidth {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result54     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55         let (tp_string, value) = match *self {
56             SdpBandwidth::As(ref x) => ("AS", x),
57             SdpBandwidth::Ct(ref x) => ("CT", x),
58             SdpBandwidth::Tias(ref x) => ("TIAS", x),
59             SdpBandwidth::Unknown(ref tp, ref x) => (&tp[..], x),
60         };
61         write!(f, "{tp}:{val}", tp = tp_string, val = value)
62     }
63 }
64 
65 /*
66  * RFC4566
67  * connection-field =    [%x63 "=" nettype SP addrtype SP
68  *                       connection-address CRLF]
69  */
70 #[derive(Clone)]
71 #[cfg_attr(feature = "serialize", derive(Serialize))]
72 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
73 pub struct SdpConnection {
74     pub address: ExplicitlyTypedAddress,
75     pub ttl: Option<u8>,
76     pub amount: Option<u32>,
77 }
78 
79 impl fmt::Display for SdpConnection {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result80     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81         self.address.fmt(f)?;
82         write_option_string!(f, "/{}", self.ttl)?;
83         write_option_string!(f, "/{}", self.amount)
84     }
85 }
86 
87 impl AnonymizingClone for SdpConnection {
masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self88     fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
89         let mut masked = self.clone();
90         masked.address = anon.mask_typed_address(&self.address);
91         masked
92     }
93 }
94 
95 /*
96  * RFC4566
97  * origin-field =        %x6f "=" username SP sess-id SP sess-version SP
98  *                       nettype SP addrtype SP unicast-address CRLF
99  */
100 #[derive(Clone)]
101 #[cfg_attr(feature = "serialize", derive(Serialize))]
102 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
103 pub struct SdpOrigin {
104     pub username: String,
105     pub session_id: u64,
106     pub session_version: u64,
107     pub unicast_addr: ExplicitlyTypedAddress,
108 }
109 
110 impl fmt::Display for SdpOrigin {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result111     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112         write!(
113             f,
114             "{username} {sess_id} {sess_vers} {unicast_addr}",
115             username = self.username,
116             sess_id = self.session_id,
117             sess_vers = self.session_version,
118             unicast_addr = self.unicast_addr
119         )
120     }
121 }
122 
123 impl AnonymizingClone for SdpOrigin {
masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self124     fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
125         let mut masked = self.clone();
126         masked.username = anon.mask_origin_user(&self.username);
127         masked.unicast_addr = anon.mask_typed_address(&masked.unicast_addr);
128         masked
129     }
130 }
131 
132 /*
133  * RFC4566
134  * time-fields =         1*( %x74 "=" start-time SP stop-time
135  *                       *(CRLF repeat-fields) CRLF)
136  *                       [zone-adjustments CRLF]
137  */
138 #[derive(Clone)]
139 #[cfg_attr(feature = "serialize", derive(Serialize))]
140 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
141 pub struct SdpTiming {
142     pub start: u64,
143     pub stop: u64,
144 }
145 
146 impl fmt::Display for SdpTiming {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result147     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148         write!(f, "{start} {stop}", start = self.start, stop = self.stop)
149     }
150 }
151 
152 #[cfg_attr(feature = "serialize", derive(Serialize))]
153 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
154 pub enum SdpType {
155     // Note: Email, Information, Key, Phone, Repeat, Uri and Zone are left out
156     //       on purposes as we don't want to support them.
157     Attribute(SdpAttribute),
158     Bandwidth(SdpBandwidth),
159     Connection(SdpConnection),
160     Media(SdpMediaLine),
161     Origin(SdpOrigin),
162     Session(String),
163     Timing(SdpTiming),
164     Version(u64),
165 }
166 
167 #[cfg_attr(feature = "serialize", derive(Serialize))]
168 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
169 pub struct SdpLine {
170     pub line_number: usize,
171     pub sdp_type: SdpType,
172     pub text: String,
173 }
174 
175 /*
176  * RFC4566
177  * ; SDP Syntax
178  * session-description = proto-version
179  *                       origin-field
180  *                       session-name-field
181  *                       information-field
182  *                       uri-field
183  *                       email-fields
184  *                       phone-fields
185  *                       connection-field
186  *                       bandwidth-fields
187  *                       time-fields
188  *                       key-field
189  *                       attribute-fields
190  *                       media-descriptions
191  */
192 #[derive(Clone)]
193 #[cfg_attr(feature = "serialize", derive(Serialize))]
194 #[cfg_attr(feature = "enhanced_debug", derive(Debug))]
195 pub struct SdpSession {
196     pub version: u64,
197     pub origin: SdpOrigin,
198     pub session: Option<String>,
199     pub connection: Option<SdpConnection>,
200     pub bandwidth: Vec<SdpBandwidth>,
201     pub timing: Option<SdpTiming>,
202     pub attribute: Vec<SdpAttribute>,
203     pub media: Vec<SdpMedia>,
204     pub warnings: Vec<SdpParserError>, // unsupported values:
205                                        // information: Option<String>,
206                                        // uri: Option<String>,
207                                        // email: Option<String>,
208                                        // phone: Option<String>,
209                                        // repeat: Option<String>,
210                                        // zone: Option<String>,
211                                        // key: Option<String>
212 }
213 
214 impl fmt::Display for SdpSession {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result215     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216         write!(
217             f,
218             "v={version}\r\n\
219              o={origin}\r\n\
220              s={session}\r\n\
221              {timing}\
222              {bandwidth}\
223              {connection}\
224              {session_attributes}\
225              {media_sections}",
226             version = self.version,
227             origin = self.origin,
228             session = self.get_session_text(),
229             timing = option_to_string!("t={}\r\n", self.timing),
230             bandwidth = maybe_vector_to_string!("b={}\r\n", self.bandwidth, "\r\nb="),
231             connection = option_to_string!("c={}\r\n", self.connection),
232             session_attributes = maybe_vector_to_string!("a={}\r\n", self.attribute, "\r\na="),
233             media_sections = maybe_vector_to_string!("{}", self.media, "\r\n")
234         )
235     }
236 }
237 
238 impl SdpSession {
new(version: u64, origin: SdpOrigin, session: String) -> SdpSession239     pub fn new(version: u64, origin: SdpOrigin, session: String) -> SdpSession {
240         let session = match session.trim() {
241             s if !s.is_empty() => Some(s.to_owned()),
242             _ => None,
243         };
244         SdpSession {
245             version,
246             origin,
247             session,
248             connection: None,
249             bandwidth: Vec::new(),
250             timing: None,
251             attribute: Vec::new(),
252             media: Vec::new(),
253             warnings: Vec::new(),
254         }
255     }
256 
get_version(&self) -> u64257     pub fn get_version(&self) -> u64 {
258         self.version
259     }
260 
get_origin(&self) -> &SdpOrigin261     pub fn get_origin(&self) -> &SdpOrigin {
262         &self.origin
263     }
264 
get_session(&self) -> &Option<String>265     pub fn get_session(&self) -> &Option<String> {
266         &self.session
267     }
268 
get_session_text(&self) -> &str269     pub fn get_session_text(&self) -> &str {
270         if let Some(text) = &self.session {
271             text.as_str()
272         } else {
273             " "
274         }
275     }
get_connection(&self) -> &Option<SdpConnection>276     pub fn get_connection(&self) -> &Option<SdpConnection> {
277         &self.connection
278     }
279 
set_connection(&mut self, c: SdpConnection)280     pub fn set_connection(&mut self, c: SdpConnection) {
281         self.connection = Some(c)
282     }
283 
add_bandwidth(&mut self, b: SdpBandwidth)284     pub fn add_bandwidth(&mut self, b: SdpBandwidth) {
285         self.bandwidth.push(b)
286     }
287 
set_timing(&mut self, t: SdpTiming)288     pub fn set_timing(&mut self, t: SdpTiming) {
289         self.timing = Some(t)
290     }
291 
add_attribute(&mut self, a: SdpAttribute) -> Result<(), SdpParserInternalError>292     pub fn add_attribute(&mut self, a: SdpAttribute) -> Result<(), SdpParserInternalError> {
293         if !a.allowed_at_session_level() {
294             return Err(SdpParserInternalError::Generic(format!(
295                 "{} not allowed at session level",
296                 a
297             )));
298         };
299         self.attribute.push(a);
300         Ok(())
301     }
302 
extend_media(&mut self, v: Vec<SdpMedia>)303     pub fn extend_media(&mut self, v: Vec<SdpMedia>) {
304         self.media.extend(v)
305     }
306 
parse_session_vector(&mut self, lines: &mut Vec<SdpLine>) -> Result<(), SdpParserError>307     pub fn parse_session_vector(&mut self, lines: &mut Vec<SdpLine>) -> Result<(), SdpParserError> {
308         while !lines.is_empty() {
309             let line = lines.remove(0);
310             match line.sdp_type {
311                 SdpType::Attribute(a) => {
312                     let _line_number = line.line_number;
313                     self.add_attribute(a).map_err(|e: SdpParserInternalError| {
314                         SdpParserError::Sequence {
315                             message: format!("{}", e),
316                             line_number: _line_number,
317                         }
318                     })?
319                 }
320                 SdpType::Bandwidth(b) => self.add_bandwidth(b),
321                 SdpType::Timing(t) => self.set_timing(t),
322                 SdpType::Connection(c) => self.set_connection(c),
323 
324                 SdpType::Origin(_) | SdpType::Session(_) | SdpType::Version(_) => {
325                     return Err(SdpParserError::Sequence {
326                         message: "version, origin or session at wrong level".to_string(),
327                         line_number: line.line_number,
328                     });
329                 }
330                 SdpType::Media(_) => {
331                     return Err(SdpParserError::Sequence {
332                         message: "media line not allowed in session parser".to_string(),
333                         line_number: line.line_number,
334                     });
335                 }
336             }
337         }
338         Ok(())
339     }
340 
get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute>341     pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
342         self.attribute
343             .iter()
344             .find(|a| SdpAttributeType::from(*a) == t)
345     }
346 
add_media( &mut self, media_type: SdpMediaValue, direction: SdpAttribute, port: u32, protocol: SdpProtocolValue, addr: ExplicitlyTypedAddress, ) -> Result<(), SdpParserInternalError>347     pub fn add_media(
348         &mut self,
349         media_type: SdpMediaValue,
350         direction: SdpAttribute,
351         port: u32,
352         protocol: SdpProtocolValue,
353         addr: ExplicitlyTypedAddress,
354     ) -> Result<(), SdpParserInternalError> {
355         let mut media = SdpMedia::new(SdpMediaLine {
356             media: media_type,
357             port,
358             port_count: 1,
359             proto: protocol,
360             formats: SdpFormatList::Integers(Vec::new()),
361         });
362 
363         media.add_attribute(direction)?;
364 
365         media.set_connection(SdpConnection {
366             address: addr,
367             ttl: None,
368             amount: None,
369         });
370 
371         self.media.push(media);
372 
373         Ok(())
374     }
375 }
376 
377 impl AnonymizingClone for SdpSession {
masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self378     fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
379         let mut masked: SdpSession = SdpSession {
380             version: self.version,
381             session: self.session.clone(),
382             origin: self.origin.masked_clone(anon),
383             connection: self.connection.clone(),
384             timing: self.timing.clone(),
385             bandwidth: self.bandwidth.clone(),
386             attribute: Vec::new(),
387             media: Vec::new(),
388             warnings: Vec::new(),
389         };
390         masked.origin = self.origin.masked_clone(anon);
391         masked.connection = masked.connection.map(|con| con.masked_clone(anon));
392         for i in &self.attribute {
393             masked.attribute.push(i.masked_clone(anon));
394         }
395         masked
396     }
397 }
398 
parse_session(value: &str) -> Result<SdpType, SdpParserInternalError>399 fn parse_session(value: &str) -> Result<SdpType, SdpParserInternalError> {
400     trace!("session: {}", value);
401     Ok(SdpType::Session(String::from(value)))
402 }
403 
parse_version(value: &str) -> Result<SdpType, SdpParserInternalError>404 fn parse_version(value: &str) -> Result<SdpType, SdpParserInternalError> {
405     let ver = value.parse::<u64>()?;
406     if ver != 0 {
407         return Err(SdpParserInternalError::Generic(format!(
408             "version type contains unsupported value {}",
409             ver
410         )));
411     };
412     trace!("version: {}", ver);
413     Ok(SdpType::Version(ver))
414 }
415 
parse_origin(value: &str) -> Result<SdpType, SdpParserInternalError>416 fn parse_origin(value: &str) -> Result<SdpType, SdpParserInternalError> {
417     let mut tokens = value.split_whitespace();
418     let username = match tokens.next() {
419         None => {
420             return Err(SdpParserInternalError::Generic(
421                 "Origin type is missing username token".to_string(),
422             ));
423         }
424         Some(x) => x,
425     };
426     let session_id = match tokens.next() {
427         None => {
428             return Err(SdpParserInternalError::Generic(
429                 "Origin type is missing session ID token".to_string(),
430             ));
431         }
432         Some(x) => x.parse::<u64>()?,
433     };
434     let session_version = match tokens.next() {
435         None => {
436             return Err(SdpParserInternalError::Generic(
437                 "Origin type is missing session version token".to_string(),
438             ));
439         }
440         Some(x) => x.parse::<u64>()?,
441     };
442     match tokens.next() {
443         None => {
444             return Err(SdpParserInternalError::Generic(
445                 "Origin type is missing network type token".to_string(),
446             ));
447         }
448         Some(x) => parse_network_type(x)?,
449     };
450     let addrtype = match tokens.next() {
451         None => {
452             return Err(SdpParserInternalError::Generic(
453                 "Origin type is missing address type token".to_string(),
454             ));
455         }
456         Some(x) => parse_address_type(x)?,
457     };
458     let unicast_addr = match tokens.next() {
459         None => {
460             return Err(SdpParserInternalError::Generic(
461                 "Origin type is missing IP address token".to_string(),
462             ));
463         }
464         Some(x) => ExplicitlyTypedAddress::try_from((addrtype, x))?,
465     };
466     if addrtype != unicast_addr.address_type() {
467         return Err(SdpParserInternalError::Generic(
468             "Origin addrtype does not match address.".to_string(),
469         ));
470     }
471     let o = SdpOrigin {
472         username: String::from(username),
473         session_id,
474         session_version,
475         unicast_addr,
476     };
477     trace!("origin: {}", o);
478     Ok(SdpType::Origin(o))
479 }
480 
parse_connection(value: &str) -> Result<SdpType, SdpParserInternalError>481 fn parse_connection(value: &str) -> Result<SdpType, SdpParserInternalError> {
482     let cv: Vec<&str> = value.split_whitespace().collect();
483     if cv.len() != 3 {
484         return Err(SdpParserInternalError::Generic(
485             "connection attribute must have three tokens".to_string(),
486         ));
487     }
488     parse_network_type(cv[0])?;
489     let addrtype = parse_address_type(cv[1])?;
490     let mut ttl = None;
491     let mut amount = None;
492     let mut addr_token = cv[2];
493     if addr_token.find('/') != None {
494         let addr_tokens: Vec<&str> = addr_token.split('/').collect();
495         if addr_tokens.len() >= 3 {
496             amount = Some(addr_tokens[2].parse::<u32>()?);
497         }
498         ttl = Some(addr_tokens[1].parse::<u8>()?);
499         addr_token = addr_tokens[0];
500     }
501     let address = ExplicitlyTypedAddress::try_from((addrtype, addr_token))?;
502     let c = SdpConnection {
503         address,
504         ttl,
505         amount,
506     };
507     trace!("connection: {}", c);
508     Ok(SdpType::Connection(c))
509 }
510 
parse_bandwidth(value: &str) -> Result<SdpType, SdpParserInternalError>511 fn parse_bandwidth(value: &str) -> Result<SdpType, SdpParserInternalError> {
512     let bv: Vec<&str> = value.split(':').collect();
513     if bv.len() != 2 {
514         return Err(SdpParserInternalError::Generic(
515             "bandwidth attribute must have two tokens".to_string(),
516         ));
517     }
518     let bandwidth = bv[1].parse::<u32>()?;
519     let bw = match bv[0].to_uppercase().as_ref() {
520         "AS" => SdpBandwidth::As(bandwidth),
521         "CT" => SdpBandwidth::Ct(bandwidth),
522         "TIAS" => SdpBandwidth::Tias(bandwidth),
523         _ => SdpBandwidth::Unknown(String::from(bv[0]), bandwidth),
524     };
525     trace!("bandwidth: {}", bw);
526     Ok(SdpType::Bandwidth(bw))
527 }
528 
parse_timing(value: &str) -> Result<SdpType, SdpParserInternalError>529 fn parse_timing(value: &str) -> Result<SdpType, SdpParserInternalError> {
530     let tv: Vec<&str> = value.split_whitespace().collect();
531     if tv.len() != 2 {
532         return Err(SdpParserInternalError::Generic(
533             "timing attribute must have two tokens".to_string(),
534         ));
535     }
536     let start = tv[0].parse::<u64>()?;
537     let stop = tv[1].parse::<u64>()?;
538     let t = SdpTiming { start, stop };
539     trace!("timing: {}", t);
540     Ok(SdpType::Timing(t))
541 }
542 
parse_sdp_line(line: &str, line_number: usize) -> Result<SdpLine, SdpParserError>543 fn parse_sdp_line(line: &str, line_number: usize) -> Result<SdpLine, SdpParserError> {
544     if line.find('=') == None {
545         return Err(SdpParserError::Line {
546             error: SdpParserInternalError::Generic("missing = character in line".to_string()),
547             line: line.to_string(),
548             line_number,
549         });
550     }
551     let mut splitted_line = line.splitn(2, '=');
552     let line_type = match splitted_line.next() {
553         None => {
554             return Err(SdpParserError::Line {
555                 error: SdpParserInternalError::Generic("missing type".to_string()),
556                 line: line.to_string(),
557                 line_number,
558             });
559         }
560         Some(t) => {
561             let trimmed = t.trim();
562             if trimmed.len() > 1 {
563                 return Err(SdpParserError::Line {
564                     error: SdpParserInternalError::Generic("type too long".to_string()),
565                     line: line.to_string(),
566                     line_number,
567                 });
568             }
569             if trimmed.is_empty() {
570                 return Err(SdpParserError::Line {
571                     error: SdpParserInternalError::Generic("type is empty".to_string()),
572                     line: line.to_string(),
573                     line_number,
574                 });
575             }
576             trimmed.to_lowercase()
577         }
578     };
579     let (line_value, untrimmed_line_value) = match splitted_line.next() {
580         None => {
581             return Err(SdpParserError::Line {
582                 error: SdpParserInternalError::Generic("missing value".to_string()),
583                 line: line.to_string(),
584                 line_number,
585             });
586         }
587         Some(v) => {
588             let trimmed = v.trim();
589             // For compatibility with sites that don't adhere to "s=-" for no session ID
590             if trimmed.is_empty() && line_type.as_str() != "s" {
591                 return Err(SdpParserError::Line {
592                     error: SdpParserInternalError::Generic("value is empty".to_string()),
593                     line: line.to_string(),
594                     line_number,
595                 });
596             }
597             (trimmed, v)
598         }
599     };
600     match line_type.as_ref() {
601         "a" => parse_attribute(line_value),
602         "b" => parse_bandwidth(line_value),
603         "c" => parse_connection(line_value),
604         "e" => Err(SdpParserInternalError::Generic(format!(
605             "unsupported type email: {}",
606             line_value
607         ))),
608         "i" => Err(SdpParserInternalError::Generic(format!(
609             "unsupported type information: {}",
610             line_value
611         ))),
612         "k" => Err(SdpParserInternalError::Generic(format!(
613             "unsupported insecure key exchange: {}",
614             line_value
615         ))),
616         "m" => parse_media(line_value),
617         "o" => parse_origin(line_value),
618         "p" => Err(SdpParserInternalError::Generic(format!(
619             "unsupported type phone: {}",
620             line_value
621         ))),
622         "r" => Err(SdpParserInternalError::Generic(format!(
623             "unsupported type repeat: {}",
624             line_value
625         ))),
626         "s" => parse_session(untrimmed_line_value),
627         "t" => parse_timing(line_value),
628         "u" => Err(SdpParserInternalError::Generic(format!(
629             "unsupported type uri: {}",
630             line_value
631         ))),
632         "v" => parse_version(line_value),
633         "z" => Err(SdpParserInternalError::Generic(format!(
634             "unsupported type zone: {}",
635             line_value
636         ))),
637         _ => Err(SdpParserInternalError::Generic(
638             "unknown sdp type".to_string(),
639         )),
640     }
641     .map(|sdp_type| SdpLine {
642         line_number,
643         sdp_type,
644         text: line.to_owned(),
645     })
646     .map_err(|e| match e {
647         SdpParserInternalError::UnknownAddressType(..)
648         | SdpParserInternalError::AddressTypeMismatch { .. }
649         | SdpParserInternalError::Generic(..)
650         | SdpParserInternalError::Integer(..)
651         | SdpParserInternalError::Float(..)
652         | SdpParserInternalError::Domain(..)
653         | SdpParserInternalError::IpAddress(..) => SdpParserError::Line {
654             error: e,
655             line: line.to_string(),
656             line_number,
657         },
658         SdpParserInternalError::Unsupported(..) => SdpParserError::Unsupported {
659             error: e,
660             line: line.to_string(),
661             line_number,
662         },
663     })
664 }
665 
sanity_check_sdp_session(session: &SdpSession) -> Result<(), SdpParserError>666 fn sanity_check_sdp_session(session: &SdpSession) -> Result<(), SdpParserError> {
667     let make_seq_error = |x: &str| SdpParserError::Sequence {
668         message: x.to_string(),
669         line_number: 0,
670     };
671 
672     if session.timing.is_none() {
673         return Err(make_seq_error("Missing timing type at session level"));
674     }
675     // Checks that all media have connections if there is no top level
676     // This explicitly allows for zero connection lines if there are no media
677     // sections for interoperability reasons.
678     let media_cons = &session.media.iter().all(|m| m.get_connection().is_some());
679     if !media_cons && session.get_connection().is_none() {
680         return Err(make_seq_error(
681             "Without connection type at session level all media sections must have connection types",
682         ));
683     }
684 
685     // Check that extmaps are not defined on session and media level
686     if session.get_attribute(SdpAttributeType::Extmap).is_some() {
687         for msection in &session.media {
688             if msection.get_attribute(SdpAttributeType::Extmap).is_some() {
689                 return Err(make_seq_error(
690                     "Extmap can't be define at session and media level",
691                 ));
692             }
693         }
694     }
695 
696     for msection in &session.media {
697         if msection.get_attribute(SdpAttributeType::Sendonly).is_some() {
698             if let Some(&SdpAttribute::Simulcast(ref x)) =
699                 msection.get_attribute(SdpAttributeType::Simulcast)
700             {
701                 if !x.receive.is_empty() {
702                     return Err(make_seq_error(
703                         "Simulcast can't define receive parameters for sendonly",
704                     ));
705                 }
706             }
707         }
708         if msection.get_attribute(SdpAttributeType::Recvonly).is_some() {
709             if let Some(&SdpAttribute::Simulcast(ref x)) =
710                 msection.get_attribute(SdpAttributeType::Simulcast)
711             {
712                 if !x.send.is_empty() {
713                     return Err(make_seq_error(
714                         "Simulcast can't define send parameters for recvonly",
715                     ));
716                 }
717             }
718         }
719 
720         let rids: Vec<&SdpAttributeRid> = msection
721             .get_attributes()
722             .iter()
723             .filter_map(|attr| match *attr {
724                 SdpAttribute::Rid(ref rid) => Some(rid),
725                 _ => None,
726             })
727             .collect();
728         let recv_rids: Vec<&str> = rids
729             .iter()
730             .filter_map(|rid| match rid.direction {
731                 SdpSingleDirection::Recv => Some(rid.id.as_str()),
732                 _ => None,
733             })
734             .collect();
735         let send_rids: Vec<&str> = rids
736             .iter()
737             .filter_map(|rid| match rid.direction {
738                 SdpSingleDirection::Send => Some(rid.id.as_str()),
739                 _ => None,
740             })
741             .collect();
742 
743         for rid_format in rids.iter().flat_map(|rid| &rid.formats) {
744             match *msection.get_formats() {
745                 SdpFormatList::Integers(ref int_fmt) => {
746                     if !int_fmt.contains(&(u32::from(*rid_format))) {
747                         return Err(make_seq_error(
748                             "Rid pts must be declared in the media section",
749                         ));
750                     }
751                 }
752                 SdpFormatList::Strings(ref str_fmt) => {
753                     if !str_fmt.contains(&rid_format.to_string()) {
754                         return Err(make_seq_error(
755                             "Rid pts must be declared in the media section",
756                         ));
757                     }
758                 }
759             }
760         }
761 
762         if let Some(&SdpAttribute::Simulcast(ref simulcast)) =
763             msection.get_attribute(SdpAttributeType::Simulcast)
764         {
765             let check_defined_rids =
766                 |simulcast_version_list: &Vec<SdpAttributeSimulcastVersion>,
767                  rid_ids: &[&str]|
768                  -> Result<(), SdpParserError> {
769                     for simulcast_rid in simulcast_version_list.iter().flat_map(|x| &x.ids) {
770                         if !rid_ids.contains(&simulcast_rid.id.as_str()) {
771                             return Err(make_seq_error(
772                                 "Simulcast RIDs must be defined in any rid attribute",
773                             ));
774                         }
775                     }
776                     Ok(())
777                 };
778 
779             check_defined_rids(&simulcast.receive, &recv_rids)?;
780             check_defined_rids(&simulcast.send, &send_rids)?;
781         }
782     }
783 
784     Ok(())
785 }
786 
parse_sdp_vector(lines: &mut Vec<SdpLine>) -> Result<SdpSession, SdpParserError>787 fn parse_sdp_vector(lines: &mut Vec<SdpLine>) -> Result<SdpSession, SdpParserError> {
788     if lines.len() < 4 {
789         return Err(SdpParserError::Sequence {
790             message: "SDP neeeds at least 4 lines".to_string(),
791             line_number: 0,
792         });
793     }
794 
795     let version = match lines.remove(0).sdp_type {
796         SdpType::Version(v) => v,
797         _ => {
798             return Err(SdpParserError::Sequence {
799                 message: "first line needs to be version number".to_string(),
800                 line_number: 0,
801             });
802         }
803     };
804     let origin = match lines.remove(0).sdp_type {
805         SdpType::Origin(v) => v,
806         _ => {
807             return Err(SdpParserError::Sequence {
808                 message: "second line needs to be origin".to_string(),
809                 line_number: 1,
810             });
811         }
812     };
813     let session = match lines.remove(0).sdp_type {
814         SdpType::Session(v) => v,
815         _ => {
816             return Err(SdpParserError::Sequence {
817                 message: "third line needs to be session".to_string(),
818                 line_number: 2,
819             });
820         }
821     };
822     let mut sdp_session = SdpSession::new(version, origin, session);
823 
824     let _media_pos = lines
825         .iter()
826         .position(|ref l| matches!(l.sdp_type, SdpType::Media(_)));
827 
828     match _media_pos {
829         Some(p) => {
830             let mut media: Vec<_> = lines.drain(p..).collect();
831             sdp_session.parse_session_vector(lines)?;
832             sdp_session.extend_media(parse_media_vector(&mut media)?);
833         }
834         None => sdp_session.parse_session_vector(lines)?,
835     };
836 
837     sanity_check_sdp_session(&sdp_session)?;
838     Ok(sdp_session)
839 }
840 
parse_sdp(sdp: &str, fail_on_warning: bool) -> Result<SdpSession, SdpParserError>841 pub fn parse_sdp(sdp: &str, fail_on_warning: bool) -> Result<SdpSession, SdpParserError> {
842     if sdp.is_empty() {
843         return Err(SdpParserError::Line {
844             error: SdpParserInternalError::Generic("empty SDP".to_string()),
845             line: sdp.to_string(),
846             line_number: 0,
847         });
848     }
849     // see test_parse_sdp_minimal_sdp_successfully
850     if sdp.len() < 51 {
851         return Err(SdpParserError::Line {
852             error: SdpParserInternalError::Generic("string too short to be valid SDP".to_string()),
853             line: sdp.to_string(),
854             line_number: 0,
855         });
856     }
857     let lines = sdp.lines();
858     let mut errors: Vec<SdpParserError> = Vec::new();
859     let mut warnings: Vec<SdpParserError> = Vec::new();
860     let mut sdp_lines: Vec<SdpLine> = Vec::new();
861     for (line_number, line) in lines.enumerate() {
862         let stripped_line = line.trim();
863         if stripped_line.is_empty() {
864             continue;
865         }
866         match parse_sdp_line(line, line_number) {
867             Ok(n) => {
868                 sdp_lines.push(n);
869             }
870             Err(e) => {
871                 match e {
872                     // TODO is this really a good way to accomplish this?
873                     SdpParserError::Line {
874                         error,
875                         line,
876                         line_number,
877                     } => errors.push(SdpParserError::Line {
878                         error,
879                         line,
880                         line_number,
881                     }),
882                     SdpParserError::Unsupported {
883                         error,
884                         line,
885                         line_number,
886                     } => {
887                         warnings.push(SdpParserError::Unsupported {
888                             error,
889                             line,
890                             line_number,
891                         });
892                     }
893                     SdpParserError::Sequence {
894                         message,
895                         line_number,
896                     } => errors.push(SdpParserError::Sequence {
897                         message,
898                         line_number,
899                     }),
900                 }
901             }
902         };
903     }
904 
905     if fail_on_warning && (!warnings.is_empty()) {
906         return Err(warnings.remove(0));
907     }
908 
909     // We just return the last of the errors here
910     if let Some(e) = errors.pop() {
911         return Err(e);
912     };
913 
914     let mut session = parse_sdp_vector(&mut sdp_lines)?;
915     session.warnings = warnings;
916 
917     for warning in &session.warnings {
918         warn!("Warning: {}", &warning);
919     }
920 
921     Ok(session)
922 }
923 
924 #[cfg(test)]
925 mod tests {
926     extern crate url;
927     use super::*;
928     use address::{Address, AddressType};
929     use anonymizer::ToBytesVec;
930     use media_type::create_dummy_media_section;
931     use std::net::IpAddr;
932     use std::net::Ipv4Addr;
933 
create_dummy_sdp_session() -> SdpSession934     fn create_dummy_sdp_session() -> SdpSession {
935         let origin = parse_origin("mozilla 506705521068071134 0 IN IP4 0.0.0.0");
936         assert!(origin.is_ok());
937         let connection = parse_connection("IN IP4 198.51.100.7");
938         assert!(connection.is_ok());
939         let mut sdp_session;
940         if let SdpType::Origin(o) = origin.unwrap() {
941             sdp_session = SdpSession::new(0, o, "-".to_string());
942 
943             if let Ok(SdpType::Connection(c)) = connection {
944                 sdp_session.connection = Some(c);
945             } else {
946                 unreachable!();
947             }
948         } else {
949             unreachable!();
950         }
951         sdp_session
952     }
953 
954     #[test]
test_session_works() -> Result<(), SdpParserInternalError>955     fn test_session_works() -> Result<(), SdpParserInternalError> {
956         parse_session("topic")?;
957         Ok(())
958     }
959 
960     #[test]
test_version_works() -> Result<(), SdpParserInternalError>961     fn test_version_works() -> Result<(), SdpParserInternalError> {
962         parse_version("0")?;
963         Ok(())
964     }
965 
966     #[test]
test_version_unsupported_input()967     fn test_version_unsupported_input() {
968         assert!(parse_version("1").is_err());
969         assert!(parse_version("11").is_err());
970         assert!(parse_version("a").is_err());
971     }
972 
973     #[test]
test_origin_works() -> Result<(), SdpParserInternalError>974     fn test_origin_works() -> Result<(), SdpParserInternalError> {
975         parse_origin("mozilla 506705521068071134 0 IN IP4 0.0.0.0")?;
976         parse_origin("mozilla 506705521068071134 0 IN IP6 2001:db8::1")?;
977         Ok(())
978     }
979 
980     #[test]
test_origin_missing_username()981     fn test_origin_missing_username() {
982         assert!(parse_origin("").is_err());
983     }
984 
985     #[test]
test_origin_missing_session_id()986     fn test_origin_missing_session_id() {
987         assert!(parse_origin("mozilla ").is_err());
988     }
989 
990     #[test]
test_origin_missing_session_version()991     fn test_origin_missing_session_version() {
992         assert!(parse_origin("mozilla 506705521068071134 ").is_err());
993     }
994 
995     #[test]
test_origin_missing_nettype()996     fn test_origin_missing_nettype() {
997         assert!(parse_origin("mozilla 506705521068071134 0 ").is_err());
998     }
999 
1000     #[test]
test_origin_unsupported_nettype()1001     fn test_origin_unsupported_nettype() {
1002         assert!(parse_origin("mozilla 506705521068071134 0 UNSUPPORTED IP4 0.0.0.0").is_err());
1003     }
1004 
1005     #[test]
test_origin_missing_addtype()1006     fn test_origin_missing_addtype() {
1007         assert!(parse_origin("mozilla 506705521068071134 0 IN ").is_err());
1008     }
1009 
1010     #[test]
test_origin_missing_ip_addr()1011     fn test_origin_missing_ip_addr() {
1012         assert!(parse_origin("mozilla 506705521068071134 0 IN IP4 ").is_err());
1013     }
1014 
1015     #[test]
test_origin_unsupported_addrtpe()1016     fn test_origin_unsupported_addrtpe() {
1017         assert!(parse_origin("mozilla 506705521068071134 0 IN IP1 0.0.0.0").is_err());
1018     }
1019 
1020     #[test]
test_origin_invalid_ip_addr()1021     fn test_origin_invalid_ip_addr() {
1022         assert!(parse_origin("mozilla 506705521068071134 0 IN IP4 1.1.1.256").is_err());
1023         assert!(parse_origin("mozilla 506705521068071134 0 IN IP6 ::g").is_err());
1024     }
1025 
1026     #[test]
test_origin_addr_type_mismatch()1027     fn test_origin_addr_type_mismatch() {
1028         assert!(parse_origin("mozilla 506705521068071134 0 IN IP4 ::1").is_err());
1029     }
1030 
1031     #[test]
connection_works() -> Result<(), SdpParserInternalError>1032     fn connection_works() -> Result<(), SdpParserInternalError> {
1033         parse_connection("IN IP4 127.0.0.1")?;
1034         parse_connection("IN IP4 127.0.0.1/10/10")?;
1035         parse_connection("IN IP6 ::1")?;
1036         parse_connection("IN IP6 ::1/1/1")?;
1037         Ok(())
1038     }
1039 
1040     #[test]
connection_lots_of_whitespace() -> Result<(), SdpParserInternalError>1041     fn connection_lots_of_whitespace() -> Result<(), SdpParserInternalError> {
1042         parse_connection("IN   IP4   127.0.0.1")?;
1043         Ok(())
1044     }
1045 
1046     #[test]
connection_wrong_amount_of_tokens()1047     fn connection_wrong_amount_of_tokens() {
1048         assert!(parse_connection("IN IP4").is_err());
1049         assert!(parse_connection("IN IP4 0.0.0.0 foobar").is_err());
1050     }
1051 
1052     #[test]
connection_unsupported_nettype()1053     fn connection_unsupported_nettype() {
1054         assert!(parse_connection("UNSUPPORTED IP4 0.0.0.0").is_err());
1055     }
1056 
1057     #[test]
connection_unsupported_addrtpe()1058     fn connection_unsupported_addrtpe() {
1059         assert!(parse_connection("IN IP1 0.0.0.0").is_err());
1060     }
1061 
1062     #[test]
connection_broken_ip_addr()1063     fn connection_broken_ip_addr() {
1064         assert!(parse_connection("IN IP4 1.1.1.256").is_err());
1065         assert!(parse_connection("IN IP6 ::g").is_err());
1066     }
1067 
1068     #[test]
connection_addr_type_mismatch()1069     fn connection_addr_type_mismatch() {
1070         assert!(parse_connection("IN IP4 ::1").is_err());
1071     }
1072 
1073     #[test]
bandwidth_works() -> Result<(), SdpParserInternalError>1074     fn bandwidth_works() -> Result<(), SdpParserInternalError> {
1075         parse_bandwidth("AS:1")?;
1076         parse_bandwidth("CT:123")?;
1077         parse_bandwidth("TIAS:12345")?;
1078         Ok(())
1079     }
1080 
1081     #[test]
bandwidth_wrong_amount_of_tokens()1082     fn bandwidth_wrong_amount_of_tokens() {
1083         assert!(parse_bandwidth("TIAS").is_err());
1084         assert!(parse_bandwidth("TIAS:12345:xyz").is_err());
1085     }
1086 
1087     #[test]
bandwidth_unsupported_type() -> Result<(), SdpParserInternalError>1088     fn bandwidth_unsupported_type() -> Result<(), SdpParserInternalError> {
1089         parse_bandwidth("UNSUPPORTED:12345")?;
1090         Ok(())
1091     }
1092 
1093     #[test]
test_timing_works() -> Result<(), SdpParserInternalError>1094     fn test_timing_works() -> Result<(), SdpParserInternalError> {
1095         parse_timing("0 0")?;
1096         Ok(())
1097     }
1098 
1099     #[test]
test_timing_non_numeric_tokens()1100     fn test_timing_non_numeric_tokens() {
1101         assert!(parse_timing("a 0").is_err());
1102         assert!(parse_timing("0 a").is_err());
1103     }
1104 
1105     #[test]
test_timing_wrong_amount_of_tokens()1106     fn test_timing_wrong_amount_of_tokens() {
1107         assert!(parse_timing("0").is_err());
1108         assert!(parse_timing("0 0 0").is_err());
1109     }
1110 
1111     #[test]
test_parse_sdp_line_works() -> Result<(), SdpParserError>1112     fn test_parse_sdp_line_works() -> Result<(), SdpParserError> {
1113         parse_sdp_line("v=0", 0)?;
1114         parse_sdp_line("s=somesession", 0)?;
1115         Ok(())
1116     }
1117 
1118     #[test]
test_parse_sdp_line_empty_line()1119     fn test_parse_sdp_line_empty_line() {
1120         assert!(parse_sdp_line("", 0).is_err());
1121     }
1122 
1123     #[test]
test_parse_sdp_line_unsupported_types()1124     fn test_parse_sdp_line_unsupported_types() {
1125         assert!(parse_sdp_line("e=foobar", 0).is_err());
1126         assert!(parse_sdp_line("i=foobar", 0).is_err());
1127         assert!(parse_sdp_line("k=foobar", 0).is_err());
1128         assert!(parse_sdp_line("p=foobar", 0).is_err());
1129         assert!(parse_sdp_line("r=foobar", 0).is_err());
1130         assert!(parse_sdp_line("u=foobar", 0).is_err());
1131         assert!(parse_sdp_line("z=foobar", 0).is_err());
1132     }
1133 
1134     #[test]
test_parse_sdp_line_unknown_key()1135     fn test_parse_sdp_line_unknown_key() {
1136         assert!(parse_sdp_line("y=foobar", 0).is_err());
1137     }
1138 
1139     #[test]
test_parse_sdp_line_too_long_type()1140     fn test_parse_sdp_line_too_long_type() {
1141         assert!(parse_sdp_line("ab=foobar", 0).is_err());
1142     }
1143 
1144     #[test]
test_parse_sdp_line_without_equal()1145     fn test_parse_sdp_line_without_equal() {
1146         assert!(parse_sdp_line("abcd", 0).is_err());
1147         assert!(parse_sdp_line("ab cd", 0).is_err());
1148     }
1149 
1150     #[test]
test_parse_sdp_line_empty_value()1151     fn test_parse_sdp_line_empty_value() {
1152         assert!(parse_sdp_line("v=", 0).is_err());
1153         assert!(parse_sdp_line("o=", 0).is_err());
1154     }
1155 
1156     #[test]
test_parse_sdp_line_empty_name()1157     fn test_parse_sdp_line_empty_name() {
1158         assert!(parse_sdp_line("=abc", 0).is_err());
1159     }
1160 
1161     #[test]
test_parse_sdp_line_valid_a_line() -> Result<(), SdpParserError>1162     fn test_parse_sdp_line_valid_a_line() -> Result<(), SdpParserError> {
1163         parse_sdp_line("a=rtpmap:8 PCMA/8000", 0)?;
1164         Ok(())
1165     }
1166 
1167     #[test]
test_parse_sdp_line_invalid_a_line()1168     fn test_parse_sdp_line_invalid_a_line() {
1169         assert!(parse_sdp_line("a=rtpmap:200 PCMA/8000", 0).is_err());
1170     }
1171 
1172     #[test]
test_add_attribute() -> Result<(), SdpParserInternalError>1173     fn test_add_attribute() -> Result<(), SdpParserInternalError> {
1174         let mut sdp_session = create_dummy_sdp_session();
1175 
1176         sdp_session.add_attribute(SdpAttribute::Sendrecv)?;
1177         assert!(sdp_session.add_attribute(SdpAttribute::BundleOnly).is_err());
1178         assert_eq!(sdp_session.attribute.len(), 1);
1179         Ok(())
1180     }
1181 
1182     #[test]
test_sanity_check_sdp_session_timing() -> Result<(), SdpParserError>1183     fn test_sanity_check_sdp_session_timing() -> Result<(), SdpParserError> {
1184         let mut sdp_session = create_dummy_sdp_session();
1185         sdp_session.extend_media(vec![create_dummy_media_section()]);
1186 
1187         assert!(sanity_check_sdp_session(&sdp_session).is_err());
1188 
1189         let t = SdpTiming { start: 0, stop: 0 };
1190         sdp_session.set_timing(t);
1191 
1192         sanity_check_sdp_session(&sdp_session)?;
1193         Ok(())
1194     }
1195 
1196     #[test]
test_sanity_check_sdp_session_media() -> Result<(), SdpParserError>1197     fn test_sanity_check_sdp_session_media() -> Result<(), SdpParserError> {
1198         let mut sdp_session = create_dummy_sdp_session();
1199         let t = SdpTiming { start: 0, stop: 0 };
1200         sdp_session.set_timing(t);
1201 
1202         sanity_check_sdp_session(&sdp_session)?;
1203 
1204         sdp_session.extend_media(vec![create_dummy_media_section()]);
1205 
1206         sanity_check_sdp_session(&sdp_session)?;
1207         Ok(())
1208     }
1209 
1210     #[test]
test_sanity_check_sdp_connection() -> Result<(), SdpParserInternalError>1211     fn test_sanity_check_sdp_connection() -> Result<(), SdpParserInternalError> {
1212         let origin = parse_origin("mozilla 506705521068071134 0 IN IP4 0.0.0.0")?;
1213         let mut sdp_session;
1214         if let SdpType::Origin(o) = origin {
1215             sdp_session = SdpSession::new(0, o, "-".to_string());
1216         } else {
1217             unreachable!();
1218         }
1219         let t = SdpTiming { start: 0, stop: 0 };
1220         sdp_session.set_timing(t);
1221 
1222         assert!(sanity_check_sdp_session(&sdp_session).is_ok());
1223 
1224         // the dummy media section doesn't contain a connection
1225         sdp_session.extend_media(vec![create_dummy_media_section()]);
1226 
1227         assert!(sanity_check_sdp_session(&sdp_session).is_err());
1228 
1229         let connection = parse_connection("IN IP6 ::1")?;
1230         if let SdpType::Connection(c) = connection {
1231             sdp_session.connection = Some(c);
1232         } else {
1233             unreachable!();
1234         }
1235 
1236         assert!(sanity_check_sdp_session(&sdp_session).is_ok());
1237 
1238         let mut second_media = create_dummy_media_section();
1239         let mconnection = parse_connection("IN IP4 0.0.0.0")?;
1240         if let SdpType::Connection(c) = mconnection {
1241             second_media.set_connection(c);
1242         } else {
1243             unreachable!();
1244         }
1245         sdp_session.extend_media(vec![second_media]);
1246         assert!(sdp_session.media.len() == 2);
1247 
1248         assert!(sanity_check_sdp_session(&sdp_session).is_ok());
1249         Ok(())
1250     }
1251 
1252     #[test]
test_sanity_check_sdp_session_extmap() -> Result<(), SdpParserInternalError>1253     fn test_sanity_check_sdp_session_extmap() -> Result<(), SdpParserInternalError> {
1254         let mut sdp_session = create_dummy_sdp_session();
1255         let t = SdpTiming { start: 0, stop: 0 };
1256         sdp_session.set_timing(t);
1257         sdp_session.extend_media(vec![create_dummy_media_section()]);
1258 
1259         let attribute =
1260             parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")?;
1261         if let SdpType::Attribute(a) = attribute {
1262             sdp_session.add_attribute(a)?;
1263         } else {
1264             unreachable!();
1265         }
1266         assert!(sdp_session
1267             .get_attribute(SdpAttributeType::Extmap)
1268             .is_some());
1269 
1270         assert!(sanity_check_sdp_session(&sdp_session).is_ok());
1271 
1272         let mut second_media = create_dummy_media_section();
1273         let mattribute =
1274             parse_attribute("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level")?;
1275         if let SdpType::Attribute(ma) = mattribute {
1276             second_media.add_attribute(ma)?;
1277         } else {
1278             unreachable!();
1279         }
1280         assert!(second_media
1281             .get_attribute(SdpAttributeType::Extmap)
1282             .is_some());
1283 
1284         sdp_session.extend_media(vec![second_media]);
1285         assert!(sdp_session.media.len() == 2);
1286 
1287         assert!(sanity_check_sdp_session(&sdp_session).is_err());
1288 
1289         sdp_session.attribute = Vec::new();
1290 
1291         assert!(sanity_check_sdp_session(&sdp_session).is_ok());
1292         Ok(())
1293     }
1294 
1295     #[test]
test_sanity_check_sdp_session_simulcast() -> Result<(), SdpParserError>1296     fn test_sanity_check_sdp_session_simulcast() -> Result<(), SdpParserError> {
1297         let mut sdp_session = create_dummy_sdp_session();
1298         let t = SdpTiming { start: 0, stop: 0 };
1299         sdp_session.set_timing(t);
1300         sdp_session.extend_media(vec![create_dummy_media_section()]);
1301 
1302         sanity_check_sdp_session(&sdp_session)?;
1303         Ok(())
1304     }
1305 
1306     #[test]
test_parse_sdp_zero_length_string_fails()1307     fn test_parse_sdp_zero_length_string_fails() {
1308         assert!(parse_sdp("", true).is_err());
1309     }
1310 
1311     #[test]
test_parse_sdp_to_short_string()1312     fn test_parse_sdp_to_short_string() {
1313         assert!(parse_sdp("fooooobarrrr", true).is_err());
1314     }
1315 
1316     #[test]
test_parse_sdp_minimal_sdp_successfully() -> Result<(), SdpParserError>1317     fn test_parse_sdp_minimal_sdp_successfully() -> Result<(), SdpParserError> {
1318         parse_sdp(
1319             "v=0\r\n
1320 o=- 0 0 IN IP6 ::1\r\n
1321 s=-\r\n
1322 c=IN IP6 ::1\r\n
1323 t=0 0\r\n",
1324             true,
1325         )?;
1326         Ok(())
1327     }
1328 
1329     #[test]
test_parse_sdp_too_short()1330     fn test_parse_sdp_too_short() {
1331         assert!(parse_sdp(
1332             "v=0\r\n
1333 o=- 0 0 IN IP4 0.0.0.0\r\n
1334 s=-\r\n",
1335             true
1336         )
1337         .is_err());
1338     }
1339 
1340     #[test]
test_parse_sdp_line_error()1341     fn test_parse_sdp_line_error() {
1342         assert!(parse_sdp(
1343             "v=0\r\n
1344 o=- 0 0 IN IP4 0.0.0.0\r\n
1345 s=-\r\n
1346 t=0 foobar\r\n
1347 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n",
1348             true
1349         )
1350         .is_err());
1351     }
1352 
1353     #[test]
test_parse_sdp_unsupported_error()1354     fn test_parse_sdp_unsupported_error() {
1355         assert!(parse_sdp(
1356             "v=0\r\n
1357 o=- 0 0 IN IP4 0.0.0.0\r\n
1358 s=-\r\n
1359 t=0 0\r\n
1360 m=foobar 0 UDP/TLS/RTP/SAVPF 0\r\n",
1361             true
1362         )
1363         .is_err());
1364     }
1365 
1366     #[test]
test_parse_sdp_unsupported_warning() -> Result<(), SdpParserError>1367     fn test_parse_sdp_unsupported_warning() -> Result<(), SdpParserError> {
1368         parse_sdp(
1369             "v=0\r\n
1370 o=- 0 0 IN IP4 0.0.0.0\r\n
1371 s=-\r\n
1372 c=IN IP4 198.51.100.7\r\n
1373 t=0 0\r\n
1374 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n
1375 a=unsupported\r\n",
1376             false,
1377         )?;
1378         Ok(())
1379     }
1380 
1381     #[test]
test_parse_sdp_sequence_error()1382     fn test_parse_sdp_sequence_error() {
1383         assert!(parse_sdp(
1384             "v=0\r\n
1385 o=- 0 0 IN IP4 0.0.0.0\r\n
1386 s=-\r\n
1387 t=0 0\r\n
1388 a=bundle-only\r\n
1389 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n",
1390             true
1391         )
1392         .is_err());
1393     }
1394 
1395     #[test]
test_parse_sdp_integer_error()1396     fn test_parse_sdp_integer_error() {
1397         assert!(parse_sdp(
1398             "v=0\r\n
1399 o=- 0 0 IN IP4 0.0.0.0\r\n
1400 s=-\r\n
1401 t=0 0\r\n
1402 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n
1403 a=rtcp:34er21\r\n",
1404             true
1405         )
1406         .is_err());
1407     }
1408 
1409     #[test]
test_parse_sdp_ipaddr_error()1410     fn test_parse_sdp_ipaddr_error() {
1411         assert!(parse_sdp(
1412             "v=0\r\n
1413 o=- 0 0 IN IP4 0.a.b.0\r\n
1414 s=-\r\n
1415 t=0 0\r\n
1416 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n",
1417             true
1418         )
1419         .is_err());
1420     }
1421 
1422     #[test]
test_parse_sdp_invalid_session_attribute()1423     fn test_parse_sdp_invalid_session_attribute() {
1424         assert!(parse_sdp(
1425             "v=0\r\n
1426 o=- 0 0 IN IP4 0.a.b.0\r\n
1427 s=-\r\n
1428 t=0 0\r\n
1429 a=bundle-only\r\n
1430 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n",
1431             true
1432         )
1433         .is_err());
1434     }
1435 
1436     #[test]
test_parse_sdp_invalid_media_attribute()1437     fn test_parse_sdp_invalid_media_attribute() {
1438         assert!(parse_sdp(
1439             "v=0\r\n
1440 o=- 0 0 IN IP4 0.a.b.0\r\n
1441 s=-\r\n
1442 t=0 0\r\n
1443 m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n
1444 a=ice-lite\r\n",
1445             true
1446         )
1447         .is_err());
1448     }
1449 
1450     #[test]
test_mask_origin()1451     fn test_mask_origin() {
1452         let mut anon = StatefulSdpAnonymizer::new();
1453         if let SdpType::Origin(origin_1) =
1454             parse_origin("mozilla 506705521068071134 0 IN IP4 0.0.0.0").unwrap()
1455         {
1456             for _ in 0..2 {
1457                 let masked = origin_1.masked_clone(&mut anon);
1458                 assert_eq!(masked.username, "origin-user-00000001");
1459                 assert_eq!(
1460                     masked.unicast_addr,
1461                     ExplicitlyTypedAddress::Ip(IpAddr::V4(Ipv4Addr::from(1)))
1462                 );
1463             }
1464         } else {
1465             unreachable!();
1466         }
1467     }
1468 
1469     #[test]
test_mask_sdp()1470     fn test_mask_sdp() {
1471         let mut anon = StatefulSdpAnonymizer::new();
1472         let sdp = parse_sdp(
1473             "v=0\r\n
1474         o=ausername 4294967296 2 IN IP4 127.0.0.1\r\n
1475         s=SIP Call\r\n
1476         c=IN IP4 198.51.100.7/51\r\n
1477         a=ice-pwd:12340\r\n
1478         a=ice-ufrag:4a799b2e\r\n
1479         a=fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC\r\n
1480         t=0 0\r\n
1481         m=video 56436 RTP/SAVPF 120\r\n
1482         a=candidate:77142221 1 udp 2113937151 192.168.137.1 54081 typ host\r\n
1483         a=remote-candidates:0 10.0.0.1 5555\r\n
1484         a=rtpmap:120 VP8/90000\r\n",
1485             true,
1486         )
1487         .unwrap();
1488         let mut masked = sdp.masked_clone(&mut anon);
1489         assert_eq!(masked.origin.username, "origin-user-00000001");
1490         assert_eq!(
1491             masked.origin.unicast_addr,
1492             ExplicitlyTypedAddress::Ip(IpAddr::V4(Ipv4Addr::from(1)))
1493         );
1494         assert_eq!(
1495             masked.connection.unwrap().address,
1496             ExplicitlyTypedAddress::Ip(IpAddr::V4(Ipv4Addr::from(2)))
1497         );
1498         let mut attributes = masked.attribute;
1499         for m in &mut masked.media {
1500             for attribute in m.get_attributes() {
1501                 attributes.push(attribute.clone());
1502             }
1503         }
1504         for attribute in attributes {
1505             match attribute {
1506                 SdpAttribute::Candidate(c) => {
1507                     assert_eq!(c.address, Address::Ip(IpAddr::V4(Ipv4Addr::from(3))));
1508                     assert_eq!(c.port, 1);
1509                 }
1510                 SdpAttribute::Fingerprint(f) => {
1511                     assert_eq!(f.fingerprint, 1u64.to_byte_vec());
1512                 }
1513                 SdpAttribute::IcePwd(p) => {
1514                     assert_eq!(p, "ice-password-00000001");
1515                 }
1516                 SdpAttribute::IceUfrag(u) => {
1517                     assert_eq!(u, "ice-user-00000001");
1518                 }
1519                 SdpAttribute::RemoteCandidate(r) => {
1520                     assert_eq!(r.address, Address::Ip(IpAddr::V4(Ipv4Addr::from(4))));
1521                     assert_eq!(r.port, 2);
1522                 }
1523                 _ => {}
1524             }
1525         }
1526     }
1527 
1528     #[test]
test_parse_session_vector() -> Result<(), SdpParserError>1529     fn test_parse_session_vector() -> Result<(), SdpParserError> {
1530         let mut sdp_session = create_dummy_sdp_session();
1531         let mut lines: Vec<SdpLine> = Vec::new();
1532         lines.push(parse_sdp_line("a=sendrecv", 1)?);
1533         sdp_session.parse_session_vector(&mut lines)?;
1534         assert_eq!(sdp_session.attribute.len(), 1);
1535         Ok(())
1536     }
1537 
1538     #[test]
test_parse_session_vector_non_session_attribute() -> Result<(), SdpParserError>1539     fn test_parse_session_vector_non_session_attribute() -> Result<(), SdpParserError> {
1540         let mut sdp_session = create_dummy_sdp_session();
1541         let mut lines: Vec<SdpLine> = Vec::new();
1542         lines.push(parse_sdp_line("a=bundle-only", 2)?);
1543         assert!(sdp_session.parse_session_vector(&mut lines).is_err());
1544         assert_eq!(sdp_session.attribute.len(), 0);
1545         Ok(())
1546     }
1547 
1548     #[test]
test_parse_session_vector_version_repeated() -> Result<(), SdpParserError>1549     fn test_parse_session_vector_version_repeated() -> Result<(), SdpParserError> {
1550         let mut sdp_session = create_dummy_sdp_session();
1551         let mut lines: Vec<SdpLine> = Vec::new();
1552         lines.push(parse_sdp_line("v=0", 3)?);
1553         assert!(sdp_session.parse_session_vector(&mut lines).is_err());
1554         Ok(())
1555     }
1556 
1557     #[test]
test_parse_session_vector_contains_media_type() -> Result<(), SdpParserError>1558     fn test_parse_session_vector_contains_media_type() -> Result<(), SdpParserError> {
1559         let mut sdp_session = create_dummy_sdp_session();
1560         let mut lines: Vec<SdpLine> = Vec::new();
1561         lines.push(parse_sdp_line("m=audio 0 UDP/TLS/RTP/SAVPF 0", 4)?);
1562         assert!(sdp_session.parse_session_vector(&mut lines).is_err());
1563         Ok(())
1564     }
1565 
1566     #[test]
test_parse_sdp_vector_no_media_section() -> Result<(), SdpParserError>1567     fn test_parse_sdp_vector_no_media_section() -> Result<(), SdpParserError> {
1568         let mut lines: Vec<SdpLine> = Vec::new();
1569         lines.push(parse_sdp_line("v=0", 1)?);
1570         lines.push(parse_sdp_line(
1571             "o=ausername 4294967296 2 IN IP4 127.0.0.1",
1572             1,
1573         )?);
1574         lines.push(parse_sdp_line("s=SIP Call", 1)?);
1575         lines.push(parse_sdp_line("t=0 0", 1)?);
1576         lines.push(parse_sdp_line("c=IN IP6 ::1", 1)?);
1577         assert!(parse_sdp_vector(&mut lines).is_ok());
1578         Ok(())
1579     }
1580 
1581     #[test]
test_parse_sdp_vector_with_media_section() -> Result<(), SdpParserError>1582     fn test_parse_sdp_vector_with_media_section() -> Result<(), SdpParserError> {
1583         let mut lines: Vec<SdpLine> = Vec::new();
1584         lines.push(parse_sdp_line("v=0", 1)?);
1585         lines.push(parse_sdp_line(
1586             "o=ausername 4294967296 2 IN IP4 127.0.0.1",
1587             1,
1588         )?);
1589         lines.push(parse_sdp_line("s=SIP Call", 1)?);
1590         lines.push(parse_sdp_line("t=0 0", 1)?);
1591         lines.push(parse_sdp_line("m=video 56436 RTP/SAVPF 120", 1)?);
1592         lines.push(parse_sdp_line("c=IN IP6 ::1", 1)?);
1593         assert!(parse_sdp_vector(&mut lines).is_ok());
1594         Ok(())
1595     }
1596 
1597     #[test]
test_parse_sdp_vector_too_short() -> Result<(), SdpParserError>1598     fn test_parse_sdp_vector_too_short() -> Result<(), SdpParserError> {
1599         let mut lines: Vec<SdpLine> = Vec::new();
1600         lines.push(parse_sdp_line("v=0", 1)?);
1601         assert!(parse_sdp_vector(&mut lines).is_err());
1602         Ok(())
1603     }
1604 
1605     #[test]
test_parse_sdp_vector_missing_version() -> Result<(), SdpParserError>1606     fn test_parse_sdp_vector_missing_version() -> Result<(), SdpParserError> {
1607         let mut lines: Vec<SdpLine> = Vec::new();
1608         lines.push(parse_sdp_line(
1609             "o=ausername 4294967296 2 IN IP4 127.0.0.1",
1610             1,
1611         )?);
1612         for _ in 0..3 {
1613             lines.push(parse_sdp_line("a=sendrecv", 1)?);
1614         }
1615         assert!(parse_sdp_vector(&mut lines).is_err());
1616         Ok(())
1617     }
1618 
1619     #[test]
test_parse_sdp_vector_missing_origin() -> Result<(), SdpParserError>1620     fn test_parse_sdp_vector_missing_origin() -> Result<(), SdpParserError> {
1621         let mut lines: Vec<SdpLine> = Vec::new();
1622         lines.push(parse_sdp_line("v=0", 1)?);
1623         for _ in 0..3 {
1624             lines.push(parse_sdp_line("a=sendrecv", 1)?);
1625         }
1626         assert!(parse_sdp_vector(&mut lines).is_err());
1627         Ok(())
1628     }
1629 
1630     #[test]
test_parse_sdp_vector_missing_session() -> Result<(), SdpParserError>1631     fn test_parse_sdp_vector_missing_session() -> Result<(), SdpParserError> {
1632         let mut lines: Vec<SdpLine> = Vec::new();
1633         lines.push(parse_sdp_line("v=0", 1)?);
1634         lines.push(parse_sdp_line(
1635             "o=ausername 4294967296 2 IN IP4 127.0.0.1",
1636             1,
1637         )?);
1638         for _ in 0..2 {
1639             lines.push(parse_sdp_line("a=sendrecv", 1)?);
1640         }
1641         assert!(parse_sdp_vector(&mut lines).is_err());
1642         Ok(())
1643     }
1644 
1645     #[test]
test_session_add_media_works() -> Result<(), SdpParserError>1646     fn test_session_add_media_works() -> Result<(), SdpParserError> {
1647         let mut sdp_session = create_dummy_sdp_session();
1648         assert!(sdp_session
1649             .add_media(
1650                 SdpMediaValue::Audio,
1651                 SdpAttribute::Sendrecv,
1652                 99,
1653                 SdpProtocolValue::RtpSavpf,
1654                 ExplicitlyTypedAddress::from(Ipv4Addr::new(127, 0, 0, 1))
1655             )
1656             .is_ok());
1657         assert!(sdp_session.get_connection().is_some());
1658         assert_eq!(sdp_session.attribute.len(), 0);
1659         assert_eq!(sdp_session.media.len(), 1);
1660         assert_eq!(sdp_session.media[0].get_attributes().len(), 1);
1661         assert!(sdp_session.media[0]
1662             .get_attribute(SdpAttributeType::Sendrecv)
1663             .is_some());
1664         Ok(())
1665     }
1666 
1667     #[test]
test_session_add_media_invalid_attribute_fails() -> Result<(), SdpParserInternalError>1668     fn test_session_add_media_invalid_attribute_fails() -> Result<(), SdpParserInternalError> {
1669         let mut sdp_session = create_dummy_sdp_session();
1670         assert!(sdp_session
1671             .add_media(
1672                 SdpMediaValue::Audio,
1673                 SdpAttribute::IceLite,
1674                 99,
1675                 SdpProtocolValue::RtpSavpf,
1676                 ExplicitlyTypedAddress::try_from((AddressType::IpV4, "127.0.0.1"))?
1677             )
1678             .is_err());
1679         Ok(())
1680     }
1681 }
1682