diff --git a/src/stream.rs b/src/stream.rs index fefae7e..8ac4d9b 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -178,7 +178,7 @@ pub(crate) fn connect_https(unit: &Unit) -> Result { pub(crate) fn connect_host(unit: &Unit, hostname: &str, port: u16) -> Result { // - let ips: Vec = match unit.proxy { + let sock_addrs: Vec = match unit.proxy { Some(ref proxy) => format!("{}:{}", proxy.server, proxy.port), None => format!("{}:{}", hostname, port), } @@ -186,38 +186,54 @@ pub(crate) fn connect_host(unit: &Unit, hostname: &str, port: u16) -> Result TcpStream::connect(&sock_addr), - _ => TcpStream::connect_timeout( - &sock_addr, - Duration::from_millis(unit.timeout_connect as u64), - ), + // Find the first sock_addr that accepts a connection + for sock_addr in sock_addrs { + // connect with a configured timeout. + let stream = if Some(Proto::SOCKS5) == proto { + connect_socks5( + unit.proxy.to_owned().unwrap(), + unit.timeout_connect, + sock_addr, + hostname, + port, + ) + } else { + match unit.timeout_connect { + 0 => TcpStream::connect(&sock_addr), + _ => TcpStream::connect_timeout( + &sock_addr, + Duration::from_millis(unit.timeout_connect as u64), + ), + } + }; + + if let Ok(stream) = stream { + any_stream = Some(stream); + break; + } else if let Err(err) = stream { + any_err = Some(err); } } - .map_err(|err| Error::ConnectionFailed(format!("{}", err)))?; + + let mut stream = if let Some(stream) = any_stream { + stream + } else { + let err = if let Some(err) = any_err { + Error::ConnectionFailed(format!("{}", err)) + } else { + Error::DnsFailed(format!("No ip address for {}", hostname)) + }; + return Err(err); + }; // rust's absurd api returns Err if we set 0. // Setting it to None will disable the native system timeout