summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/websocket/wsl_client.cpp72
-rw-r--r--modules/websocket/wsl_client.h5
2 files changed, 56 insertions, 21 deletions
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index be1c75c354..bebb198126 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -163,22 +163,24 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
_peer = Ref<WSLPeer>(memnew(WSLPeer));
if (p_host.is_valid_ip_address()) {
- ip_candidates.clear();
- ip_candidates.push_back(IPAddress(p_host));
+ _ip_candidates.push_back(IPAddress(p_host));
} else {
- ip_candidates = IP::get_singleton()->resolve_hostname_addresses(p_host);
- }
-
- ERR_FAIL_COND_V(ip_candidates.is_empty(), ERR_INVALID_PARAMETER);
-
- String port = "";
- if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) {
- port = ":" + itos(p_port);
+ // Queue hostname for resolution.
+ _resolver_id = IP::get_singleton()->resolve_hostname_queue_item(p_host);
+ ERR_FAIL_COND_V(_resolver_id == IP::RESOLVER_INVALID_ID, ERR_INVALID_PARAMETER);
+ // Check if it was found in cache.
+ IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id);
+ if (ip_status == IP::RESOLVER_STATUS_DONE) {
+ _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id);
+ IP::get_singleton()->erase_resolve_item(_resolver_id);
+ _resolver_id = IP::RESOLVER_INVALID_ID;
+ }
}
- 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);
+ // We assume OK while hostname resultion is pending.
+ Error err = _resolver_id != IP::RESOLVER_INVALID_ID ? OK : FAILED;
+ while (_ip_candidates.size()) {
+ err = _tcp->connect_to_host(_ip_candidates.pop_front(), p_port);
if (err == OK) {
break;
}
@@ -200,8 +202,11 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
}
_key = WSLPeer::generate_key();
- // TODO custom extra headers (allow overriding this too?)
String request = "GET " + p_path + " HTTP/1.1\r\n";
+ String port = "";
+ if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) {
+ port = ":" + itos(p_port);
+ }
request += "Host: " + p_host + port + "\r\n";
request += "Upgrade: websocket\r\n";
request += "Connection: Upgrade\r\n";
@@ -231,6 +236,30 @@ int WSLClient::get_max_packet_size() const {
}
void WSLClient::poll() {
+ if (_resolver_id != IP::RESOLVER_INVALID_ID) {
+ IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id);
+ if (ip_status == IP::RESOLVER_STATUS_WAITING) {
+ return;
+ }
+ // Anything else is either a candidate or a failure.
+ Error err = FAILED;
+ if (ip_status == IP::RESOLVER_STATUS_DONE) {
+ _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id);
+ while (_ip_candidates.size()) {
+ err = _tcp->connect_to_host(_ip_candidates.pop_front(), _port);
+ if (err == OK) {
+ break;
+ }
+ }
+ }
+ IP::get_singleton()->erase_resolve_item(_resolver_id);
+ _resolver_id = IP::RESOLVER_INVALID_ID;
+ if (err != OK) {
+ disconnect_from_host();
+ _on_error();
+ return;
+ }
+ }
if (_peer->is_connected_to_host()) {
_peer->poll();
if (!_peer->is_connected_to_host()) {
@@ -251,7 +280,7 @@ void WSLClient::poll() {
_on_error();
break;
case StreamPeerTCP::STATUS_CONNECTED: {
- ip_candidates.clear();
+ _ip_candidates.clear();
Ref<StreamPeerSSL> ssl;
if (_use_ssl) {
if (_connection == _tcp) {
@@ -282,9 +311,9 @@ void WSLClient::poll() {
_do_handshake();
} break;
case StreamPeerTCP::STATUS_ERROR:
- while (ip_candidates.size() > 0) {
+ while (_ip_candidates.size() > 0) {
_tcp->disconnect_from_host();
- if (_tcp->connect_to_host(ip_candidates.pop_front(), _port) == OK) {
+ if (_tcp->connect_to_host(_ip_candidates.pop_front(), _port) == OK) {
return;
}
}
@@ -307,7 +336,7 @@ MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
return CONNECTION_CONNECTED;
}
- if (_tcp->is_connected_to_host()) {
+ if (_tcp->is_connected_to_host() || _resolver_id != IP::RESOLVER_INVALID_ID) {
return CONNECTION_CONNECTING;
}
@@ -330,7 +359,12 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
memset(_resp_buf, 0, sizeof(_resp_buf));
_resp_pos = 0;
- ip_candidates.clear();
+ if (_resolver_id != IP::RESOLVER_INVALID_ID) {
+ IP::get_singleton()->erase_resolve_item(_resolver_id);
+ _resolver_id = IP::RESOLVER_INVALID_ID;
+ }
+
+ _ip_candidates.clear();
}
IPAddress WSLClient::get_connected_host() const {
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index 4839d7ab9b..d846e6be00 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -63,10 +63,11 @@ private:
String _key;
String _host;
- int _port;
- Array ip_candidates;
+ uint16_t _port;
+ Array _ip_candidates;
Vector<String> _protocols;
bool _use_ssl = false;
+ IP::ResolverID _resolver_id = IP::RESOLVER_INVALID_ID;
void _do_handshake();
bool _verify_headers(String &r_protocol);