1// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use core::net::IpAddr;
8
9use xso::{AsXml, FromXml};
10
11use crate::jingle_ice_udp::Type;
12use crate::ns;
13
14/// Wrapper element for an raw UDP transport.
15#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)]
16#[xml(namespace = ns::JINGLE_RAW_UDP, name = "transport")]
17pub struct Transport {
18 /// List of candidates for this raw UDP session.
19 #[xml(child(n = ..))]
20 pub candidates: Vec<Candidate>,
21}
22
23impl Transport {
24 /// Create a new ICE-UDP transport.
25 pub fn new() -> Transport {
26 Transport::default()
27 }
28
29 /// Add a candidate to this transport.
30 pub fn add_candidate(mut self, candidate: Candidate) -> Self {
31 self.candidates.push(candidate);
32 self
33 }
34}
35
36/// A candidate for an ICE-UDP session.
37#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
38#[xml(namespace = ns::JINGLE_RAW_UDP, name = "candidate")]
39pub struct Candidate {
40 /// A Component ID as defined in ICE-CORE.
41 #[xml(attribute)]
42 pub component: u8,
43
44 /// An index, starting at 0, that enables the parties to keep track of updates to the
45 /// candidate throughout the life of the session.
46 #[xml(attribute)]
47 pub generation: u8,
48
49 /// A unique identifier for the candidate.
50 #[xml(attribute)]
51 pub id: String,
52
53 /// The Internet Protocol (IP) address for the candidate transport mechanism; this can be
54 /// either an IPv4 address or an IPv6 address.
55 #[xml(attribute)]
56 pub ip: IpAddr,
57
58 /// The port at the candidate IP address.
59 #[xml(attribute)]
60 pub port: u16,
61
62 /// A Candidate Type as defined in ICE-CORE.
63 #[xml(attribute(default, name = "type"))]
64 pub type_: Option<Type>,
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use minidom::Element;
71
72 #[cfg(target_pointer_width = "32")]
73 #[test]
74 fn test_size() {
75 assert_size!(Transport, 12);
76 assert_size!(Candidate, 36);
77 }
78
79 #[cfg(target_pointer_width = "64")]
80 #[test]
81 fn test_size() {
82 assert_size!(Transport, 24);
83 assert_size!(Candidate, 48);
84 }
85
86 #[test]
87 fn example_1() {
88 let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:raw-udp:1'>
89 <candidate component='1'
90 generation='0'
91 id='a9j3mnbtu1'
92 ip='10.1.1.104'
93 port='13540'/>
94</transport>"
95 .parse()
96 .unwrap();
97 let mut transport = Transport::try_from(elem).unwrap();
98 assert_eq!(transport.candidates.len(), 1);
99 let candidate = transport.candidates.pop().unwrap();
100 assert_eq!(candidate.component, 1);
101 assert_eq!(candidate.generation, 0);
102 assert_eq!(candidate.id, "a9j3mnbtu1");
103 assert_eq!(candidate.ip, "10.1.1.104".parse::<IpAddr>().unwrap());
104 assert_eq!(candidate.port, 13540u16);
105 assert!(candidate.type_.is_none());
106 }
107}