rust_strict_sdp/lib.rs
1use std::{fmt, str::FromStr};
2
3pub struct Origin<'a> {
4 pub user_id: &'a [u8],
5 pub session_id: &'a [u8],
6 pub session_version: &'a [u8],
7 pub network_type: &'a [u8],
8 pub address_type: &'a [u8],
9 pub unicast_address: &'a [u8],
10}
11
12impl<'a> fmt::Debug for Origin<'a> {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 f.debug_struct("Origin")
15 .field("user_id", &String::from_utf8_lossy(&self.user_id))
16 .field("session_id", &String::from_utf8_lossy(&self.session_id))
17 .field(
18 "session_version",
19 &String::from_utf8_lossy(&self.session_version),
20 )
21 .field("network_type", &String::from_utf8_lossy(&self.network_type))
22 .field("address_type", &String::from_utf8_lossy(&self.address_type))
23 .field(
24 "unicast_address",
25 &String::from_utf8_lossy(&self.unicast_address),
26 )
27 .finish()
28 }
29}
30
31pub struct ConnectionData<'a> {
32 pub network_type: &'a [u8],
33 pub address_type: &'a [u8],
34 pub connection_address: &'a [u8],
35}
36
37impl<'a> fmt::Debug for ConnectionData<'a> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("ConnectionData")
40 .field("network_type", &String::from_utf8_lossy(&self.network_type))
41 .field("address_type", &String::from_utf8_lossy(&self.address_type))
42 .field(
43 "connection_address",
44 &String::from_utf8_lossy(&self.connection_address),
45 )
46 .finish()
47 }
48}
49
50pub struct Media<'a> {
51 pub media_type: &'a [u8],
52 pub port: u16,
53 pub number_of_ports: i32,
54 pub protocol: &'a [u8],
55 pub formats: Vec<&'a [u8]>,
56 pub connection: Option<ConnectionData<'a>>,
57 pub attributes: Vec<&'a [u8]>,
58}
59
60impl<'a> fmt::Debug for Media<'a> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 let mut debug_struct = f.debug_struct("Media");
63 debug_struct
64 .field("media_type", &String::from_utf8_lossy(&self.media_type))
65 .field("port", &self.port)
66 .field("number_of_ports", &self.number_of_ports)
67 .field("protocol", &String::from_utf8_lossy(&self.protocol));
68 for format in &self.formats {
69 debug_struct.field("format", &String::from_utf8_lossy(format));
70 }
71 if let Some(connection) = &self.connection {
72 debug_struct.field("connection", connection);
73 }
74 for attribute in &self.attributes {
75 debug_struct.field("attribute", &String::from_utf8_lossy(attribute));
76 }
77 debug_struct.finish()
78 }
79}
80
81pub struct Sdp<'a> {
82 pub version: &'a [u8],
83 pub origin: Origin<'a>,
84 pub session_name: &'a [u8],
85 pub connection: Option<ConnectionData<'a>>,
86 pub session_start_time: u64,
87 pub session_end_time: u64,
88 pub attributes: Vec<&'a [u8]>,
89 pub medias: Vec<Media<'a>>,
90}
91
92#[derive(Debug)]
93enum Phase {
94 Begin,
95 Set,
96 Reading,
97 SkippingError,
98}
99
100#[derive(Debug)]
101enum Section<'a> {
102 Main,
103 Time,
104 Media(
105 Option<&'a [u8]>,
106 Option<(u16, i32)>,
107 Option<&'a [u8]>,
108 Option<Vec<&'a [u8]>>,
109 Option<ConnectionData<'a>>,
110 Option<Vec<&'a [u8]>>,
111 ),
112}
113
114#[derive(Debug)]
115enum Operator<'a> {
116 None,
117
118 V,
119 O(
120 Option<&'a [u8]>,
121 Option<&'a [u8]>,
122 Option<&'a [u8]>,
123 Option<&'a [u8]>,
124 Option<&'a [u8]>,
125 ),
126 S,
127 I,
128 U,
129 E,
130 P,
131 C(Option<&'a [u8]>, Option<&'a [u8]>),
132 B,
133
134 T(Option<&'a [u8]>),
135 R,
136
137 Z,
138 K,
139 A,
140
141 M,
142}
143
144impl<'a> Operator<'a> {
145 fn get_order(&self) -> i32 {
146 match self {
147 Operator::None => 0,
148 Operator::V => 1,
149 Operator::O(_, _, _, _, _) => 2,
150 Operator::S => 3,
151 Operator::I => 4,
152 Operator::U => 5,
153 Operator::E => 6,
154 Operator::P => 7,
155 Operator::C(_, _) => 8,
156 Operator::B => 9,
157 Operator::T(_) => 10,
158 Operator::R => 11,
159 Operator::Z => 12,
160 Operator::K => 13,
161 Operator::A => 14,
162 Operator::M => 15,
163 }
164 }
165}
166
167pub trait AsSDP<'a> {
168 type Target;
169 fn as_sdp(&'a self) -> Option<Self::Target>;
170}
171
172impl<'a> AsSDP<'a> for [u8] {
173 type Target = Sdp<'a>;
174 fn as_sdp(&self) -> Option<Sdp> {
175 let mut phase = Phase::Begin;
176 let mut section = Section::Main;
177 let mut op: Operator = Operator::None;
178
179 let mut slice_start: Option<usize> = None;
180
181 let mut version: Option<&[u8]> = None;
182 let mut origin: Option<Origin> = None;
183 let mut session_name: Option<&[u8]> = None;
184 let mut connection: Option<ConnectionData> = None;
185
186 let mut session_start_time: u64 = 0;
187 let mut session_end_time: u64 = 0;
188
189 let mut medias: Vec<Media> = Vec::new();
190
191 let mut attributes: Vec<&[u8]> = Vec::new();
192
193 let mut i = 0;
194
195 while i < self.len() {
196 let b = self[i];
197
198 match &phase {
199 Phase::Begin => {
200 if b == b'\r' || b == b'\n' {
201 i = i + 1;
202 continue;
203 } else {
204 let mut next_op: Operator = Operator::None;
205
206 if b == b'v' {
207 next_op = Operator::V;
208 } else if b == b'o' {
209 next_op = Operator::O(None, None, None, None, None);
210 } else if b == b's' {
211 next_op = Operator::S;
212 } else if b == b'i' {
213 next_op = Operator::I;
214 } else if b == b'u' {
215 next_op = Operator::U;
216 } else if b == b'e' {
217 next_op = Operator::E;
218 } else if b == b'p' {
219 next_op = Operator::P;
220 } else if b == b'c' {
221 next_op = Operator::C(None, None);
222 } else if b == b'b' {
223 next_op = Operator::B;
224 } else if b == b't' {
225 next_op = Operator::T(None);
226 } else if b == b'r' {
227 next_op = Operator::R;
228 } else if b == b'z' {
229 next_op = Operator::Z;
230 } else if b == b'k' {
231 next_op = Operator::K;
232 } else if b == b'a' {
233 next_op = Operator::A;
234 } else if b == b'm' {
235 next_op = Operator::M;
236 }
237
238 match §ion {
239 Section::Main => {
240 if op.get_order() < next_op.get_order() {
241 op = next_op;
242 phase = Phase::Set;
243 } else if let (Operator::A, Operator::A) = (&op, &next_op) {
244 op = next_op;
245 phase = Phase::Set;
246 } else {
247 phase = Phase::SkippingError;
248 }
249 }
250
251 Section::Time => {
252 if next_op.get_order() >= Operator::T(None).get_order() {
253 op = next_op;
254 phase = Phase::Set;
255 } else {
256 phase = Phase::SkippingError;
257 }
258 }
259
260 Section::Media(_, _, _, _, _, _) => {
261 if op.get_order() < next_op.get_order() {
262 match next_op {
263 Operator::I
264 | Operator::C(_, _)
265 | Operator::B
266 | Operator::K
267 | Operator::A
268 | Operator::M => {
269 op = next_op;
270 phase = Phase::Set;
271 }
272 _ => {
273 phase = Phase::SkippingError;
274 }
275 }
276 } else if let (Operator::A, Operator::A) = (&op, &next_op) {
277 op = next_op;
278 phase = Phase::Set;
279 } else {
280 phase = Phase::SkippingError;
281 }
282 }
283 }
284 }
285 }
286
287 Phase::Reading => {
288 if b == b'\r' || b == b'\n' {
289 match &mut section {
290 Section::Main => match &op {
291 Operator::V => {
292 if let Some(slice_start) = slice_start {
293 version.replace(&self[slice_start..i]);
294 }
295 slice_start = None;
296 }
297
298 Operator::O(
299 user_id,
300 session_id,
301 session_version,
302 network_type,
303 address_type,
304 ) => {
305 match (
306 user_id,
307 session_id,
308 session_version,
309 network_type,
310 address_type,
311 ) {
312 (
313 Some(user_id),
314 Some(session_id),
315 Some(session_version),
316 Some(network_type),
317 Some(address_type),
318 ) => {
319 if let Some(slice_start) = slice_start {
320 let slice = &self[slice_start..i];
321 origin = Some(Origin {
322 user_id,
323 session_id,
324 session_version,
325 network_type,
326 address_type,
327 unicast_address: slice,
328 })
329 }
330 slice_start = None;
331 }
332
333 _ => {
334 println!(
335 "Incomplete originator and session identifier",
336 );
337 return None;
338 }
339 }
340 }
341
342 Operator::S => {
343 if let Some(slice_start) = slice_start {
344 session_name.replace(&self[slice_start..i]);
345 }
346 slice_start = None;
347 }
348
349 Operator::I | Operator::U | Operator::E | Operator::P => {}
350
351 Operator::C(network_type, address_type) => {
352 match (network_type, address_type) {
353 (Some(network_type), Some(address_type)) => {
354 if let Some(slice_start) = slice_start {
355 let slice = &self[slice_start..i];
356 connection = Some(ConnectionData {
357 network_type,
358 address_type,
359 connection_address: slice,
360 });
361 }
362 slice_start = None;
363 }
364
365 _ => {
366 println!("Incomplete connection information",);
367 return None;
368 }
369 }
370 }
371
372 Operator::B | Operator::Z | Operator::K => {}
373
374 Operator::A => {
375 if let Some(slice_start) = slice_start {
376 attributes.push(&self[slice_start..i]);
377 }
378 slice_start = None;
379 }
380
381 _ => {
382 println!("Unknown description in main section");
383 return None;
384 }
385 },
386
387 Section::Time => match &op {
388 Operator::T(start_time) => {
389 if let Some(start_time) = start_time {
390 if start_time == b"0" {
391 session_start_time = u64::MIN;
392 } else {
393 if let Ok(t) = start_time.to_int::<u64>() {
394 session_start_time = t - 2208988800;
395 } else {
396 println!("Bad time description format",);
397 return None;
398 }
399 }
400 if let Some(slice_start) = slice_start {
401 let slice = &self[slice_start..i];
402 if slice == b"0" {
403 session_end_time = u64::MAX;
404 } else {
405 if let Ok(t) = slice.to_int::<u64>() {
406 session_end_time = t - 2208988800;
407 } else {
408 println!("Bad time description format",);
409 return None;
410 }
411 }
412 } else {
413 println!("Bad time description format");
414 return None;
415 }
416 slice_start = None;
417 } else {
418 println!("Bad time description format");
419 return None;
420 }
421 }
422
423 Operator::R => {}
424
425 // Sometimes a= comes after t=
426 Operator::A => {
427 if let Some(slice_start) = slice_start {
428 attributes.push(&self[slice_start..i]);
429 }
430 slice_start = None;
431 }
432
433 _ => {
434 println!("Unknown description in time section");
435 return None;
436 }
437 },
438
439 Section::Media(_, _, _, formats, connection, attributes) => match &op {
440 Operator::None => {
441 if let Some(slice_start) = slice_start {
442 if let Some(formats) = formats {
443 formats.push(&self[slice_start..i]);
444 } else {
445 let mut v = Vec::new();
446 v.push(&self[slice_start..i]);
447 formats.replace(v);
448 }
449 }
450 slice_start = None;
451 }
452
453 Operator::I => {}
454
455 Operator::C(network_type, address_type) => {
456 match (network_type, address_type) {
457 (Some(network_type), Some(address_type)) => {
458 if let Some(slice_start) = slice_start {
459 let slice = &self[slice_start..i];
460 *connection = Some(ConnectionData {
461 network_type,
462 address_type,
463 connection_address: slice,
464 });
465 }
466 slice_start = None;
467 }
468
469 _ => {
470 println!("Incomplete connection information",);
471 return None;
472 }
473 }
474 }
475
476 Operator::B | Operator::K => {}
477
478 Operator::A => {
479 if let Some(slice_start) = slice_start {
480 if let Some(attributes) = attributes {
481 attributes.push(&self[slice_start..i]);
482 } else {
483 let mut v = Vec::new();
484 v.push(&self[slice_start..i]);
485 attributes.replace(v);
486 }
487 }
488 slice_start = None;
489 }
490
491 _ => {}
492 },
493 }
494
495 phase = Phase::Begin;
496 } else if b == b' ' {
497 let mut freeform = false;
498
499 match &mut section {
500 Section::Main => match &mut op {
501 Operator::V => {
502 println!("Duplicated protocol version");
503 return None;
504 }
505
506 Operator::O(
507 user_id,
508 session_id,
509 session_version,
510 network_type,
511 address_type,
512 ) => {
513 match (
514 &user_id,
515 &session_id,
516 &session_version,
517 &network_type,
518 &address_type,
519 ) {
520 (Some(_), Some(_), Some(_), Some(_), None) => {
521 if let Some(slice_start) = slice_start {
522 address_type.replace(&self[slice_start..i]);
523 }
524 slice_start = None;
525 }
526
527 (Some(_), Some(_), Some(_), None, None) => {
528 if let Some(slice_start) = slice_start {
529 network_type.replace(&self[slice_start..i]);
530 }
531 slice_start = None;
532 }
533
534 (Some(_), Some(_), None, None, None) => {
535 if let Some(slice_start) = slice_start {
536 session_version.replace(&self[slice_start..i]);
537 }
538 slice_start = None;
539 }
540
541 (Some(_), None, None, None, None) => {
542 if let Some(slice_start) = slice_start {
543 session_id.replace(&self[slice_start..i]);
544 }
545 slice_start = None;
546 }
547
548 (None, None, None, None, None) => {
549 if let Some(slice_start) = slice_start {
550 user_id.replace(&self[slice_start..i]);
551 }
552 slice_start = None;
553 }
554
555 _ => {
556 println!("Bad originator and session identifier",);
557 return None;
558 }
559 }
560 }
561
562 Operator::S => {
563 println!("Duplicated session name");
564 return None;
565 }
566
567 Operator::I | Operator::U | Operator::E | Operator::P => {}
568
569 Operator::C(network_type, address_type) => {
570 match (&network_type, &address_type) {
571 (Some(_), None) => {
572 if let Some(slice_start) = slice_start {
573 address_type.replace(&self[slice_start..i]);
574 }
575 slice_start = None;
576 }
577
578 (None, None) => {
579 if let Some(slice_start) = slice_start {
580 network_type.replace(&self[slice_start..i]);
581 }
582 slice_start = None;
583 }
584
585 _ => {
586 println!("Bad connection information");
587 return None;
588 }
589 }
590 }
591
592 Operator::B | Operator::Z | Operator::K => {}
593
594 Operator::A => {
595 freeform = true;
596 }
597
598 _ => {
599 println!("Unknown description in main section");
600 return None;
601 }
602 },
603
604 Section::Time => match &mut op {
605 Operator::T(start_time) => {
606 if let Some(slice_start) = slice_start {
607 start_time.replace(&self[slice_start..i]);
608 }
609 slice_start = None;
610 }
611
612 Operator::R => {}
613
614 Operator::A => {
615 freeform = true;
616 }
617
618 _ => {
619 println!("Unknown description in time section");
620 return None;
621 }
622 },
623
624 Section::Media(media_type, port_pair, protocol, formats, _, _) => {
625 match &mut op {
626 Operator::None => {
627 match (&media_type, &port_pair, &protocol, &formats) {
628 (Some(_), Some(_), Some(_), _) => {
629 if let Some(slice_start) = slice_start {
630 if let Some(formats) = formats {
631 formats.push(&self[slice_start..i]);
632 } else {
633 let mut v = Vec::new();
634 v.push(&self[slice_start..i]);
635 formats.replace(v);
636 }
637 }
638 slice_start = None;
639 }
640
641 (Some(_), Some(_), None, None) => {
642 if let Some(slice_start) = slice_start {
643 protocol.replace(&self[slice_start..i]);
644 }
645 slice_start = None;
646 }
647
648 (Some(_), None, None, None) => {
649 if let Some(slice_start) = slice_start {
650 let slice = &self[slice_start..i];
651 let mut iter = slice.iter();
652 if let Some(idx) = iter.position(|c| *c == b'/')
653 {
654 if let (Ok(port), Ok(number_of_ports)) = (
655 slice[..idx].to_int::<u16>(),
656 slice[idx + 1..].to_int::<i32>(),
657 ) {
658 port_pair
659 .replace((port, number_of_ports));
660 } else {
661 println!("Bad media connection information format");
662 return None;
663 }
664 } else {
665 if let Ok(port) = slice.to_int::<u16>() {
666 port_pair.replace((port, 1));
667 } else {
668 println!("Bad media connection information format");
669 return None;
670 }
671 }
672 }
673 slice_start = None;
674 }
675
676 (None, None, None, None) => {
677 if let Some(slice_start) = slice_start {
678 media_type.replace(&self[slice_start..i]);
679 }
680 slice_start = None;
681 }
682
683 _ => {}
684 }
685 }
686
687 Operator::I => {}
688
689 Operator::C(network_type, address_type) => {
690 match (&network_type, &address_type) {
691 (Some(_), None) => {
692 if let Some(slice_start) = slice_start {
693 address_type.replace(&self[slice_start..i]);
694 }
695 slice_start = None;
696 }
697
698 (None, None) => {
699 if let Some(slice_start) = slice_start {
700 network_type.replace(&self[slice_start..i]);
701 }
702 slice_start = None;
703 }
704
705 _ => {
706 println!("Bad connection information");
707 return None;
708 }
709 }
710 }
711 Operator::B | Operator::K => {}
712
713 Operator::A => {
714 freeform = true;
715 }
716
717 _ => {
718 println!("Unknown description in media section",);
719 return None;
720 }
721 }
722 }
723 }
724
725 if !freeform {
726 slice_start = None;
727 }
728 } else {
729 if slice_start.is_none() {
730 slice_start = Some(i);
731 }
732 }
733 }
734
735 Phase::Set => {
736 if b == b'=' {
737 match &mut op {
738 Operator::T(_) | Operator::R => {
739 section = Section::Time;
740 }
741
742 Operator::M => {
743 if let Section::Media(
744 Some(media_type),
745 Some(port_pair),
746 Some(protocol),
747 Some(formats),
748 connection,
749 Some(attributes),
750 ) = section
751 {
752 let (port, number_of_ports) = port_pair;
753 medias.push(Media {
754 media_type,
755 port,
756 number_of_ports,
757 protocol,
758 formats,
759 connection,
760 attributes,
761 });
762 }
763
764 op = Operator::None;
765
766 section = Section::Media(None, None, None, None, None, None);
767 }
768
769 _ => {}
770 }
771
772 phase = Phase::Reading;
773 } else if b == b'\r' || b == b'\n' {
774 phase = Phase::Begin;
775 } else {
776 phase = Phase::SkippingError;
777 }
778 }
779
780 Phase::SkippingError => {
781 if b == b'\r' || b == b'\n' {
782 phase = Phase::Begin;
783 }
784 }
785 }
786
787 i = i + 1;
788 }
789
790 if let Section::Media(
791 Some(media_type),
792 Some(port_pair),
793 Some(protocol),
794 Some(formats),
795 connection,
796 Some(attributes),
797 ) = section
798 {
799 let (port, number_of_ports) = port_pair;
800 medias.push(Media {
801 media_type,
802 port,
803 number_of_ports,
804 protocol,
805 formats,
806 connection,
807 attributes,
808 });
809 }
810
811 if let (Some(version), Some(origin), Some(session_name)) = (version, origin, session_name) {
812 Some(Sdp {
813 version,
814 origin,
815 session_name,
816 connection,
817 session_start_time,
818 session_end_time,
819 attributes,
820 medias,
821 })
822 } else {
823 println!("Incomplete sdp");
824 None
825 }
826 }
827}
828
829impl<'a> fmt::Debug for Sdp<'a> {
830 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831 let mut debug_struct = f.debug_struct("Sdp");
832 debug_struct
833 .field("version", &String::from_utf8_lossy(&self.version))
834 .field("origin", &self.origin)
835 .field("session_name", &String::from_utf8_lossy(&self.session_name))
836 .field("connection", &self.connection)
837 .field("start_time", &self.session_start_time)
838 .field("end_time", &self.session_end_time);
839 for attribute in &self.attributes {
840 debug_struct.field("attribute", &String::from_utf8_lossy(attribute));
841 }
842 debug_struct.field("medias", &self.medias).finish()
843 }
844}
845
846trait ToInt {
847 fn to_int<R>(&self) -> Result<R, String>
848 where
849 R: FromStr;
850}
851
852impl ToInt for [u8] {
853 fn to_int<R>(&self) -> Result<R, String>
854 where
855 R: FromStr,
856 {
857 match std::str::from_utf8(self) {
858 Ok(s) => match R::from_str(s) {
859 Ok(i) => return Ok(i),
860 Err(_) => {
861 return Err(String::from("std::num::ParseIntError"));
862 }
863 },
864 Err(e) => {
865 // std::str::Utf8Error
866 let s: String = format!("{}", e);
867 return Err(s);
868 }
869 }
870 }
871}