Path: blob/master/editor/debugger/editor_debugger_server.cpp
20874 views
/**************************************************************************/1/* editor_debugger_server.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_debugger_server.h"3132#include "core/io/tcp_server.h"33#include "core/io/uds_server.h"34#include "core/os/thread.h"35#include "editor/editor_log.h"36#include "editor/editor_node.h"37#include "editor/settings/editor_settings.h"3839template <typename T>40class EditorDebuggerServerSocket : public EditorDebuggerServer {41GDSOFTCLASS(EditorDebuggerServerSocket, EditorDebuggerServer);4243protected:44Ref<T> server;45String endpoint;4647public:48virtual void poll() override {}49virtual String get_uri() const override;50virtual void stop() override;51virtual bool is_active() const override;52virtual bool is_connection_available() const override;53virtual Ref<RemoteDebuggerPeer> take_connection() override;5455EditorDebuggerServerSocket();56};5758class EditorDebuggerServerTCP : public EditorDebuggerServerSocket<TCPServer> {59public:60static EditorDebuggerServer *create(const String &p_protocol);6162virtual Error start(const String &p_uri) override;63};6465EditorDebuggerServer *EditorDebuggerServerTCP::create(const String &p_protocol) {66ERR_FAIL_COND_V(p_protocol != "tcp://", nullptr);67return memnew(EditorDebuggerServerTCP);68}6970template <typename T>71EditorDebuggerServerSocket<T>::EditorDebuggerServerSocket() {72server.instantiate();73}7475template <typename T>76String EditorDebuggerServerSocket<T>::get_uri() const {77return endpoint;78}7980Error EditorDebuggerServerTCP::start(const String &p_uri) {81// Default host and port82String bind_host = (String)EDITOR_GET("network/debug/remote_host");83int bind_port = (int)EDITOR_GET("network/debug/remote_port");8485// Optionally override86if (!p_uri.is_empty() && p_uri != "tcp://") {87String scheme, path, fragment;88Error err = p_uri.parse_url(scheme, bind_host, bind_port, path, fragment);89ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);90ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);91}9293// Try listening on ports94const int max_attempts = 5;95for (int attempt = 1;; ++attempt) {96const Error err = server->listen(bind_port, bind_host);97if (err == OK) {98break;99}100if (attempt >= max_attempts) {101EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, remote debugging unavailable.", bind_port), EditorLog::MSG_TYPE_ERROR);102return err;103}104int last_port = bind_port++;105EditorNode::get_log()->add_message(vformat("Cannot listen on port %d, trying %d instead.", last_port, bind_port), EditorLog::MSG_TYPE_WARNING);106}107108// Endpoint that the client should connect to109endpoint = vformat("tcp://%s:%d", bind_host, bind_port);110111return OK;112}113114template <typename T>115void EditorDebuggerServerSocket<T>::stop() {116server->stop();117}118119template <typename T>120bool EditorDebuggerServerSocket<T>::is_active() const {121return server->is_listening();122}123124template <typename T>125bool EditorDebuggerServerSocket<T>::is_connection_available() const {126return server->is_listening() && server->is_connection_available();127}128129template <typename T>130Ref<RemoteDebuggerPeer> EditorDebuggerServerSocket<T>::take_connection() {131const Ref<RemoteDebuggerPeer> out;132ERR_FAIL_COND_V(!is_connection_available(), out);133Ref<StreamPeerSocket> stream = server->take_socket_connection();134ERR_FAIL_COND_V(stream.is_null(), out);135return memnew(RemoteDebuggerPeerTCP(stream));136}137138class EditorDebuggerServerUDS : public EditorDebuggerServerSocket<UDSServer> {139public:140static EditorDebuggerServer *create(const String &p_protocol);141142virtual Error start(const String &p_uri) override;143};144145EditorDebuggerServer *EditorDebuggerServerUDS::create(const String &p_protocol) {146ERR_FAIL_COND_V(p_protocol != "unix://", nullptr);147return memnew(EditorDebuggerServerUDS);148}149150Error EditorDebuggerServerUDS::start(const String &p_uri) {151String bind_path = p_uri.is_empty() ? String("/tmp/godot_debugger.sock") : p_uri.replace("unix://", "");152153const Error err = server->listen(bind_path);154if (err != OK) {155EditorNode::get_log()->add_message(vformat("Cannot listen at path %s, remote debugging unavailable.", bind_path), EditorLog::MSG_TYPE_ERROR);156return err;157}158endpoint = "unix://" + bind_path;159return OK;160}161162/// EditorDebuggerServer163HashMap<StringName, EditorDebuggerServer::CreateServerFunc> EditorDebuggerServer::protocols;164165EditorDebuggerServer *EditorDebuggerServer::create(const String &p_protocol) {166CreateServerFunc *create_fn = protocols.getptr(p_protocol);167ERR_FAIL_NULL_V(create_fn, nullptr);168return (*create_fn)(p_protocol);169}170171void EditorDebuggerServer::register_protocol_handler(const String &p_protocol, CreateServerFunc p_func) {172ERR_FAIL_COND(protocols.has(p_protocol));173protocols[p_protocol] = p_func;174}175176void EditorDebuggerServer::initialize() {177register_protocol_handler("tcp://", EditorDebuggerServerTCP::create);178#if defined(UNIX_ENABLED)179register_protocol_handler("unix://", EditorDebuggerServerUDS::create);180#endif181}182183void EditorDebuggerServer::deinitialize() {184protocols.clear();185}186187188