Mercurial > crates > systemd-socket
annotate src/resolv_addr.rs @ 4:66c0e10c89fc
Support resolving hostnames
Until now the crate supported only IP addresses and systemd sockets.
This was troublesome because it prevented the popular `localhost:1234`
format. This commit changes the behavior so that if parsing of
`std::net::SocketAddr` fails it attempts to parse it as `hostname:port`.
`bind_*()` methods were also modified to be async because of this.
author | Martin Habovstiak <martin.habovstiak@gmail.com> |
---|---|
date | Fri, 27 Nov 2020 15:05:19 +0100 |
parents | |
children | cfef4593e207 |
rev | line source |
---|---|
4
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
1 use thiserror::Error; |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
2 use std::fmt; |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
3 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
4 #[derive(Debug, PartialEq)] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
5 pub(crate) struct ResolvAddr(String); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
6 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
7 impl ResolvAddr { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
8 pub(crate) fn as_str(&self) -> &str { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
9 &self.0 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
10 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
11 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
12 pub(crate) fn try_from_generic<T: std::ops::Deref<Target=str> + Into<String>>(string: T) -> Result<Self, ResolvAddrError> { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
13 // can't use a combinator due to borrowing |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
14 let colon = match string.rfind(':') { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
15 Some(colon) => colon, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
16 None => return Err(ResolvAddrError::MissingPort(string.into())), |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
17 }; |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
18 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
19 let (hostname, port) = string.split_at(colon); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
20 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
21 if let Err(error) = port[1..].parse::<u16>() { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
22 return Err(ResolvAddrError::InvalidPort { string: string.into(), error, }); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
23 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
24 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
25 let len = hostname.len(); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
26 if len > 253 { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
27 return Err(ResolvAddrError::TooLong { string: string.into(), len, } ) |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
28 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
29 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
30 let mut label_start = 0usize; |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
31 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
32 for (i, c) in hostname.chars().enumerate() { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
33 match c { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
34 '.' => { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
35 if i - label_start == 0 { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
36 return Err(ResolvAddrError::EmptyLabel { string: string.into(), label_start, }); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
37 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
38 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
39 label_start = i + 1; |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
40 }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
41 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' => (), |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
42 _ => return Err(ResolvAddrError::InvalidCharacter { string: string.into(), c, pos: i, }), |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
43 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
44 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
45 if i - label_start > 63 { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
46 return Err(ResolvAddrError::LongLabel { string: string.into(), label_start, label_end: i, }); |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
47 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
48 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
49 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
50 Ok(ResolvAddr(string.into())) |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
51 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
52 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
53 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
54 impl fmt::Display for ResolvAddr { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
56 fmt::Display::fmt(&self.0, f) |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
57 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
58 } |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
59 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
60 |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
61 #[derive(Debug, Error)] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
62 pub(crate) enum ResolvAddrError { |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
63 #[error("hostname {string} has {len} character which exceeds the limit of 253")] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
64 TooLong { string: String, len: usize }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
65 #[error("invalid character {c} in hostname {string} at position {pos}")] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
66 InvalidCharacter { string: String, pos: usize, c: char, }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
67 #[error("hostname {string} contains a label {} at position {label_start} which is {} characters long - more than the limit 63", &string[(*label_start)..(*label_end)], label_end - label_start)] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
68 LongLabel { string: String, label_start: usize, label_end: usize, }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
69 #[error("hostname {string} contains an empty label at position {label_start}")] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
70 EmptyLabel { string: String, label_start: usize, }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
71 #[error("the address {0} is missing a port")] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
72 MissingPort(String), |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
73 #[error("failed to parse port numer in the address {string}")] |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
74 InvalidPort { string: String, error: std::num::ParseIntError, }, |
66c0e10c89fc
Support resolving hostnames
Martin Habovstiak <martin.habovstiak@gmail.com>
parents:
diff
changeset
|
75 } |