diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 49be934fb..1069cb8cf 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -321,6 +321,13 @@ pub fn is_ip_str(id: &str) -> bool { is_ipv4_str(id) || is_ipv6_str(id) } +#[inline] +pub fn is_hostname_port_str(id: &str) -> bool { + regex::Regex::new(r"^[\-.0-9a-zA-Z]+:\d{1,5}$") + .unwrap() + .is_match(id) +} + #[cfg(test)] mod test_lib { use super::*; @@ -340,4 +347,19 @@ mod test_lib { assert_eq!(is_ipv6_str("[1:2::0]:"), false); assert_eq!(is_ipv6_str("1:2::0]:1"), false); } + #[test] + fn test_hostname_port() { + assert_eq!(is_ipv6_str("a:12"), true); + assert_eq!(is_ipv6_str("a.b.c:12"), true); + assert_eq!(is_ipv6_str("test.com:12"), true); + assert_eq!(is_ipv6_str("1.2.3:12"), true); + assert_eq!(is_ipv6_str("a.b.c:123456"), false); + // todo: should we also check for these edge case? + // out-of-range port + assert_eq!(is_ipv6_str("test.com:0"), true); + assert_eq!(is_ipv6_str("test.com:98989"), true); + // invalid hostname + assert_eq!(is_ipv6_str("---:12"), true); + assert_eq!(is_ipv6_str(".:12"), true); + } } diff --git a/src/client.rs b/src/client.rs index 8b2edbcda..f3cca9b36 100644 --- a/src/client.rs +++ b/src/client.rs @@ -181,6 +181,17 @@ impl Client { true, )); } + // Allow connect to {hostname}:{port} + if hbb_common.is_hostname_port_str(peer) { + return Ok(( + socket_client::connect_tcp( + peer, + RENDEZVOUS_TIMEOUT, + ) + .await?, + true, + )); + } let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await; let mut socket = socket_client::connect_tcp(&*rendezvous_server, RENDEZVOUS_TIMEOUT).await; debug_assert!(!servers.contains(&rendezvous_server));