diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 581362b51a03..e30b59a6fdb6 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -52,6 +52,8 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, conn_port = p_port; conn_host = p_host; + ip_candidates.clear(); + ssl = p_ssl; ssl_verify_host = p_verify_host; @@ -306,6 +308,7 @@ void HTTPClient::close() { resolving = IP::RESOLVER_INVALID_ID; } + ip_candidates.clear(); response_headers.clear(); response_str.clear(); body_size = -1; @@ -328,10 +331,17 @@ Error HTTPClient::poll() { return OK; // Still resolving case IP::RESOLVER_STATUS_DONE: { - IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving); - Error err = tcp_connection->connect_to_host(host, conn_port); + ip_candidates = IP::get_singleton()->get_resolve_item_addresses(resolving); IP::get_singleton()->erase_resolve_item(resolving); 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) { status = STATUS_CANT_CONNECT; return err; @@ -385,6 +395,7 @@ Error HTTPClient::poll() { if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { // Handshake has been successful handshaking = false; + ip_candidates.clear(); status = STATUS_CONNECTED; return OK; } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { @@ -395,15 +406,24 @@ Error HTTPClient::poll() { } // ... we will need to poll more for handshake to finish } else { + ip_candidates.clear(); status = STATUS_CONNECTED; } return OK; } break; case StreamPeerTCP::STATUS_ERROR: 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(); status = STATUS_CANT_CONNECT; - return ERR_CANT_CONNECT; + return err; } break; } } break; diff --git a/core/io/http_client.h b/core/io/http_client.h index 9a14d72bd614..47ad576f5d7d 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -159,6 +159,7 @@ class HTTPClient : public Reference { #ifndef JAVASCRIPT_ENABLED Status status; IP::ResolverID resolving; + Array ip_candidates; int conn_port; String conn_host; bool ssl; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 3125d5ab7f9b..415f49c29cf7 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -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.empty(), ERR_INVALID_PARAMETER); _peer = Ref(memnew(WSLPeer)); - IP_Address addr; - if (!p_host.is_valid_ip_address()) { - addr = IP::get_singleton()->resolve_hostname(p_host); + if (p_host.is_valid_ip_address()) { + ip_candidates.clear(); + ip_candidates.push_back(IP_Address(p_host)); } 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.empty(), ERR_INVALID_PARAMETER); String port = ""; if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) { 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) { _tcp->disconnect_from_host(); _on_error(); @@ -185,6 +191,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, _connection = _tcp; _use_ssl = p_ssl; _host = p_host; + _port = p_port; // Strip edges from protocols. _protocols.resize(p_protocols.size()); String *pw = _protocols.ptrw(); @@ -244,6 +251,7 @@ void WSLClient::poll() { _on_error(); break; case StreamPeerTCP::STATUS_CONNECTED: { + ip_candidates.clear(); Ref ssl; if (_use_ssl) { if (_connection == _tcp) { @@ -274,6 +282,12 @@ void WSLClient::poll() { _do_handshake(); } break; 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(); _on_error(); break; @@ -315,6 +329,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) { memset(_resp_buf, 0, sizeof(_resp_buf)); _resp_pos = 0; + + ip_candidates.clear(); } IP_Address WSLClient::get_connected_host() const { diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h index d453c880a493..93fe290b7568 100644 --- a/modules/websocket/wsl_client.h +++ b/modules/websocket/wsl_client.h @@ -63,6 +63,8 @@ class WSLClient : public WebSocketClient { String _key; String _host; + int _port; + Array ip_candidates; Vector _protocols; bool _use_ssl;