1use std::net::{
4 IpAddr,
5 Ipv4Addr,
6 Ipv6Addr,
7 SocketAddr,
8};
9
10use nom::{
11 IResult,
12 do_parse, alt, switch, terminated, map, cond, call, take,
13 number::complete::{be_u16, le_u8},
14};
15use cookie_factory::{do_gen, gen_slice, gen_cond, gen_call, gen_be_u8, gen_be_u16};
16
17use tox_binary_io::*;
18
19pub const SIZE_IPPORT: usize = 19;
21
22pub const IPV4_PADDING_SIZE: usize = 12;
25
26#[derive(Copy, Clone, Debug, Eq, PartialEq)]
29pub enum IpPortPadding {
30 WithPadding,
32 NoPadding,
34}
35
36#[derive(Copy, Clone, Debug, Eq, PartialEq)]
44pub enum ProtocolType {
45 UDP,
47 TCP
49}
50
51#[derive(Clone, Debug, Eq, PartialEq)]
65pub struct IpPort {
66 pub protocol: ProtocolType,
68 pub ip_addr: IpAddr,
70 pub port: u16
72}
73
74impl IpPort {
75 fn ip_type(&self) -> u8 {
89 if self.ip_addr.is_ipv4() {
90 match self.protocol {
91 ProtocolType::UDP => 2,
92 ProtocolType::TCP => 130,
93 }
94 } else {
95 match self.protocol {
96 ProtocolType::UDP => 10,
97 ProtocolType::TCP => 138,
98 }
99 }
100 }
101
102 pub fn from_udp_bytes(input: &[u8], padding: IpPortPadding) -> IResult<&[u8], IpPort> {
104 do_parse!(input,
105 ip_addr: switch!(le_u8,
106 2 => terminated!(
107 map!(Ipv4Addr::from_bytes, IpAddr::V4),
108 cond!(padding == IpPortPadding::WithPadding, take!(IPV4_PADDING_SIZE))
109 ) |
110 10 => map!(Ipv6Addr::from_bytes, IpAddr::V6)
111 ) >>
112 port: be_u16 >>
113 (IpPort { protocol: ProtocolType::UDP, ip_addr, port })
114 )
115 }
116
117 pub fn from_tcp_bytes(input: &[u8], padding: IpPortPadding) -> IResult<&[u8], IpPort> {
119 do_parse!(input,
120 ip_addr: switch!(le_u8,
121 130 => terminated!(
122 map!(Ipv4Addr::from_bytes, IpAddr::V4),
123 cond!(padding == IpPortPadding::WithPadding, take!(IPV4_PADDING_SIZE))
124 ) |
125 138 => map!(Ipv6Addr::from_bytes, IpAddr::V6)
126 ) >>
127 port: be_u16 >>
128 (IpPort { protocol: ProtocolType::TCP, ip_addr, port })
129 )
130 }
131
132 pub fn from_bytes(input: &[u8], padding: IpPortPadding) -> IResult<&[u8], IpPort> {
134 alt!(input, call!(IpPort::from_udp_bytes, padding) | call!(IpPort::from_tcp_bytes, padding))
135 }
136
137 pub fn to_udp_bytes<'a>(&self, buf: (&'a mut [u8], usize), padding: IpPortPadding) -> Result<(&'a mut [u8], usize), GenError> {
139 do_gen!(buf,
140 gen_cond!(self.protocol == ProtocolType::TCP, |buf| gen_error(buf, 0)) >>
141 gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf, padding), self)
142 )
143 }
144
145 pub fn to_tcp_bytes<'a>(&self, buf: (&'a mut [u8], usize), padding: IpPortPadding) -> Result<(&'a mut [u8], usize), GenError> {
147 do_gen!(buf,
148 gen_cond!(self.protocol == ProtocolType::UDP, |buf| gen_error(buf, 0)) >>
149 gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf, padding), self)
150 )
151 }
152
153 pub fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize), padding: IpPortPadding) -> Result<(&'a mut [u8], usize), GenError> {
155 do_gen!(buf,
156 gen_be_u8!(self.ip_type()) >>
157 gen_call!(|buf, ip_addr| IpAddr::to_bytes(ip_addr, buf), &self.ip_addr) >>
158 gen_cond!(padding == IpPortPadding::WithPadding && self.ip_addr.is_ipv4(), gen_slice!(&[0; IPV4_PADDING_SIZE])) >>
159 gen_be_u16!(self.port)
160 )
161 }
162
163 pub fn from_udp_saddr(saddr: SocketAddr) -> IpPort {
165 IpPort {
166 protocol: ProtocolType::UDP,
167 ip_addr: saddr.ip(),
168 port: saddr.port()
169 }
170 }
171
172 pub fn from_tcp_saddr(saddr: SocketAddr) -> IpPort {
174 IpPort {
175 protocol: ProtocolType::TCP,
176 ip_addr: saddr.ip(),
177 port: saddr.port()
178 }
179 }
180
181 pub fn to_saddr(&self) -> SocketAddr {
183 SocketAddr::new(self.ip_addr, self.port)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 macro_rules! ip_port_with_padding_encode_decode_test (
192 ($test:ident, $protocol:expr) => (
193 #[test]
194 fn $test() {
195 let value = IpPort {
196 protocol: $protocol,
197 ip_addr: "5.6.7.8".parse().unwrap(),
198 port: 12345
199 };
200 let mut buf = [0; SIZE_IPPORT];
201 let (_, size) = value.to_bytes((&mut buf, 0), IpPortPadding::WithPadding).unwrap();
202 assert_eq!(size, SIZE_IPPORT);
203 let (rest, decoded_value) = IpPort::from_bytes(&buf[..size], IpPortPadding::WithPadding).unwrap();
204 assert!(rest.is_empty());
205 assert_eq!(decoded_value, value);
206 }
207 )
208 );
209
210 ip_port_with_padding_encode_decode_test!(ip_port_udp_with_padding_encode_decode, ProtocolType::UDP);
211 ip_port_with_padding_encode_decode_test!(ip_port_tcp_with_padding_encode_decode, ProtocolType::TCP);
212
213 macro_rules! ip_port_without_padding_encode_decode_test (
214 ($test:ident, $protocol:expr) => (
215 #[test]
216 fn $test() {
217 let value = IpPort {
218 protocol: $protocol,
219 ip_addr: "5.6.7.8".parse().unwrap(),
220 port: 12345
221 };
222 let mut buf = [0; SIZE_IPPORT - IPV4_PADDING_SIZE];
223 let (_, size) = value.to_bytes((&mut buf, 0), IpPortPadding::NoPadding).unwrap();
224 assert_eq!(size, SIZE_IPPORT - IPV4_PADDING_SIZE);
225 let (rest, decoded_value) = IpPort::from_bytes(&buf[..size], IpPortPadding::NoPadding).unwrap();
226 assert!(rest.is_empty());
227 assert_eq!(decoded_value, value);
228 }
229 )
230 );
231
232 ip_port_without_padding_encode_decode_test!(ip_port_udp_without_padding_encode_decode, ProtocolType::UDP);
233 ip_port_without_padding_encode_decode_test!(ip_port_tcp_without_padding_encode_decode, ProtocolType::TCP);
234
235 #[test]
236 fn ip_port_from_to_udp_saddr() {
237 let ip_port_1 = IpPort {
238 protocol: ProtocolType::UDP,
239 ip_addr: "5.6.7.8".parse().unwrap(),
240 port: 12345
241 };
242 let ip_port_2 = IpPort::from_udp_saddr(ip_port_1.to_saddr());
243 assert_eq!(ip_port_2, ip_port_1);
244 }
245
246 #[test]
247 fn ip_port_from_to_tcp_saddr() {
248 let ip_port_1 = IpPort {
249 protocol: ProtocolType::TCP,
250 ip_addr: "5.6.7.8".parse().unwrap(),
251 port: 12345
252 };
253 let ip_port_2 = IpPort::from_tcp_saddr(ip_port_1.to_saddr());
254 assert_eq!(ip_port_2, ip_port_1);
255 }
256}