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 &section {
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}