Try other resolved IPs if one fails to connect

This commit is contained in:
Haoyu Qiu 2021-07-11 17:43:52 +08:00
parent 9d38ebdc3c
commit fd52e18d19
4 changed files with 48 additions and 9 deletions

View File

@ -45,6 +45,8 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
conn_port = p_port; conn_port = p_port;
conn_host = p_host; conn_host = p_host;
ip_candidates.clear();
ssl = p_ssl; ssl = p_ssl;
ssl_verify_host = p_verify_host; ssl_verify_host = p_verify_host;
@ -234,6 +236,7 @@ void HTTPClientTCP::close() {
resolving = IP::RESOLVER_INVALID_ID; resolving = IP::RESOLVER_INVALID_ID;
} }
ip_candidates.clear();
response_headers.clear(); response_headers.clear();
response_str.clear(); response_str.clear();
body_size = -1; body_size = -1;
@ -256,10 +259,17 @@ Error HTTPClientTCP::poll() {
return OK; // Still resolving return OK; // Still resolving
case IP::RESOLVER_STATUS_DONE: { case IP::RESOLVER_STATUS_DONE: {
IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving); ip_candidates = IP::get_singleton()->get_resolve_item_addresses(resolving);
Error err = tcp_connection->connect_to_host(host, conn_port);
IP::get_singleton()->erase_resolve_item(resolving); IP::get_singleton()->erase_resolve_item(resolving);
resolving = IP::RESOLVER_INVALID_ID; resolving = IP::RESOLVER_INVALID_ID;
Error err = ERR_BUG; // Should be at least one entry.
while (ip_candidates.size() > 0) {
err = tcp_connection->connect_to_host(ip_candidates.front(), conn_port);
if (err == OK) {
break;
}
}
if (err) { if (err) {
status = STATUS_CANT_CONNECT; status = STATUS_CANT_CONNECT;
return err; return err;
@ -313,6 +323,7 @@ Error HTTPClientTCP::poll() {
if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
// Handshake has been successful // Handshake has been successful
handshaking = false; handshaking = false;
ip_candidates.clear();
status = STATUS_CONNECTED; status = STATUS_CONNECTED;
return OK; return OK;
} else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
@ -323,15 +334,24 @@ Error HTTPClientTCP::poll() {
} }
// ... we will need to poll more for handshake to finish // ... we will need to poll more for handshake to finish
} else { } else {
ip_candidates.clear();
status = STATUS_CONNECTED; status = STATUS_CONNECTED;
} }
return OK; return OK;
} break; } break;
case StreamPeerTCP::STATUS_ERROR: case StreamPeerTCP::STATUS_ERROR:
case StreamPeerTCP::STATUS_NONE: { case StreamPeerTCP::STATUS_NONE: {
Error err = ERR_CANT_CONNECT;
while (ip_candidates.size() > 0) {
tcp_connection->disconnect_from_host();
err = tcp_connection->connect_to_host(ip_candidates.pop_front(), conn_port);
if (err == OK) {
return OK;
}
}
close(); close();
status = STATUS_CANT_CONNECT; status = STATUS_CANT_CONNECT;
return ERR_CANT_CONNECT; return err;
} break; } break;
} }
} break; } break;

View File

@ -37,6 +37,7 @@ class HTTPClientTCP : public HTTPClient {
private: private:
Status status = STATUS_DISCONNECTED; Status status = STATUS_DISCONNECTED;
IP::ResolverID resolving = IP::RESOLVER_INVALID_ID; IP::ResolverID resolving = IP::RESOLVER_INVALID_ID;
Array ip_candidates;
int conn_port = -1; int conn_port = -1;
String conn_host; String conn_host;
bool ssl = false; bool ssl = false;

View File

@ -161,22 +161,28 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
_peer = Ref<WSLPeer>(memnew(WSLPeer)); _peer = Ref<WSLPeer>(memnew(WSLPeer));
IPAddress addr;
if (!p_host.is_valid_ip_address()) { if (p_host.is_valid_ip_address()) {
addr = IP::get_singleton()->resolve_hostname(p_host); ip_candidates.clear();
ip_candidates.push_back(IPAddress(p_host));
} else { } else {
addr = p_host; ip_candidates = IP::get_singleton()->resolve_hostname_addresses(p_host);
} }
ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(ip_candidates.is_empty(), ERR_INVALID_PARAMETER);
String port = ""; String port = "";
if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) { if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) {
port = ":" + itos(p_port); port = ":" + itos(p_port);
} }
Error err = _tcp->connect_to_host(addr, p_port); Error err = ERR_BUG; // Should be at least one entry.
while (ip_candidates.size() > 0) {
err = _tcp->connect_to_host(ip_candidates.pop_front(), p_port);
if (err == OK) {
break;
}
}
if (err != OK) { if (err != OK) {
_tcp->disconnect_from_host(); _tcp->disconnect_from_host();
_on_error(); _on_error();
@ -185,6 +191,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
_connection = _tcp; _connection = _tcp;
_use_ssl = p_ssl; _use_ssl = p_ssl;
_host = p_host; _host = p_host;
_port = p_port;
// Strip edges from protocols. // Strip edges from protocols.
_protocols.resize(p_protocols.size()); _protocols.resize(p_protocols.size());
String *pw = _protocols.ptrw(); String *pw = _protocols.ptrw();
@ -244,6 +251,7 @@ void WSLClient::poll() {
_on_error(); _on_error();
break; break;
case StreamPeerTCP::STATUS_CONNECTED: { case StreamPeerTCP::STATUS_CONNECTED: {
ip_candidates.clear();
Ref<StreamPeerSSL> ssl; Ref<StreamPeerSSL> ssl;
if (_use_ssl) { if (_use_ssl) {
if (_connection == _tcp) { if (_connection == _tcp) {
@ -274,6 +282,12 @@ void WSLClient::poll() {
_do_handshake(); _do_handshake();
} break; } break;
case StreamPeerTCP::STATUS_ERROR: case StreamPeerTCP::STATUS_ERROR:
while (ip_candidates.size() > 0) {
_tcp->disconnect_from_host();
if (_tcp->connect_to_host(ip_candidates.pop_front(), _port) == OK) {
return;
}
}
disconnect_from_host(); disconnect_from_host();
_on_error(); _on_error();
break; break;
@ -315,6 +329,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
memset(_resp_buf, 0, sizeof(_resp_buf)); memset(_resp_buf, 0, sizeof(_resp_buf));
_resp_pos = 0; _resp_pos = 0;
ip_candidates.clear();
} }
IPAddress WSLClient::get_connected_host() const { IPAddress WSLClient::get_connected_host() const {

View File

@ -63,6 +63,8 @@ private:
String _key; String _key;
String _host; String _host;
int _port;
Array ip_candidates;
Vector<String> _protocols; Vector<String> _protocols;
bool _use_ssl = false; bool _use_ssl = false;