Merge pull request #32683 from Faless/ws/improve_pr
WebSocket improvements, SSL server, custom headers.
This commit is contained in:
commit
be446038bb
14 changed files with 181 additions and 38 deletions
|
@ -21,10 +21,13 @@
|
|||
</argument>
|
||||
<argument index="2" name="gd_mp_api" type="bool" default="false">
|
||||
</argument>
|
||||
<argument index="3" name="custom_headers" type="PoolStringArray" default="PoolStringArray( )">
|
||||
</argument>
|
||||
<description>
|
||||
Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested.
|
||||
If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
|
||||
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
|
||||
You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request (not supported in HTML5 platform).
|
||||
</description>
|
||||
</method>
|
||||
<method name="disconnect_from_host">
|
||||
|
@ -38,8 +41,25 @@
|
|||
Disconnects this client from the connected host. See [method WebSocketPeer.close] for more information.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_connected_host" qualifiers="const">
|
||||
<return type="String">
|
||||
</return>
|
||||
<description>
|
||||
Return the IP address of the currently connected host.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_connected_port" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Return the IP port of the currently connected host.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="trusted_ssl_certificate" type="X509Certificate" setter="set_trusted_ssl_certificate" getter="get_trusted_ssl_certificate">
|
||||
If specified, this [X509Certificate] will be the only one accepted when connecting to an SSL host. Any other certificate provided by the server will be regarded as invalid.
|
||||
</member>
|
||||
<member name="verify_ssl" type="bool" setter="set_verify_ssl_enabled" getter="is_verify_ssl_enabled">
|
||||
If [code]true[/code], SSL certificate verification is enabled.
|
||||
[b]Note:[/b] You must specify the certificates to be used in the Project Settings for it to work when exported.
|
||||
|
|
|
@ -82,6 +82,17 @@
|
|||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain">
|
||||
When using SSL (see [member private_key] and [member ssl_certificate]), you can set this to a valid [X509Certificate] to be provided as additional CA chain information during the SSL handshake.
|
||||
</member>
|
||||
<member name="private_key" type="CryptoKey" setter="set_private_key" getter="get_private_key">
|
||||
When set to a valid [CryptoKey] (along with [member ssl_certificate]) will cause the server to require SSL instead of regular TCP (i.e. the `wss://` protocol).
|
||||
</member>
|
||||
<member name="ssl_certificate" type="X509Certificate" setter="set_ssl_certificate" getter="get_ssl_certificate">
|
||||
When set to a valid [X509Certificate] (along with [member private_key]) will cause the server to require SSL instead of regular TCP (i.e. the `wss://` protocol).
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="client_close_request">
|
||||
<argument index="0" name="id" type="int">
|
||||
|
|
|
@ -64,13 +64,20 @@ EMSCRIPTEN_KEEPALIVE void _esws_on_close(void *obj, int code, char *reason, int
|
|||
}
|
||||
}
|
||||
|
||||
Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
|
||||
Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const PoolVector<String> p_protocols, const Vector<String> p_custom_headers) {
|
||||
|
||||
String proto_string = p_protocols.join(",");
|
||||
String str = "ws://";
|
||||
|
||||
if (p_ssl)
|
||||
if (p_custom_headers.size()) {
|
||||
WARN_PRINT_ONCE("Custom headers are not supported in in HTML5 platform.");
|
||||
}
|
||||
if (p_ssl) {
|
||||
str = "wss://";
|
||||
if (ssl_cert.is_valid()) {
|
||||
WARN_PRINT_ONCE("Custom SSL certificate is not supported in HTML5 platform.");
|
||||
}
|
||||
}
|
||||
str += p_host + ":" + itos(p_port) + p_path;
|
||||
|
||||
_is_connecting = true;
|
||||
|
@ -193,12 +200,12 @@ void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
|
|||
|
||||
IP_Address EMWSClient::get_connected_host() const {
|
||||
|
||||
return IP_Address();
|
||||
ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
|
||||
};
|
||||
|
||||
uint16_t EMWSClient::get_connected_port() const {
|
||||
|
||||
return 1025;
|
||||
ERR_FAIL_V_MSG(0, "Not supported in HTML5 export.");
|
||||
};
|
||||
|
||||
int EMWSClient::get_max_packet_size() const {
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
bool _is_connecting;
|
||||
|
||||
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
|
||||
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
|
||||
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const PoolVector<String> p_protocol = PoolVector<String>(), const Dictionary p_custom_headers = Dictionary());
|
||||
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
|
||||
void disconnect_from_host(int p_code = 1000, String p_reason = "");
|
||||
IP_Address get_connected_host() const;
|
||||
|
|
|
@ -40,7 +40,7 @@ WebSocketClient::WebSocketClient() {
|
|||
WebSocketClient::~WebSocketClient() {
|
||||
}
|
||||
|
||||
Error WebSocketClient::connect_to_url(String p_url, PoolVector<String> p_protocols, bool gd_mp_api) {
|
||||
Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_protocols, bool gd_mp_api, const Vector<String> p_custom_headers) {
|
||||
_is_multiplayer = gd_mp_api;
|
||||
|
||||
String host = p_url;
|
||||
|
@ -72,7 +72,7 @@ Error WebSocketClient::connect_to_url(String p_url, PoolVector<String> p_protoco
|
|||
host = host.substr(0, p_len);
|
||||
}
|
||||
|
||||
return connect_to_host(host, path, port, ssl, p_protocols);
|
||||
return connect_to_host(host, path, port, ssl, p_protocols, p_custom_headers);
|
||||
}
|
||||
|
||||
void WebSocketClient::set_verify_ssl_enabled(bool p_verify_ssl) {
|
||||
|
@ -85,6 +85,17 @@ bool WebSocketClient::is_verify_ssl_enabled() const {
|
|||
return verify_ssl;
|
||||
}
|
||||
|
||||
Ref<X509Certificate> WebSocketClient::get_trusted_ssl_certificate() const {
|
||||
|
||||
return ssl_cert;
|
||||
}
|
||||
|
||||
void WebSocketClient::set_trusted_ssl_certificate(Ref<X509Certificate> p_cert) {
|
||||
|
||||
ERR_FAIL_COND(get_connection_status() != CONNECTION_DISCONNECTED);
|
||||
ssl_cert = p_cert;
|
||||
}
|
||||
|
||||
bool WebSocketClient::is_server() const {
|
||||
|
||||
return false;
|
||||
|
@ -132,13 +143,20 @@ void WebSocketClient::_on_error() {
|
|||
}
|
||||
|
||||
void WebSocketClient::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("connect_to_url", "url", "protocols", "gd_mp_api"), &WebSocketClient::connect_to_url, DEFVAL(PoolVector<String>()), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("connect_to_url", "url", "protocols", "gd_mp_api", "custom_headers"), &WebSocketClient::connect_to_url, DEFVAL(Vector<String>()), DEFVAL(false), DEFVAL(Vector<String>()));
|
||||
ClassDB::bind_method(D_METHOD("disconnect_from_host", "code", "reason"), &WebSocketClient::disconnect_from_host, DEFVAL(1000), DEFVAL(""));
|
||||
ClassDB::bind_method(D_METHOD("get_connected_host"), &WebSocketClient::get_connected_host);
|
||||
ClassDB::bind_method(D_METHOD("get_connected_port"), &WebSocketClient::get_connected_port);
|
||||
ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_trusted_ssl_certificate"), &WebSocketClient::get_trusted_ssl_certificate);
|
||||
ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate"), &WebSocketClient::set_trusted_ssl_certificate);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_trusted_ssl_certificate", "get_trusted_ssl_certificate");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("data_received"));
|
||||
ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol")));
|
||||
ADD_SIGNAL(MethodInfo("server_close_request", PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason")));
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef WEBSOCKET_CLIENT_H
|
||||
#define WEBSOCKET_CLIENT_H
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/error_list.h"
|
||||
#include "websocket_multiplayer_peer.h"
|
||||
#include "websocket_peer.h"
|
||||
|
@ -43,17 +44,20 @@ class WebSocketClient : public WebSocketMultiplayerPeer {
|
|||
protected:
|
||||
Ref<WebSocketPeer> _peer;
|
||||
bool verify_ssl;
|
||||
Ref<X509Certificate> ssl_cert;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
Error connect_to_url(String p_url, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
|
||||
Error connect_to_url(String p_url, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false, const Vector<String> p_custom_headers = Vector<String>());
|
||||
|
||||
void set_verify_ssl_enabled(bool p_verify_ssl);
|
||||
bool is_verify_ssl_enabled() const;
|
||||
Ref<X509Certificate> get_trusted_ssl_certificate() const;
|
||||
void set_trusted_ssl_certificate(Ref<X509Certificate> p_cert);
|
||||
|
||||
virtual void poll() = 0;
|
||||
virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>()) = 0;
|
||||
virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) = 0;
|
||||
virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0;
|
||||
virtual IP_Address get_connected_host() const = 0;
|
||||
virtual uint16_t get_connected_port() const = 0;
|
||||
|
|
|
@ -42,19 +42,58 @@ WebSocketServer::~WebSocketServer() {
|
|||
void WebSocketServer::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening);
|
||||
ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(PoolVector<String>()), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(Vector<String>()), DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop);
|
||||
ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer);
|
||||
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketServer::get_peer_address);
|
||||
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketServer::get_peer_port);
|
||||
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL(""));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key);
|
||||
ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", 0), "set_private_key", "get_private_key");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_ssl_certificate"), &WebSocketServer::get_ssl_certificate);
|
||||
ClassDB::bind_method(D_METHOD("set_ssl_certificate"), &WebSocketServer::set_ssl_certificate);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ssl_certificate", "get_ssl_certificate");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_ca_chain"), &WebSocketServer::get_ca_chain);
|
||||
ClassDB::bind_method(D_METHOD("set_ca_chain"), &WebSocketServer::set_ca_chain);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ca_chain", "get_ca_chain");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason")));
|
||||
ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close")));
|
||||
ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "protocol")));
|
||||
ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
|
||||
}
|
||||
|
||||
Ref<CryptoKey> WebSocketServer::get_private_key() const {
|
||||
return private_key;
|
||||
}
|
||||
|
||||
void WebSocketServer::set_private_key(Ref<CryptoKey> p_key) {
|
||||
ERR_FAIL_COND(is_listening());
|
||||
private_key = p_key;
|
||||
}
|
||||
|
||||
Ref<X509Certificate> WebSocketServer::get_ssl_certificate() const {
|
||||
return ssl_cert;
|
||||
}
|
||||
|
||||
void WebSocketServer::set_ssl_certificate(Ref<X509Certificate> p_cert) {
|
||||
ERR_FAIL_COND(is_listening());
|
||||
ssl_cert = p_cert;
|
||||
}
|
||||
|
||||
Ref<X509Certificate> WebSocketServer::get_ca_chain() const {
|
||||
return ca_chain;
|
||||
}
|
||||
|
||||
void WebSocketServer::set_ca_chain(Ref<X509Certificate> p_ca_chain) {
|
||||
ERR_FAIL_COND(is_listening());
|
||||
ca_chain = p_ca_chain;
|
||||
}
|
||||
|
||||
NetworkedMultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const {
|
||||
if (is_listening())
|
||||
return CONNECTION_CONNECTED;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef WEBSOCKET_H
|
||||
#define WEBSOCKET_H
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/reference.h"
|
||||
#include "websocket_multiplayer_peer.h"
|
||||
#include "websocket_peer.h"
|
||||
|
@ -43,9 +44,13 @@ class WebSocketServer : public WebSocketMultiplayerPeer {
|
|||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
Ref<CryptoKey> private_key;
|
||||
Ref<X509Certificate> ssl_cert;
|
||||
Ref<X509Certificate> ca_chain;
|
||||
|
||||
public:
|
||||
virtual void poll() = 0;
|
||||
virtual Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false) = 0;
|
||||
virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool is_listening() const = 0;
|
||||
virtual bool has_peer(int p_id) const = 0;
|
||||
|
@ -62,6 +67,15 @@ public:
|
|||
void _on_disconnect(int32_t p_peer_id, bool p_was_clean);
|
||||
void _on_close_request(int32_t p_peer_id, int p_code, String p_reason);
|
||||
|
||||
Ref<CryptoKey> get_private_key() const;
|
||||
void set_private_key(Ref<CryptoKey> p_key);
|
||||
|
||||
Ref<X509Certificate> get_ssl_certificate() const;
|
||||
void set_ssl_certificate(Ref<X509Certificate> p_cert);
|
||||
|
||||
Ref<X509Certificate> get_ca_chain() const;
|
||||
void set_ca_chain(Ref<X509Certificate> p_ca_chain);
|
||||
|
||||
virtual Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) = 0;
|
||||
|
||||
WebSocketServer();
|
||||
|
|
|
@ -86,6 +86,7 @@ void WSLClient::_do_handshake() {
|
|||
WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
|
||||
data->obj = this;
|
||||
data->conn = _connection;
|
||||
data->tcp = _tcp;
|
||||
data->is_server = false;
|
||||
data->id = 1;
|
||||
_peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
|
||||
|
@ -151,7 +152,7 @@ bool WSLClient::_verify_headers(String &r_protocol) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
|
||||
Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocols, const Vector<String> p_custom_headers) {
|
||||
|
||||
ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE);
|
||||
|
||||
|
@ -180,7 +181,8 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
|
|||
_connection = _tcp;
|
||||
_use_ssl = p_ssl;
|
||||
_host = p_host;
|
||||
_protocols = p_protocols;
|
||||
_protocols.clear();
|
||||
_protocols.append_array(p_protocols);
|
||||
|
||||
_key = WSLPeer::generate_key();
|
||||
// TODO custom extra headers (allow overriding this too?)
|
||||
|
@ -199,6 +201,9 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
|
|||
}
|
||||
request += "\r\n";
|
||||
}
|
||||
for (int i = 0; i < p_custom_headers.size(); i++) {
|
||||
request += p_custom_headers[i] + "\r\n";
|
||||
}
|
||||
request += "\r\n";
|
||||
_request = request.utf8();
|
||||
|
||||
|
@ -236,7 +241,7 @@ void WSLClient::poll() {
|
|||
ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
|
||||
ERR_FAIL_COND_MSG(ssl.is_null(), "SSL is not available in this build.");
|
||||
ssl->set_blocking_handshake_enabled(false);
|
||||
if (ssl->connect_to_stream(_tcp, verify_ssl, _host) != OK) {
|
||||
if (ssl->connect_to_stream(_tcp, verify_ssl, _host, ssl_cert) != OK) {
|
||||
disconnect_from_host();
|
||||
_on_error();
|
||||
return;
|
||||
|
@ -293,7 +298,7 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
|
|||
|
||||
_key = "";
|
||||
_host = "";
|
||||
_protocols.resize(0);
|
||||
_protocols.clear();
|
||||
_use_ssl = false;
|
||||
|
||||
_request = "";
|
||||
|
@ -305,12 +310,14 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
|
|||
|
||||
IP_Address WSLClient::get_connected_host() const {
|
||||
|
||||
return IP_Address();
|
||||
ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IP_Address());
|
||||
return _peer->get_connected_host();
|
||||
}
|
||||
|
||||
uint16_t WSLClient::get_connected_port() const {
|
||||
|
||||
return 1025;
|
||||
ERR_FAIL_COND_V(!_peer->is_connected_to_host(), 0);
|
||||
return _peer->get_connected_port();
|
||||
}
|
||||
|
||||
Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
|
||||
|
|
|
@ -64,7 +64,7 @@ private:
|
|||
|
||||
String _key;
|
||||
String _host;
|
||||
PoolVector<String> _protocols;
|
||||
Vector<String> _protocols;
|
||||
bool _use_ssl;
|
||||
|
||||
void _do_handshake();
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
|
||||
public:
|
||||
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
|
||||
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>());
|
||||
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
|
||||
int get_max_packet_size() const;
|
||||
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
|
||||
void disconnect_from_host(int p_code = 1000, String p_reason = "");
|
||||
|
|
|
@ -208,7 +208,6 @@ void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigne
|
|||
_data = p_data;
|
||||
_data->peer = this;
|
||||
_data->valid = true;
|
||||
_connection = Ref<StreamPeer>(_data->conn);
|
||||
|
||||
if (_data->is_server)
|
||||
wslay_event_context_server_init(&(_data->ctx), &wsl_callbacks, _data);
|
||||
|
@ -302,18 +301,16 @@ void WSLPeer::close(int p_code, String p_reason) {
|
|||
|
||||
IP_Address WSLPeer::get_connected_host() const {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), IP_Address());
|
||||
ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IP_Address());
|
||||
|
||||
IP_Address ip;
|
||||
return ip;
|
||||
return _data->tcp->get_connected_host();
|
||||
}
|
||||
|
||||
uint16_t WSLPeer::get_connected_port() const {
|
||||
|
||||
ERR_FAIL_COND_V(!is_connected_to_host(), 0);
|
||||
ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), 0);
|
||||
|
||||
uint16_t port = 0;
|
||||
return port;
|
||||
return _data->tcp->get_connected_port();
|
||||
}
|
||||
|
||||
void WSLPeer::invalidate() {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "core/error_list.h"
|
||||
#include "core/io/packet_peer.h"
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
#include "core/ring_buffer.h"
|
||||
#include "packet_buffer.h"
|
||||
#include "websocket_peer.h"
|
||||
|
@ -55,6 +56,7 @@ public:
|
|||
void *obj;
|
||||
void *peer;
|
||||
Ref<StreamPeer> conn;
|
||||
Ref<StreamPeerTCP> tcp;
|
||||
int id;
|
||||
wslay_event_context_ptr ctx;
|
||||
|
||||
|
@ -77,7 +79,6 @@ private:
|
|||
static bool _wsl_poll(struct PeerData *p_data);
|
||||
static void _wsl_destroy(struct PeerData **p_data);
|
||||
|
||||
Ref<StreamPeer> _connection;
|
||||
struct PeerData *_data;
|
||||
uint8_t _is_string;
|
||||
// Our packet info is just a boolean (is_string), using uint8_t for it.
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "core/project_settings.h"
|
||||
|
||||
WSLServer::PendingPeer::PendingPeer() {
|
||||
use_ssl = false;
|
||||
time = 0;
|
||||
has_request = false;
|
||||
response_sent = 0;
|
||||
|
@ -42,7 +43,7 @@ WSLServer::PendingPeer::PendingPeer() {
|
|||
memset(req_buf, 0, sizeof(req_buf));
|
||||
}
|
||||
|
||||
bool WSLServer::PendingPeer::_parse_request(const PoolStringArray p_protocols) {
|
||||
bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols) {
|
||||
Vector<String> psa = String((char *)req_buf).split("\r\n");
|
||||
int len = psa.size();
|
||||
ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
|
||||
|
@ -97,9 +98,19 @@ bool WSLServer::PendingPeer::_parse_request(const PoolStringArray p_protocols) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Error WSLServer::PendingPeer::do_handshake(PoolStringArray p_protocols) {
|
||||
Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) {
|
||||
if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT)
|
||||
return ERR_TIMEOUT;
|
||||
if (use_ssl) {
|
||||
Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL> >(connection);
|
||||
if (ssl.is_null())
|
||||
return FAILED;
|
||||
ssl->poll();
|
||||
if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING)
|
||||
return ERR_BUSY;
|
||||
else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED)
|
||||
return FAILED;
|
||||
}
|
||||
if (!has_request) {
|
||||
int read = 0;
|
||||
while (true) {
|
||||
|
@ -143,11 +154,11 @@ Error WSLServer::PendingPeer::do_handshake(PoolStringArray p_protocols) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error WSLServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_api) {
|
||||
Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp_api) {
|
||||
ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE);
|
||||
|
||||
_is_multiplayer = gd_mp_api;
|
||||
_protocols = p_protocols;
|
||||
_protocols.append_array(p_protocols);
|
||||
_server->listen(p_port);
|
||||
|
||||
return OK;
|
||||
|
@ -185,6 +196,7 @@ void WSLServer::poll() {
|
|||
WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
|
||||
data->obj = this;
|
||||
data->conn = ppeer->connection;
|
||||
data->tcp = ppeer->tcp;
|
||||
data->is_server = true;
|
||||
data->id = id;
|
||||
|
||||
|
@ -204,12 +216,21 @@ void WSLServer::poll() {
|
|||
return;
|
||||
|
||||
while (_server->is_connection_available()) {
|
||||
Ref<StreamPeer> conn = _server->take_connection();
|
||||
Ref<StreamPeerTCP> conn = _server->take_connection();
|
||||
if (is_refusing_new_connections())
|
||||
continue; // Conn will go out-of-scope and be closed.
|
||||
|
||||
Ref<PendingPeer> peer = memnew(PendingPeer);
|
||||
peer->connection = conn;
|
||||
if (private_key.is_valid() && ssl_cert.is_valid()) {
|
||||
Ref<StreamPeerSSL> ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
|
||||
ssl->set_blocking_handshake_enabled(false);
|
||||
ssl->accept_stream(conn, private_key, ssl_cert, ca_chain);
|
||||
peer->connection = ssl;
|
||||
peer->use_ssl = true;
|
||||
} else {
|
||||
peer->connection = conn;
|
||||
}
|
||||
peer->tcp = conn;
|
||||
peer->time = OS::get_singleton()->get_ticks_msec();
|
||||
_pending.push_back(peer);
|
||||
}
|
||||
|
@ -231,6 +252,7 @@ void WSLServer::stop() {
|
|||
}
|
||||
_pending.clear();
|
||||
_peer_map.clear();
|
||||
_protocols.clear();
|
||||
}
|
||||
|
||||
bool WSLServer::has_peer(int p_id) const {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "websocket_server.h"
|
||||
#include "wsl_peer.h"
|
||||
|
||||
#include "core/io/stream_peer_ssl.h"
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
#include "core/io/tcp_server.h"
|
||||
|
||||
|
@ -49,10 +50,12 @@ private:
|
|||
class PendingPeer : public Reference {
|
||||
|
||||
private:
|
||||
bool _parse_request(const PoolStringArray p_protocols);
|
||||
bool _parse_request(const Vector<String> p_protocols);
|
||||
|
||||
public:
|
||||
Ref<StreamPeerTCP> tcp;
|
||||
Ref<StreamPeer> connection;
|
||||
bool use_ssl;
|
||||
|
||||
int time;
|
||||
uint8_t req_buf[WSL_MAX_HEADER_SIZE];
|
||||
|
@ -65,7 +68,7 @@ private:
|
|||
|
||||
PendingPeer();
|
||||
|
||||
Error do_handshake(const PoolStringArray p_protocols);
|
||||
Error do_handshake(const Vector<String> p_protocols);
|
||||
};
|
||||
|
||||
int _in_buf_size;
|
||||
|
@ -75,11 +78,11 @@ private:
|
|||
|
||||
List<Ref<PendingPeer> > _pending;
|
||||
Ref<TCP_Server> _server;
|
||||
PoolStringArray _protocols;
|
||||
Vector<String> _protocols;
|
||||
|
||||
public:
|
||||
Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
|
||||
Error listen(int p_port, PoolVector<String> p_protocols = PoolVector<String>(), bool gd_mp_api = false);
|
||||
Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false);
|
||||
void stop();
|
||||
bool is_listening() const;
|
||||
int get_max_packet_size() const;
|
||||
|
|
Loading…
Reference in a new issue