Skip to content

Commit c3976b3

Browse files
committed
feat(client): allow both IPv6 and IPv4 local addrs
Currently HttpConnector::set_local_address method accepts a single argument. Server might not support IPv6 or IPv4. Therefore, the only solution at the moment is to manually perform DNS resolution and pick appropriate local address family. This is inefficient, as leads to 2 DNS lookups per request. This commit allows specifying both IPv4 and IPv6, so connector can decide which one to use based on DNS resolution results. Closes: #2169 BREAKING CHANGE: `HttpConnector::set_local_address(&mut self, addr: Option<IpAddr>)` signature has been changed to `HttpConnector::set_local_address(&mut self, addr_ipv4: Option<Ipv4Addr>, addr_ipv6: Option<Ipv6Addr>)`
1 parent f329ae0 commit c3976b3

File tree

3 files changed

+188
-58
lines changed

3 files changed

+188
-58
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ net2 = { version = "0.2.32", optional = true }
4444
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
4545
matches = "0.1"
4646
num_cpus = "1.0"
47+
pnet = "0.25.0"
4748
pretty_env_logger = "0.4"
4849
spmc = "0.3"
4950
serde = "1.0"

src/client/connect/dns.rs

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -194,27 +194,33 @@ impl IpAddrs {
194194
None
195195
}
196196

197-
pub(super) fn split_by_preference(self, local_addr: Option<IpAddr>) -> (IpAddrs, IpAddrs) {
198-
if let Some(local_addr) = local_addr {
199-
let preferred = self
200-
.iter
201-
.filter(|addr| addr.is_ipv6() == local_addr.is_ipv6())
202-
.collect();
203-
204-
(IpAddrs::new(preferred), IpAddrs::new(vec![]))
205-
} else {
206-
let preferring_v6 = self
207-
.iter
208-
.as_slice()
209-
.first()
210-
.map(SocketAddr::is_ipv6)
211-
.unwrap_or(false);
212-
213-
let (preferred, fallback) = self
214-
.iter
215-
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
216-
217-
(IpAddrs::new(preferred), IpAddrs::new(fallback))
197+
#[inline]
198+
fn filter(self, predicate: impl FnMut(&SocketAddr) -> bool) -> IpAddrs {
199+
IpAddrs::new(self.iter.filter(predicate).collect())
200+
}
201+
202+
pub(super) fn split_by_preference(
203+
self,
204+
local_addr_ipv4: Option<Ipv4Addr>,
205+
local_addr_ipv6: Option<Ipv6Addr>,
206+
) -> (IpAddrs, IpAddrs) {
207+
match (local_addr_ipv4, local_addr_ipv6) {
208+
(Some(_), None) => (self.filter(SocketAddr::is_ipv4), IpAddrs::new(vec![])),
209+
(None, Some(_)) => (self.filter(SocketAddr::is_ipv6), IpAddrs::new(vec![])),
210+
_ => {
211+
let preferring_v6 = self
212+
.iter
213+
.as_slice()
214+
.first()
215+
.map(SocketAddr::is_ipv6)
216+
.unwrap_or(false);
217+
218+
let (preferred, fallback) = self
219+
.iter
220+
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
221+
222+
(IpAddrs::new(preferred), IpAddrs::new(fallback))
223+
}
218224
}
219225
}
220226

@@ -349,34 +355,50 @@ mod tests {
349355

350356
#[test]
351357
fn test_ip_addrs_split_by_preference() {
352-
let v4_addr = (Ipv4Addr::new(127, 0, 0, 1), 80).into();
353-
let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into();
358+
let ip_v4 = Ipv4Addr::new(127, 0, 0, 1);
359+
let ip_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
360+
let v4_addr = (ip_v4, 80).into();
361+
let v6_addr = (ip_v6, 80).into();
362+
363+
let (mut preferred, mut fallback) = IpAddrs {
364+
iter: vec![v4_addr, v6_addr].into_iter(),
365+
}
366+
.split_by_preference(None, None);
367+
assert!(preferred.next().unwrap().is_ipv4());
368+
assert!(fallback.next().unwrap().is_ipv6());
369+
370+
let (mut preferred, mut fallback) = IpAddrs {
371+
iter: vec![v6_addr, v4_addr].into_iter(),
372+
}
373+
.split_by_preference(None, None);
374+
assert!(preferred.next().unwrap().is_ipv6());
375+
assert!(fallback.next().unwrap().is_ipv4());
354376

355377
let (mut preferred, mut fallback) = IpAddrs {
356378
iter: vec![v4_addr, v6_addr].into_iter(),
357379
}
358-
.split_by_preference(None);
380+
.split_by_preference(Some(ip_v4), Some(ip_v6));
359381
assert!(preferred.next().unwrap().is_ipv4());
360382
assert!(fallback.next().unwrap().is_ipv6());
361383

362384
let (mut preferred, mut fallback) = IpAddrs {
363385
iter: vec![v6_addr, v4_addr].into_iter(),
364386
}
365-
.split_by_preference(None);
387+
.split_by_preference(Some(ip_v4), Some(ip_v6));
366388
assert!(preferred.next().unwrap().is_ipv6());
367389
assert!(fallback.next().unwrap().is_ipv4());
368390

369391
let (mut preferred, fallback) = IpAddrs {
370392
iter: vec![v4_addr, v6_addr].into_iter(),
371393
}
372-
.split_by_preference(Some(v4_addr.ip()));
394+
.split_by_preference(Some(ip_v4), None);
373395
assert!(preferred.next().unwrap().is_ipv4());
374396
assert!(fallback.is_empty());
375397

376398
let (mut preferred, fallback) = IpAddrs {
377399
iter: vec![v4_addr, v6_addr].into_iter(),
378400
}
379-
.split_by_preference(Some(v6_addr.ip()));
401+
.split_by_preference(None, Some(ip_v6));
380402
assert!(preferred.next().unwrap().is_ipv6());
381403
assert!(fallback.is_empty());
382404
}

0 commit comments

Comments
 (0)