Core: Add UNIX domain socket support

> [!NOTE]
>
> Later versions of Windows has support for `AF_UNIX`, so it could be
> added.
This commit is contained in:
Stuart Carnie
2025-06-25 07:01:29 +10:00
parent a078895ad2
commit 7227fdd805
39 changed files with 1791 additions and 529 deletions

View File

@ -121,7 +121,10 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks,
}
void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, bool p_ignore_error_breaks, const Vector<String> &p_breakpoints, void (*p_allow_focus_steal_fn)()) {
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create_tcp); // TCP is the default protocol. Platforms/modules can add more.
#ifdef UNIX_ENABLED
register_uri_handler("unix://", RemoteDebuggerPeerTCP::create_unix);
#endif
if (p_uri.is_empty()) {
return;
}
@ -132,10 +135,10 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, bo
OS::get_singleton()->initialize_debugging();
} else if (p_uri.contains("://")) {
const String proto = p_uri.substr(0, p_uri.find("://") + 3);
if (!protocols.has(proto)) {
return;
}
RemoteDebuggerPeer *peer = protocols[proto](p_uri);
CreatePeerFunc *create_fn = protocols.getptr(proto);
ERR_FAIL_NULL_MSG(create_fn, vformat("Invalid protocol: %s.", proto));
RemoteDebuggerPeer *peer = (*create_fn)(p_uri);
if (!peer) {
return;
}

View File

@ -76,18 +76,19 @@ void RemoteDebuggerPeerTCP::close() {
in_buf.clear();
}
RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP() {
// This means remote debugger takes 16 MiB just because it exists...
in_buf.resize((8 << 20) + 4); // 8 MiB should be way more than enough (need 4 extra bytes for encoding packet size).
out_buf.resize(8 << 20); // 8 MiB should be way more than enough
tcp_client = p_tcp;
if (tcp_client.is_valid()) { // Attaching to an already connected stream.
connected = true;
running = true;
thread.start(_thread_func, this);
} else {
tcp_client.instantiate();
}
}
RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerSocket> p_stream) :
RemoteDebuggerPeerTCP() {
DEV_ASSERT(p_stream.is_valid());
tcp_client = p_stream;
connected = true;
running = true;
thread.start(_thread_func, this);
}
RemoteDebuggerPeerTCP::~RemoteDebuggerPeerTCP() {
@ -154,22 +155,10 @@ void RemoteDebuggerPeerTCP::_read_in() {
}
}
Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
} else {
ip = IP::get_singleton()->resolve_hostname(p_host);
}
int port = p_port;
Error RemoteDebuggerPeerTCP::_try_connect(Ref<StreamPeerSocket> tcp_client) {
const int tries = 6;
const int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 };
Error err = tcp_client->connect_to_host(ip, port);
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Remote Debugger: Unable to connect to host '%s:%d'.", p_host, port));
for (int i = 0; i < tries; i++) {
tcp_client->poll();
if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
@ -186,9 +175,6 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
ERR_PRINT(vformat("Remote Debugger: Unable to connect. Status: %s.", String::num_int64(tcp_client->get_status())));
return FAILED;
}
connected = true;
running = true;
thread.start(_thread_func, this);
return OK;
}
@ -222,7 +208,7 @@ void RemoteDebuggerPeerTCP::_poll() {
}
}
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create_tcp(const String &p_uri) {
ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
String debug_host = p_uri.replace("tcp://", "");
@ -234,13 +220,30 @@ RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
debug_host = debug_host.substr(0, sep_pos);
}
RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP);
Error err = peer->connect_to_host(debug_host, debug_port);
if (err != OK) {
memdelete(peer);
return nullptr;
IPAddress ip;
if (debug_host.is_valid_ip_address()) {
ip = debug_host;
} else {
ip = IP::get_singleton()->resolve_hostname(debug_host);
}
return peer;
Ref<StreamPeerTCP> stream;
stream.instantiate();
ERR_FAIL_COND_V_MSG(stream->connect_to_host(ip, debug_port) != OK, nullptr, vformat("Remote Debugger: Unable to connect to host '%s:%d'.", debug_host, debug_port));
ERR_FAIL_COND_V(_try_connect(stream), nullptr);
return memnew(RemoteDebuggerPeerTCP(stream));
}
RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create_unix(const String &p_uri) {
ERR_FAIL_COND_V(!p_uri.begins_with("unix://"), nullptr);
String debug_path = p_uri.replace("unix://", "");
Ref<StreamPeerUDS> stream;
stream.instantiate();
Error err = stream->connect_to_host(debug_path);
ERR_FAIL_COND_V_MSG(err != OK && err != ERR_BUSY, nullptr, vformat("Remote Debugger: Unable to connect to socket path '%s'.", debug_path));
ERR_FAIL_COND_V(_try_connect(stream), nullptr);
return memnew(RemoteDebuggerPeerTCP(stream));
}
RemoteDebuggerPeer::RemoteDebuggerPeer() {

View File

@ -31,6 +31,7 @@
#pragma once
#include "core/io/stream_peer_tcp.h"
#include "core/io/stream_peer_uds.h"
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
@ -59,7 +60,7 @@ class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
GDSOFTCLASS(RemoteDebuggerPeerTCP, RemoteDebuggerPeer);
private:
Ref<StreamPeerTCP> tcp_client;
Ref<StreamPeerSocket> tcp_client;
Mutex mutex;
Thread thread;
List<Array> in_queue;
@ -78,11 +79,11 @@ private:
void _poll();
void _write_out();
void _read_in();
static Error _try_connect(Ref<StreamPeerSocket> p_stream);
public:
static RemoteDebuggerPeer *create(const String &p_uri);
Error connect_to_host(const String &p_host, uint16_t p_port);
static RemoteDebuggerPeer *create_tcp(const String &p_uri);
static RemoteDebuggerPeer *create_unix(const String &p_uri);
bool is_peer_connected() override;
int get_max_message_size() const override;
@ -92,6 +93,7 @@ public:
void poll() override;
void close() override;
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
RemoteDebuggerPeerTCP(Ref<StreamPeerSocket> p_stream);
RemoteDebuggerPeerTCP();
~RemoteDebuggerPeerTCP();
};