1use std::fmt;
2use std::net::IpAddr;
3use std::str::FromStr;
4
5use super::{Error, Method};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct Transport {
9 lower: Option<Lower>,
10 parameters: Vec<Parameter>,
11}
12
13impl Transport {
14 pub fn new() -> Self {
15 Self {
16 lower: None,
17 parameters: Vec::new(),
18 }
19 }
20
21 pub fn with_lower_protocol(mut self, lower: Lower) -> Self {
22 self.lower = Some(lower);
23 self
24 }
25
26 pub fn with_parameter(mut self, parameter: Parameter) -> Self {
27 self.parameters.push(parameter);
28 self
29 }
30
31 pub fn with_parameters(mut self, parameters: impl IntoIterator<Item = Parameter>) -> Self {
32 self.parameters.extend(parameters);
33 self
34 }
35
36 pub fn lower_protocol(&self) -> Option<&Lower> {
37 self.lower.as_ref()
38 }
39
40 pub fn parameters(&self) -> &impl IntoIterator<Item = Parameter> {
41 &self.parameters
42 }
43
44 pub fn parameters_iter(&self) -> impl Iterator<Item = &Parameter> {
45 self.parameters.iter()
46 }
47
48 pub fn destination(&self) -> Option<&IpAddr> {
49 self.parameters_iter()
50 .filter_map(|parameter| {
51 if let Parameter::Destination(ip_addr) = parameter {
52 Some(ip_addr)
53 } else {
54 None
55 }
56 })
57 .next()
58 }
59
60 pub fn port(&self) -> Option<&Port> {
61 self.parameters_iter()
62 .filter_map(|parameter| {
63 if let Parameter::Port(port) = parameter {
64 Some(port)
65 } else {
66 None
67 }
68 })
69 .next()
70 }
71
72 pub fn client_port(&self) -> Option<&Port> {
73 self.parameters_iter()
74 .filter_map(|parameter| {
75 if let Parameter::ClientPort(port) = parameter {
76 Some(port)
77 } else {
78 None
79 }
80 })
81 .next()
82 }
83
84 pub fn server_port(&self) -> Option<&Port> {
85 self.parameters_iter()
86 .filter_map(|parameter| {
87 if let Parameter::ServerPort(port) = parameter {
88 Some(port)
89 } else {
90 None
91 }
92 })
93 .next()
94 }
95
96 pub fn interleaved_channel(&self) -> Option<&Channel> {
97 self.parameters_iter()
98 .filter_map(|parameter| {
99 if let Parameter::Interleaved(channel) = parameter {
100 Some(channel)
101 } else {
102 None
103 }
104 })
105 .next()
106 }
107}
108
109impl Default for Transport {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl fmt::Display for Transport {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 write!(f, "RTP/AVP")?;
118 if let Some(lower) = self.lower.as_ref() {
119 write!(f, "/{}", lower)?;
120 }
121 for parameter in self.parameters.iter() {
122 write!(f, ";{}", parameter)?;
123 }
124 Ok(())
125 }
126}
127
128impl FromStr for Transport {
129 type Err = Error;
130
131 fn from_str(s: &str) -> Result<Self, Self::Err> {
132 let (spec, params) = s
133 .split_once(';')
134 .map(|(spec, params)| (spec, Some(params)))
135 .unwrap_or_else(|| (s, None));
136
137 if spec.starts_with("RTP/AVP") {
138 let lower = spec
139 .split('/')
140 .nth(2)
141 .map(|lower| lower.parse())
142 .transpose()?;
143
144 let parameters = params
145 .map(|params| {
146 params
147 .split(';')
148 .map(|p| p.parse())
149 .collect::<Result<Vec<_>, _>>()
150 })
151 .transpose()?
152 .unwrap_or_default();
153
154 Ok(Transport { lower, parameters })
155 } else {
156 Err(Error::TransportProtocolProfileMissing {
157 value: s.to_string(),
158 })
159 }
160 }
161}
162
163#[derive(Debug, Clone, PartialEq)]
164pub enum Lower {
165 Tcp,
166 Udp,
167}
168
169impl fmt::Display for Lower {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 match self {
172 Lower::Tcp => write!(f, "TCP"),
173 Lower::Udp => write!(f, "UDP"),
174 }
175 }
176}
177
178impl FromStr for Lower {
179 type Err = Error;
180
181 fn from_str(s: &str) -> Result<Self, Self::Err> {
182 match s {
183 "TCP" => Ok(Lower::Tcp),
184 "UDP" => Ok(Lower::Udp),
185 _ => Err(Error::TransportLowerUnknown {
186 value: s.to_string(),
187 }),
188 }
189 }
190}
191
192#[derive(Debug, Clone, PartialEq)]
193pub enum Parameter {
194 Unicast,
195 Multicast,
196 Destination(IpAddr),
197 Interleaved(Channel),
198 Append,
199 Ttl(usize),
200 Layers(usize),
201 Port(Port),
202 ClientPort(Port),
203 ServerPort(Port),
204 Ssrc(String),
205 Mode(Method),
206}
207
208impl fmt::Display for Parameter {
209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210 match self {
211 Parameter::Unicast => {
212 write!(f, "unicast")
213 }
214 Parameter::Multicast => {
215 write!(f, "multicast")
216 }
217 Parameter::Destination(host) => {
218 write!(f, "destination={}", host)
219 }
220 Parameter::Interleaved(channel) => {
221 write!(f, "interleaved={}", channel)
222 }
223 Parameter::Append => {
224 write!(f, "append")
225 }
226 Parameter::Ttl(ttl) => {
227 write!(f, "ttl={}", ttl)
228 }
229 Parameter::Layers(layers) => {
230 write!(f, "layers={}", layers)
231 }
232 Parameter::Port(port) => {
233 write!(f, "port={}", port)
234 }
235 Parameter::ClientPort(client_port) => {
236 write!(f, "client_port={}", client_port)
237 }
238 Parameter::ServerPort(server_port) => {
239 write!(f, "server_port={}", server_port)
240 }
241 Parameter::Ssrc(ssrc) => {
242 write!(f, "ssrc={}", ssrc)
243 }
244 Parameter::Mode(method) => {
245 write!(f, "mode=\"{}\"", method)
246 }
247 }
248 }
249}
250
251impl FromStr for Parameter {
252 type Err = Error;
253
254 fn from_str(s: &str) -> Result<Self, Self::Err> {
255 let mut parts = s.split('=');
256 let var = parts
257 .next()
258 .ok_or_else(|| Error::TransportParameterInvalid {
259 parameter: s.to_string(),
260 })?;
261
262 let mut val_or_err = || {
263 parts
264 .next()
265 .ok_or_else(|| Error::TransportParameterValueMissing {
266 var: var.to_string(),
267 })
268 };
269
270 fn parse_or_err<T: FromStr>(var: &str, val: &str) -> Result<T, Error> {
271 val.parse::<T>()
272 .map_err(|_| Error::TransportParameterValueInvalid {
273 var: var.to_string(),
274 val: val.to_string(),
275 })
276 }
277
278 match var {
279 "unicast" => Ok(Parameter::Unicast),
280 "multicast" => Ok(Parameter::Multicast),
281 "destination" => {
282 let val = val_or_err()?;
283 let host = parse_or_err(var, val)?;
284 Ok(Parameter::Destination(host))
285 }
286 "interleaved" => {
287 let val = val_or_err()?;
288 let channel = parse_or_err(var, val)?;
289 Ok(Parameter::Interleaved(channel))
290 }
291 "append" => Ok(Parameter::Append),
292 "ttl" => {
293 let val = val_or_err()?;
294 let ttl = parse_or_err(var, val)?;
295 Ok(Parameter::Ttl(ttl))
296 }
297 "layers" => {
298 let val = val_or_err()?;
299 let layers = parse_or_err(var, val)?;
300 Ok(Parameter::Layers(layers))
301 }
302 "port" => {
303 let val = val_or_err()?;
304 let port = parse_or_err(var, val)?;
305 Ok(Parameter::Port(port))
306 }
307 "client_port" => {
308 let val = val_or_err()?;
309 let port = parse_or_err(var, val)?;
310 Ok(Parameter::ClientPort(port))
311 }
312 "server_port" => {
313 let val = val_or_err()?;
314 let port = parse_or_err(var, val)?;
315 Ok(Parameter::ServerPort(port))
316 }
317 "ssrc" => {
318 let val = val_or_err()?;
319 Ok(Parameter::Ssrc(val.to_string()))
320 }
321 "mode" => {
322 let val = val_or_err()?;
323 let val = val
324 .strip_prefix('"')
325 .unwrap_or(val)
326 .strip_suffix('"')
327 .unwrap_or(val);
328 let method = parse_or_err(var, val)?;
329 Ok(Parameter::Mode(method))
330 }
331 _ => Err(Error::TransportParameterUnknown {
332 var: var.to_string(),
333 }),
334 }
335 }
336}
337
338#[derive(Debug, Clone, PartialEq)]
339pub enum Channel {
340 Single(u8),
341 Range(u8, u8),
342}
343
344impl fmt::Display for Channel {
345 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
346 match self {
347 Channel::Single(channel) => {
348 write!(f, "{}", channel)
349 }
350 Channel::Range(channel_1, channel_2) => {
351 write!(f, "{}-{}", channel_1, channel_2)
352 }
353 }
354 }
355}
356
357impl FromStr for Channel {
358 type Err = Error;
359
360 fn from_str(s: &str) -> Result<Self, Self::Err> {
361 let mut parts = s.split('-');
362 let channel_1 = parts
363 .next()
364 .and_then(|channel| channel.parse::<u8>().ok())
365 .ok_or_else(|| Error::TransportChannelMalformed {
366 value: s.to_string(),
367 })?;
368 let channel_2 = parts.next().map(|channel| {
369 channel
370 .parse::<u8>()
371 .map_err(|_| Error::TransportChannelMalformed {
372 value: s.to_string(),
373 })
374 });
375
376 Ok(if let Some(channel_2) = channel_2 {
377 Channel::Range(channel_1, channel_2?)
378 } else {
379 Channel::Single(channel_1)
380 })
381 }
382}
383
384#[derive(Debug, Clone, PartialEq)]
385pub enum Port {
386 Single(u16),
387 Range(u16, u16),
388}
389
390impl fmt::Display for Port {
391 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392 match self {
393 Port::Single(port) => {
394 write!(f, "{}", port)
395 }
396 Port::Range(port_1, port_2) => {
397 write!(f, "{}-{}", port_1, port_2)
398 }
399 }
400 }
401}
402
403impl FromStr for Port {
404 type Err = Error;
405
406 fn from_str(s: &str) -> Result<Self, Self::Err> {
407 let mut parts = s.split('-');
408 let port_1 = parts
409 .next()
410 .and_then(|port| port.parse::<u16>().ok())
411 .ok_or_else(|| Error::TransportPortMalformed {
412 value: s.to_string(),
413 })?;
414 let port_2 = parts.next().map(|port| {
415 port.parse::<u16>()
416 .map_err(|_| Error::TransportPortMalformed {
417 value: s.to_string(),
418 })
419 });
420
421 Ok(if let Some(port_2) = port_2 {
422 Port::Range(port_1, port_2?)
423 } else {
424 Port::Single(port_1)
425 })
426 }
427}
428
429#[cfg(test)]
430mod tests {
431
432 use super::{Channel, Error, Lower, Method, Parameter, Port, Transport};
433
434 #[test]
435 fn parse_minimal() {
436 assert_eq!("RTP/AVP".parse::<Transport>().unwrap(), Transport::new(),);
437 }
438
439 #[test]
440 fn parse_lower_tcp() {
441 assert_eq!(
442 "RTP/AVP/TCP".parse::<Transport>().unwrap(),
443 Transport::new().with_lower_protocol(Lower::Tcp),
444 );
445 }
446
447 #[test]
448 fn parse_lower_udp() {
449 assert_eq!(
450 "RTP/AVP/UDP".parse::<Transport>().unwrap(),
451 Transport::new().with_lower_protocol(Lower::Udp),
452 );
453 }
454
455 #[test]
456 fn parse_unicast() {
457 assert_eq!(
458 "RTP/AVP;unicast".parse::<Transport>().unwrap(),
459 Transport::new().with_parameter(Parameter::Unicast),
460 );
461 }
462
463 #[test]
464 fn parse_destination_missing_value() {
465 assert!(matches!(
466 "RTP/AVP/UDP;destination".parse::<Transport>(),
467 Err(Error::TransportParameterValueMissing { var: _ }),
468 ),);
469 }
470
471 #[test]
472 fn parse_destination_ip() {
473 assert_eq!(
474 "RTP/AVP/UDP;destination=127.0.0.1"
475 .parse::<Transport>()
476 .unwrap(),
477 Transport::new()
478 .with_lower_protocol(Lower::Udp)
479 .with_parameter(Parameter::Destination([127, 0, 0, 1].into())),
480 );
481 }
482
483 #[test]
484 fn parse_interleaved_invalid() {
485 assert!(matches!(
486 "RTP/AVP/UDP;interleaved=invalid".parse::<Transport>(),
487 Err(Error::TransportParameterValueInvalid { var: _, val: _ }),
488 ),);
489 }
490
491 #[test]
492 fn parse_interleaved_channel() {
493 assert_eq!(
494 "RTP/AVP/UDP;interleaved=8-9".parse::<Transport>().unwrap(),
495 Transport::new()
496 .with_lower_protocol(Lower::Udp)
497 .with_parameter(Parameter::Interleaved(Channel::Range(8, 9))),
498 );
499 }
500
501 #[test]
502 fn parse_layers() {
503 assert_eq!(
504 "RTP/AVP/UDP;layers=3".parse::<Transport>().unwrap(),
505 Transport::new()
506 .with_lower_protocol(Lower::Udp)
507 .with_parameter(Parameter::Layers(3)),
508 );
509 }
510
511 #[test]
512 fn parse_port_single() {
513 assert_eq!(
514 "RTP/AVP/UDP;port=3".parse::<Transport>().unwrap(),
515 Transport::new()
516 .with_lower_protocol(Lower::Udp)
517 .with_parameter(Parameter::Port(Port::Single(3))),
518 );
519 }
520
521 #[test]
522 fn parse_server_port_range() {
523 assert_eq!(
524 "RTP/AVP/UDP;server_port=3-4".parse::<Transport>().unwrap(),
525 Transport::new()
526 .with_lower_protocol(Lower::Udp)
527 .with_parameter(Parameter::ServerPort(Port::Range(3, 4))),
528 );
529 }
530
531 #[test]
532 fn parse_ssrc() {
533 assert_eq!(
534 "RTP/AVP/UDP;ssrc=ABCDEF".parse::<Transport>().unwrap(),
535 Transport::new()
536 .with_lower_protocol(Lower::Udp)
537 .with_parameter(Parameter::Ssrc("ABCDEF".to_string())),
538 );
539 }
540
541 #[test]
542 fn parse_mode_method_unknown() {
543 assert!(matches!(
544 "RTP/AVP/UDP;mode=UNKNOWN".parse::<Transport>(),
545 Err(Error::TransportParameterValueInvalid { var: _, val: _ }),
546 ),);
547 }
548
549 #[test]
550 fn parse_mode_method() {
551 assert_eq!(
552 "RTP/AVP/UDP;mode=PLAY".parse::<Transport>().unwrap(),
553 Transport::new()
554 .with_lower_protocol(Lower::Udp)
555 .with_parameter(Parameter::Mode(Method::Play)),
556 );
557 assert_eq!(
558 "RTP/AVP/UDP;mode=\"PLAY\"".parse::<Transport>().unwrap(),
559 Transport::new()
560 .with_lower_protocol(Lower::Udp)
561 .with_parameter(Parameter::Mode(Method::Play)),
562 );
563 }
564
565 #[test]
566 fn parse_rfc2326_section_12_39_examples() {
567 assert_eq!(
568 "RTP/AVP;multicast;ttl=127;mode=\"PLAY\""
569 .parse::<Transport>()
570 .unwrap(),
571 Transport::new()
572 .with_parameter(Parameter::Multicast)
573 .with_parameter(Parameter::Ttl(127))
574 .with_parameter(Parameter::Mode(Method::Play)),
575 );
576 assert_eq!(
577 "RTP/AVP;unicast;client_port=3456-3457;mode=\"PLAY\""
578 .parse::<Transport>()
579 .unwrap(),
580 Transport::new()
581 .with_parameter(Parameter::Unicast)
582 .with_parameter(Parameter::ClientPort(Port::Range(3456, 3457)))
583 .with_parameter(Parameter::Mode(Method::Play)),
584 );
585 }
586
587 #[test]
588 fn format_minimal() {
589 assert_eq!(&Transport::new().to_string(), "RTP/AVP",);
590 }
591
592 #[test]
593 fn format_lower_tcp() {
594 assert_eq!(
595 &Transport::new().with_lower_protocol(Lower::Tcp).to_string(),
596 "RTP/AVP/TCP",
597 );
598 }
599
600 #[test]
601 fn format_lower_udp() {
602 assert_eq!(
603 &Transport::new().with_lower_protocol(Lower::Udp).to_string(),
604 "RTP/AVP/UDP",
605 );
606 }
607
608 #[test]
609 fn format_unicast() {
610 assert_eq!(
611 &Transport::new()
612 .with_lower_protocol(Lower::Udp)
613 .with_parameter(Parameter::Unicast)
614 .to_string(),
615 "RTP/AVP/UDP;unicast",
616 );
617 }
618
619 #[test]
620 fn format_rfc2326_section_12_39_examples() {
621 assert_eq!(
622 &Transport::new()
623 .with_parameter(Parameter::Multicast)
624 .with_parameter(Parameter::Ttl(127))
625 .with_parameter(Parameter::Mode(Method::Play))
626 .to_string(),
627 "RTP/AVP;multicast;ttl=127;mode=\"PLAY\"",
628 );
629 assert_eq!(
630 &Transport::new()
631 .with_parameter(Parameter::Unicast)
632 .with_parameter(Parameter::ClientPort(Port::Range(3456, 3457)))
633 .with_parameter(Parameter::Mode(Method::Play))
634 .to_string(),
635 "RTP/AVP;unicast;client_port=3456-3457;mode=\"PLAY\"",
636 );
637 }
638
639 #[test]
640 fn format_all_parameters() {
641 assert_eq!(
642 &Transport::new()
643 .with_lower_protocol(Lower::Tcp)
644 .with_parameter(Parameter::Unicast)
645 .with_parameter(Parameter::Multicast)
646 .with_parameter(Parameter::Destination([1, 2, 3, 4].into()))
647 .with_parameter(Parameter::Interleaved(Channel::Range(12, 13)))
648 .with_parameter(Parameter::Append)
649 .with_parameter(Parameter::Ttl(999))
650 .with_parameter(Parameter::Layers(2))
651 .with_parameter(Parameter::Port(Port::Single(8)))
652 .with_parameter(Parameter::ClientPort(Port::Range(9, 10)))
653 .with_parameter(Parameter::ServerPort(Port::Range(11, 12)))
654 .with_parameter(Parameter::Ssrc("01234ABCDEF".to_string()))
655 .with_parameter(Parameter::Mode(Method::Describe))
656 .to_string(),
657 "RTP/AVP/TCP;unicast;multicast;destination=1.2.3.4;interleaved=12-13;append;ttl=999;layers=2;port=8;client_port=9-10;server_port=11-12;ssrc=01234ABCDEF;mode=\"DESCRIBE\"",
658 );
659 }
660}