Skip to content

Commit

Permalink
Stub of gadp server.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasnoble committed Jan 15, 2021
1 parent 4e82aa9 commit f6ad4a2
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 3 deletions.
217 changes: 217 additions & 0 deletions src/core/gadp-server.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/***************************************************************************
* Copyright (C) 2020 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/

#include "core/gadp-server.h"

#include <assert.h>

#include "core/debug.h"
#include "core/misc.h"
#include "core/psxemulator.h"
#include "core/psxmem.h"
#include "core/r3000a.h"
#include "core/system.h"
#include "support/protobuf.h"
#include "uvw.hpp"

#undef VOID

enum class ErrorCode {
UNKNOWN = 0,
BAD_REQUEST = 1,
NO_VERSION = 2,
NO_OBJECT = 3,
NO_INTERFACE = 4,
BAD_ARGUMENT = 5,
BAD_ADDRESS = 6,
NOT_SUPPORTED = 7,
MEMORY_ACCESS = 8,
REGISTER_ACCESS = 9,
USER_ERROR = 10,
MODEL_ACCESS = 11,
};

enum class StepKind {
INTO = 0,
ADVANCE = 1,
FINISH = 2,
LINE = 3,
OVER = 4,
OVER_LINE = 5,
SKIP = 6,
RETURN = 7,
UNTIL = 8,
};

enum class AttachKind {
BY_OBJECT_REF = 0,
BY_ID = 1,
};

enum class ExecutionState {
INACTIVE = 0,
ACTIVE = 1,
STOPPED = 2,
RUNNING = 3,
TERMINATED = 4,
};

enum class PrimitiveKind {
UNDEFINED = 0,
VOID = 1,
UINT = 2,
SINT = 3,
FLOAT = 4,
COMPLEX = 5,
};

enum class UpdateMode {
UNSOLICITED = 0,
SOLICITED = 1,
FIXED = 2,
};

enum class ValueType {
VT_VOID = 0,
VT_BOOL = 1,
VT_INT = 2,
VT_LONG = 3,
VT_FLOAT = 4,
VT_DOUBLE = 5,
VT_BYTES = 6,
VT_STRING = 7,
VT_STRING_LIST = 8,
VT_ADDRESS = 9,
VT_RANGE = 10,
VT_BREAK_KIND_SET = 11,
VT_EXECUTION_STATE = 12,
VT_STEP_KIND_SET = 13,
VT_PRIMITIVE_KIND = 14,
VT_DATA_TYPE = 15,
VT_UPDATE_MODE = 16,
VT_PATH = 17,
VT_PATH_LIST = 18,
VT_TYPE = 19,
VT_ATTACH_KIND_SET = 20,
};

enum class TargetEventType {
EV_STOPPED = 0,
EV_RUNNING = 1,
PROCESS_CREATED = 2,
PROCESS_EXITED = 3,
THREAD_CREATED = 4,
THREAD_EXITED = 5,
MODULE_LOADED = 6,
MODULE_UNLOADED = 7,
BREAKPOINT_HIT = 8,
STEP_COMPLETED = 9,
EXCEPTION = 10,
SIGNAL = 11,
};

PCSX::GadpServer::GadpServer() : m_listener(g_system->m_eventBus) {
m_listener.listen<Events::SettingsLoaded>([this](const auto& event) {
if (g_emulator->settings.get<Emulator::SettingGadpServer>()) {
startServer(g_emulator->settings.get<Emulator::SettingGadpServerPort>());
}
});
m_listener.listen<Events::Quitting>([this](const auto& event) {
if (m_serverStatus == SERVER_STARTED) stopServer();
});
}

void PCSX::GadpServer::stopServer() {
assert(m_serverStatus == SERVER_STARTED);
for (auto& client : m_clients) client.close();
m_server->close();
}

void PCSX::GadpServer::startServer(int port) {
assert(m_serverStatus == SERVER_STOPPED);
m_server = g_emulator->m_loop->resource<uvw::TCPHandle>();
m_server->on<uvw::ListenEvent>([this](const uvw::ListenEvent&, uvw::TCPHandle& srv) { onNewConnection(); });
m_server->on<uvw::CloseEvent>(
[this](const uvw::CloseEvent&, uvw::TCPHandle& srv) { m_serverStatus = SERVER_STOPPED; });
m_server->on<uvw::ErrorEvent>(
[this](const uvw::ErrorEvent& event, uvw::TCPHandle& srv) { m_gotError = event.what(); });
m_gotError = "";
m_server->bind("0.0.0.0", port);
if (!m_gotError.empty()) {
g_system->printf("Error while trying to bind to port %i: %s\n", port, m_gotError.c_str());
m_server->close();
return;
}
m_server->listen();
if (!m_gotError.empty()) {
g_system->printf("Error while trying to listen to port %i: %s\n", port, m_gotError.c_str());
m_server->close();
return;
}

m_serverStatus = SERVER_STARTED;
}

void PCSX::GadpServer::onNewConnection() {
GadpClient* client = new GadpClient(m_server);
m_clients.push_back(client);
client->accept(m_server);
}

PCSX::GadpClient::GadpClient(std::shared_ptr<uvw::TCPHandle> srv)
: m_tcp(srv->loop().resource<uvw::TCPHandle>()), m_listener(g_system->m_eventBus) {
m_listener.listen<Events::ExecutionFlow::Pause>([this](const auto& event) {});
m_listener.listen<Events::ExecutionFlow::ShellReached>([this](const auto& event) {});
}

void PCSX::GadpClient::processData(const Slice& slice) {
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(slice.data());
auto size = slice.size();
int v = 0;

while (size) {
switch (m_state) {
case WAIT_FOR_LEN:
m_lenBuffer[m_length++] = *ptr++;
size--;
if (m_length == 4) {
m_length = m_lenBuffer[0] | (m_lenBuffer[1] << 8) | (m_lenBuffer[2] << 16) | (m_lenBuffer[3] << 24);
m_protoBuffer.clear();
if (m_length != 0) {
m_state = READING_DATA;
} else {
// process empty proto
}
}
break;
case READING_DATA: {
auto copySize = std::min(size, m_length);
m_protoBuffer += std::string((const char*)ptr, copySize);
ptr += copySize;
size -= copySize;
m_length -= copySize;

if (m_length == 0) {
m_state = WAIT_FOR_LEN;
// process proto
}
}
}
}
}
124 changes: 124 additions & 0 deletions src/core/gadp-server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/***************************************************************************
* Copyright (C) 2020 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/

#pragma once

#include <assert.h>

#include "support/eventbus.h"
#include "support/list.h"
#include "support/slice.h"
#include "uvw.hpp"

namespace PCSX {

class GadpClient : public Intrusive::List<GadpClient>::Node {
public:
GadpClient(std::shared_ptr<uvw::TCPHandle> srv);
~GadpClient() { assert(m_requests.size() == 0); }
typedef Intrusive::List<GadpClient> ListType;

void accept(std::shared_ptr<uvw::TCPHandle> srv) {
assert(m_status == CLOSED);
m_tcp->on<uvw::CloseEvent>([this](const uvw::CloseEvent&, uvw::TCPHandle&) { delete this; });
m_tcp->on<uvw::EndEvent>([this](const uvw::EndEvent&, uvw::TCPHandle&) { close(); });
m_tcp->on<uvw::ErrorEvent>([this](const uvw::ErrorEvent&, uvw::TCPHandle&) { close(); });
m_tcp->on<uvw::DataEvent>([this](const uvw::DataEvent& event, uvw::TCPHandle&) { read(event); });
m_tcp->on<uvw::WriteEvent>([this](const uvw::WriteEvent&, uvw::TCPHandle&) {
auto top = m_requests.begin();
if (top == m_requests.end()) return;
top->gotWriteEvent();
});
srv->accept(*m_tcp);
m_tcp->read();
m_status = OPEN;
}
void close() {
if (m_status != OPEN) return;
m_status = CLOSING;
m_tcp->close();
m_requests.destroyAll();
}

private:
void write(const Slice& slice) {
auto* req = new WriteRequest();
req->m_slice = slice;
req->enqueue(this);
}

struct WriteRequest : public Intrusive::List<WriteRequest>::Node {
void enqueue(GadpClient* client) {
m_outstanding = 1;
client->m_requests.push_back(this);
client->m_tcp->write(static_cast<char*>(const_cast<void*>(m_slice.data())), m_slice.size());
}
void gotWriteEvent() {
if (--m_outstanding == 0) delete this;
}
uv_write_t m_req;
Slice m_slice;
unsigned m_outstanding;
};
friend struct WriteRequest;
Intrusive::List<WriteRequest> m_requests;
void read(const uvw::DataEvent& event) {
Slice slice;
slice.borrow(event.data.get(), event.length);

processData(slice);
}
void processData(const Slice& slice);

std::shared_ptr<uvw::TCPHandle> m_tcp;
enum { CLOSED, OPEN, CLOSING } m_status = CLOSED;

EventBus::Listener m_listener;

std::string m_protoBuffer;
enum {
WAIT_FOR_LEN,
READING_DATA,
} m_state = WAIT_FOR_LEN;
uint8_t m_lenBuffer[4];
uint32_t m_length = 0;
};

class GadpServer {
public:
GadpServer();
enum GadpServerStatus {
SERVER_STOPPED,
SERVER_STARTED,
};
GadpServerStatus getServerStatus() { return m_serverStatus; }

void startServer(int port = 15432);
void stopServer();

private:
void onNewConnection();
GadpServerStatus m_serverStatus = SERVER_STOPPED;
std::shared_ptr<uvw::TCPHandle> m_server;
GadpClient::ListType m_clients;
EventBus::Listener m_listener;
std::string m_gotError;
};

} // namespace PCSX
1 change: 1 addition & 0 deletions src/core/psxemulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "core/cdrom.h"
#include "core/cheat.h"
#include "core/debug.h"
#include "core/gadp-server.h"
#include "core/gdb-server.h"
#include "core/gpu.h"
#include "core/gte.h"
Expand Down
10 changes: 7 additions & 3 deletions src/core/psxemulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class CDRom;
class Cheats;
class Counters;
class Debug;
class GadpServer;
class GdbServer;
class WebServer;
class GPU;
Expand Down Expand Up @@ -141,6 +142,8 @@ class Emulator {
typedef SettingString<TYPESTRING("Locale")> SettingLocale;
typedef Setting<bool, TYPESTRING("Mcd1Inserted"), true> SettingMcd1Inserted;
typedef Setting<bool, TYPESTRING("Mcd2Inserted"), true> SettingMcd2Inserted;
typedef Setting<bool, TYPESTRING("GadpServer"), false> SettingGadpServer;
typedef Setting<int, TYPESTRING("GadpServerPort"), 15432> SettingGadpServerPort;
typedef Setting<bool, TYPESTRING("GdbServer"), false> SettingGdbServer;
typedef Setting<bool, TYPESTRING("GdbManifest"), true> SettingGdbManifest;
typedef Setting<int, TYPESTRING("GdbServerPort"), 3333> SettingGdbServerPort;
Expand All @@ -152,9 +155,9 @@ class Emulator {
Settings<SettingStdout, SettingLogfile, SettingMcd1, SettingMcd2, SettingBios, SettingPpfDir, SettingPsxExe,
SettingXa, SettingSioIrq, SettingSpuIrq, SettingBnWMdec, SettingAutoVideo, SettingVideo, SettingCDDA,
SettingFastBoot, SettingDebug, SettingVerbose, SettingRCntFix, SettingIsoPath, SettingLocale,
SettingMcd1Inserted, SettingMcd2Inserted, SettingBiosOverlay, SettingGdbServer, SettingGdbManifest,
SettingGdbServerPort, SettingGdbServerTrace, SettingWebServer, SettingWebServerPort, SettingDynarec,
Setting8MB>
SettingMcd1Inserted, SettingMcd2Inserted, SettingBiosOverlay, SettingGadpServer, SettingGadpServerPort,
SettingGdbServer, SettingGdbManifest, SettingGdbServerPort, SettingGdbServerTrace, SettingWebServer,
SettingWebServerPort, SettingDynarec, Setting8MB>
settings;
class PcsxConfig {
public:
Expand Down Expand Up @@ -207,6 +210,7 @@ class Emulator {
std::unique_ptr<Cheats> m_cheats;
std::unique_ptr<MDEC> m_mdec;
std::unique_ptr<GPU> m_gpu;
std::unique_ptr<GadpServer> m_gadpServer;
std::unique_ptr<GdbServer> m_gdbServer;
std::unique_ptr<WebServer> m_webServer;
std::unique_ptr<Debug> m_debug;
Expand Down
Loading

0 comments on commit f6ad4a2

Please sign in to comment.