123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*************************************************************************/
- /* editor_debugger_server.cpp */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
- /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #include "editor_debugger_server.h"
- #include "core/io/packet_peer.h"
- #include "core/io/tcp_server.h"
- #include "core/os/mutex.h"
- #include "core/os/thread.h"
- #include "editor/editor_log.h"
- #include "editor/editor_node.h"
- #include "editor/editor_settings.h"
- class EditorDebuggerPeerTCP : public EditorDebuggerPeer {
- private:
- enum {
- QUEUE_MAX = 2048,
- POLL_USEC_MAX = 100,
- };
- Ref<StreamPeerTCP> tcp;
- Ref<PacketPeerStream> packet_peer;
- List<Array> out_queue;
- List<Array> in_queue;
- Mutex mutex;
- bool connected = false;
- public:
- Error poll() {
- MutexLock lock(mutex);
- connected = tcp->get_status() == StreamPeerTCP::STATUS_CONNECTED;
- Error err = OK;
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- while (connected && packet_peer->get_available_packet_count() > 0 && in_queue.size() < QUEUE_MAX && OS::get_singleton()->get_ticks_usec() - ticks < POLL_USEC_MAX) {
- Variant var;
- err = packet_peer->get_var(var);
- connected = tcp->get_status() == StreamPeerTCP::STATUS_CONNECTED;
- if (err != OK) {
- ERR_PRINT("Error reading variant from peer");
- break;
- }
- ERR_CONTINUE_MSG(var.get_type() != Variant::ARRAY, "Malformed packet received, not an Array.");
- in_queue.push_back(var);
- }
- ticks = OS::get_singleton()->get_ticks_usec();
- while (connected && out_queue.size() > 0 && OS::get_singleton()->get_ticks_usec() - ticks < POLL_USEC_MAX) {
- Array arr = out_queue[0];
- out_queue.pop_front();
- packet_peer->put_var(arr);
- connected = tcp->get_status() == StreamPeerTCP::STATUS_CONNECTED;
- }
- return err;
- }
- bool has_message() {
- return in_queue.size() > 0;
- }
- Array get_message() {
- MutexLock lock(mutex);
- ERR_FAIL_COND_V(!has_message(), Array());
- Array out = in_queue[0];
- in_queue.pop_front();
- return out;
- }
- Error put_message(const Array p_arr) {
- MutexLock lock(mutex);
- if (out_queue.size() > QUEUE_MAX) {
- return ERR_OUT_OF_MEMORY;
- }
- out_queue.push_back(p_arr);
- return OK;
- }
- int get_max_message_size() const {
- return 8 << 20; // 8 MiB
- }
- bool is_peer_connected() {
- return connected;
- }
- void close() {
- MutexLock lock(mutex);
- connected = false;
- tcp->disconnect_from_host();
- }
- EditorDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream) {
- packet_peer.instance();
- tcp = p_stream;
- if (tcp.is_null()) {
- tcp.instance(); // Bug?
- }
- packet_peer->set_stream_peer(tcp);
- }
- ~EditorDebuggerPeerTCP() {
- close();
- packet_peer->set_stream_peer(Ref<StreamPeer>());
- }
- };
- class EditorDebuggerServerTCP : public EditorDebuggerServer {
- private:
- Ref<TCP_Server> server;
- List<Ref<EditorDebuggerPeer> > peers;
- Thread *thread = NULL;
- Mutex mutex;
- bool running = false;
- static void _poll_func(void *p_ud);
- public:
- virtual Error start();
- virtual void stop();
- virtual bool is_active() const;
- virtual bool is_connection_available() const;
- virtual Ref<EditorDebuggerPeer> take_connection();
- EditorDebuggerServerTCP();
- };
- EditorDebuggerServerTCP::EditorDebuggerServerTCP() {
- server.instance();
- }
- Error EditorDebuggerServerTCP::start() {
- int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
- const Error err = server->listen(remote_port);
- if (err != OK) {
- EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), EditorLog::MSG_TYPE_ERROR);
- return err;
- }
- running = true;
- thread = Thread::create(_poll_func, this);
- return err;
- }
- void EditorDebuggerServerTCP::stop() {
- server->stop();
- if (thread != NULL) {
- running = false;
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = NULL;
- }
- }
- bool EditorDebuggerServerTCP::is_active() const {
- return server->is_listening();
- }
- bool EditorDebuggerServerTCP::is_connection_available() const {
- return server->is_listening() && server->is_connection_available();
- }
- Ref<EditorDebuggerPeer> EditorDebuggerServerTCP::take_connection() {
- ERR_FAIL_COND_V(!is_connection_available(), Ref<EditorDebuggerPeer>());
- MutexLock lock(mutex);
- Ref<EditorDebuggerPeerTCP> peer = memnew(EditorDebuggerPeerTCP(server->take_connection()));
- peers.push_back(peer);
- return peer;
- }
- void EditorDebuggerServerTCP::_poll_func(void *p_ud) {
- EditorDebuggerServerTCP *me = (EditorDebuggerServerTCP *)p_ud;
- while (me->running) {
- me->mutex.lock();
- List<Ref<EditorDebuggerPeer> > remove;
- for (int i = 0; i < me->peers.size(); i++) {
- Ref<EditorDebuggerPeer> peer = me->peers[i];
- Error err = ((EditorDebuggerPeerTCP *)peer.ptr())->poll();
- if (err != OK || !peer->is_peer_connected())
- remove.push_back(peer);
- }
- for (List<Ref<EditorDebuggerPeer> >::Element *E = remove.front(); E; E = E->next()) {
- me->peers.erase(E->get());
- }
- me->mutex.unlock();
- OS::get_singleton()->delay_usec(50);
- }
- }
- EditorDebuggerServer *EditorDebuggerServer::create_default() {
- return memnew(EditorDebuggerServerTCP);
- }
|