mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
[Net] Non-blocking WebSocket hostname resolution.
Hostname is now resolved during poll in WebSocketClient (wslay) to avoid blocking during connect. An attempt is still made to find the hostname in the resolver cache.
This commit is contained in:
parent
3db1d689ce
commit
1ec96bc206
2 changed files with 56 additions and 21 deletions
|
@ -163,22 +163,24 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
|
||||||
_peer = Ref<WSLPeer>(memnew(WSLPeer));
|
_peer = Ref<WSLPeer>(memnew(WSLPeer));
|
||||||
|
|
||||||
if (p_host.is_valid_ip_address()) {
|
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 {
|
} else {
|
||||||
ip_candidates = IP::get_singleton()->resolve_hostname_addresses(p_host);
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND_V(ip_candidates.is_empty(), ERR_INVALID_PARAMETER);
|
// We assume OK while hostname resultion is pending.
|
||||||
|
Error err = _resolver_id != IP::RESOLVER_INVALID_ID ? OK : FAILED;
|
||||||
String port = "";
|
while (_ip_candidates.size()) {
|
||||||
if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) {
|
err = _tcp->connect_to_host(_ip_candidates.pop_front(), p_port);
|
||||||
port = ":" + itos(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) {
|
if (err == OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -200,8 +202,11 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
|
||||||
}
|
}
|
||||||
|
|
||||||
_key = WSLPeer::generate_key();
|
_key = WSLPeer::generate_key();
|
||||||
// TODO custom extra headers (allow overriding this too?)
|
|
||||||
String request = "GET " + p_path + " HTTP/1.1\r\n";
|
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 += "Host: " + p_host + port + "\r\n";
|
||||||
request += "Upgrade: websocket\r\n";
|
request += "Upgrade: websocket\r\n";
|
||||||
request += "Connection: Upgrade\r\n";
|
request += "Connection: Upgrade\r\n";
|
||||||
|
@ -231,6 +236,30 @@ int WSLClient::get_max_packet_size() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSLClient::poll() {
|
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()) {
|
if (_peer->is_connected_to_host()) {
|
||||||
_peer->poll();
|
_peer->poll();
|
||||||
if (!_peer->is_connected_to_host()) {
|
if (!_peer->is_connected_to_host()) {
|
||||||
|
@ -251,7 +280,7 @@ void WSLClient::poll() {
|
||||||
_on_error();
|
_on_error();
|
||||||
break;
|
break;
|
||||||
case StreamPeerTCP::STATUS_CONNECTED: {
|
case StreamPeerTCP::STATUS_CONNECTED: {
|
||||||
ip_candidates.clear();
|
_ip_candidates.clear();
|
||||||
Ref<StreamPeerSSL> ssl;
|
Ref<StreamPeerSSL> ssl;
|
||||||
if (_use_ssl) {
|
if (_use_ssl) {
|
||||||
if (_connection == _tcp) {
|
if (_connection == _tcp) {
|
||||||
|
@ -282,9 +311,9 @@ void WSLClient::poll() {
|
||||||
_do_handshake();
|
_do_handshake();
|
||||||
} break;
|
} break;
|
||||||
case StreamPeerTCP::STATUS_ERROR:
|
case StreamPeerTCP::STATUS_ERROR:
|
||||||
while (ip_candidates.size() > 0) {
|
while (_ip_candidates.size() > 0) {
|
||||||
_tcp->disconnect_from_host();
|
_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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +336,7 @@ MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
|
||||||
return CONNECTION_CONNECTED;
|
return CONNECTION_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tcp->is_connected_to_host()) {
|
if (_tcp->is_connected_to_host() || _resolver_id != IP::RESOLVER_INVALID_ID) {
|
||||||
return CONNECTION_CONNECTING;
|
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));
|
memset(_resp_buf, 0, sizeof(_resp_buf));
|
||||||
_resp_pos = 0;
|
_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 {
|
IPAddress WSLClient::get_connected_host() const {
|
||||||
|
|
|
@ -63,10 +63,11 @@ private:
|
||||||
|
|
||||||
String _key;
|
String _key;
|
||||||
String _host;
|
String _host;
|
||||||
int _port;
|
uint16_t _port;
|
||||||
Array ip_candidates;
|
Array _ip_candidates;
|
||||||
Vector<String> _protocols;
|
Vector<String> _protocols;
|
||||||
bool _use_ssl = false;
|
bool _use_ssl = false;
|
||||||
|
IP::ResolverID _resolver_id = IP::RESOLVER_INVALID_ID;
|
||||||
|
|
||||||
void _do_handshake();
|
void _do_handshake();
|
||||||
bool _verify_headers(String &r_protocol);
|
bool _verify_headers(String &r_protocol);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue