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