summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2019-10-11 08:28:47 +0200
committerGitHub <noreply@github.com>2019-10-11 08:28:47 +0200
commitbe446038bb8231a16c1f1a915bab89f1b7e45368 (patch)
treec40d28f088ed4844d9e1bb0e9848b415438e73f9
parentbe0da31f7a2e91b211b556ead5f1529f4427441a (diff)
parent2c557787c119ac629085cba2455132f5b82553dc (diff)
Merge pull request #32683 from Faless/ws/improve_pr
WebSocket improvements, SSL server, custom headers.
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml20
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml11
-rw-r--r--modules/websocket/emws_client.cpp15
-rw-r--r--modules/websocket/emws_client.h2
-rw-r--r--modules/websocket/websocket_client.cpp24
-rw-r--r--modules/websocket/websocket_client.h8
-rw-r--r--modules/websocket/websocket_server.cpp41
-rw-r--r--modules/websocket/websocket_server.h16
-rw-r--r--modules/websocket/wsl_client.cpp19
-rw-r--r--modules/websocket/wsl_client.h4
-rw-r--r--modules/websocket/wsl_peer.cpp11
-rw-r--r--modules/websocket/wsl_peer.h3
-rw-r--r--modules/websocket/wsl_server.cpp34
-rw-r--r--modules/websocket/wsl_server.h11
14 files changed, 181 insertions, 38 deletions
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index c3baf9de83..705e3485f5 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -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.
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index 63318e5874..651048316c 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -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">
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 409cc9f699..fad766ea5d 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -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 {
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index 1811d05eea..2d35f7f0f6 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -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;
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index 4ff5404c61..8bbd5aa37f 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -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")));
diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h
index 7ddb9468a5..08fd6798fe 100644
--- a/modules/websocket/websocket_client.h
+++ b/modules/websocket/websocket_client.h
@@ -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;
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index ef5f6f5c20..c7414075ed 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -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;
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index 83c0c10419..0b39f94473 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -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();
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 0006a057e0..a422f65cfc 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -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) {
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index 57dfd635b7..870be94a87 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -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 = "");
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 74fb901232..32beccde5d 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -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() {
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index d51b304fe1..01ad250468 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -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.
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index efb526eed1..993dceafb9 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -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 {
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 2ceb941073..aae563355e 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -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;