Skip to content

Commit c010e16

Browse files
committed
Stub of gadp server.
1 parent 4e82aa9 commit c010e16

File tree

7 files changed

+369
-3
lines changed

7 files changed

+369
-3
lines changed

src/core/gadp-server.cc

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/***************************************************************************
2+
* Copyright (C) 2021 PCSX-Redux authors *
3+
* *
4+
* This program is free software; you can redistribute it and/or modify *
5+
* it under the terms of the GNU General Public License as published by *
6+
* the Free Software Foundation; either version 2 of the License, or *
7+
* (at your option) any later version. *
8+
* *
9+
* This program is distributed in the hope that it will be useful, *
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12+
* GNU General Public License for more details. *
13+
* *
14+
* You should have received a copy of the GNU General Public License *
15+
* along with this program; if not, write to the *
16+
* Free Software Foundation, Inc., *
17+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
18+
***************************************************************************/
19+
20+
#include "core/gadp-server.h"
21+
22+
#include <assert.h>
23+
24+
#include "core/debug.h"
25+
#include "core/misc.h"
26+
#include "core/psxemulator.h"
27+
#include "core/psxmem.h"
28+
#include "core/r3000a.h"
29+
#include "core/system.h"
30+
#include "support/protobuf.h"
31+
#include "uvw.hpp"
32+
33+
enum class ErrorCode {
34+
EC_UNKNOWN = 0,
35+
EC_BAD_REQUEST = 1,
36+
EC_NO_VERSION = 2,
37+
EC_NO_OBJECT = 3,
38+
EC_NO_INTERFACE = 4,
39+
EC_BAD_ARGUMENT = 5,
40+
EC_BAD_ADDRESS = 6,
41+
EC_NOT_SUPPORTED = 7,
42+
EC_MEMORY_ACCESS = 8,
43+
EC_REGISTER_ACCESS = 9,
44+
EC_USER_ERROR = 10,
45+
EC_MODEL_ACCESS = 11,
46+
};
47+
48+
enum class StepKind {
49+
SK_INTO = 0,
50+
SK_ADVANCE = 1,
51+
SK_FINISH = 2,
52+
SK_LINE = 3,
53+
SK_OVER = 4,
54+
SK_OVER_LINE = 5,
55+
SK_SKIP = 6,
56+
SK_RETURN = 7,
57+
SK_UNTIL = 8,
58+
};
59+
60+
enum class AttachKind {
61+
AK_BY_OBJECT_REF = 0,
62+
AK_BY_ID = 1,
63+
};
64+
65+
enum class ExecutionState {
66+
ES_INACTIVE = 0,
67+
ES_ACTIVE = 1,
68+
ES_STOPPED = 2,
69+
ES_RUNNING = 3,
70+
ES_TERMINATED = 4,
71+
};
72+
73+
enum class PrimitiveKind {
74+
PK_UNDEFINED = 0,
75+
PK_VOID = 1,
76+
PK_UINT = 2,
77+
PK_SINT = 3,
78+
PK_FLOAT = 4,
79+
PK_COMPLEX = 5,
80+
};
81+
82+
enum class UpdateMode {
83+
UM_UNSOLICITED = 0,
84+
UM_SOLICITED = 1,
85+
UM_FIXED = 2,
86+
};
87+
88+
enum class ValueType {
89+
VT_VOID = 0,
90+
VT_BOOL = 1,
91+
VT_INT = 2,
92+
VT_LONG = 3,
93+
VT_FLOAT = 4,
94+
VT_DOUBLE = 5,
95+
VT_BYTES = 6,
96+
VT_STRING = 7,
97+
VT_STRING_LIST = 8,
98+
VT_ADDRESS = 9,
99+
VT_RANGE = 10,
100+
VT_BREAK_KIND_SET = 11,
101+
VT_EXECUTION_STATE = 12,
102+
VT_STEP_KIND_SET = 13,
103+
VT_PRIMITIVE_KIND = 14,
104+
VT_DATA_TYPE = 15,
105+
VT_UPDATE_MODE = 16,
106+
VT_PATH = 17,
107+
VT_PATH_LIST = 18,
108+
VT_TYPE = 19,
109+
VT_ATTACH_KIND_SET = 20,
110+
};
111+
112+
enum class TargetEventType {
113+
TET_STOPPED = 0,
114+
TET_RUNNING = 1,
115+
TET_PROCESS_CREATED = 2,
116+
TET_PROCESS_EXITED = 3,
117+
TET_THREAD_CREATED = 4,
118+
TET_THREAD_EXITED = 5,
119+
TET_MODULE_LOADED = 6,
120+
TET_MODULE_UNLOADED = 7,
121+
TET_BREAKPOINT_HIT = 8,
122+
TET_STEP_COMPLETED = 9,
123+
TET_EXCEPTION = 10,
124+
TET_SIGNAL = 11,
125+
};
126+
127+
PCSX::GadpServer::GadpServer() : m_listener(g_system->m_eventBus) {
128+
m_listener.listen<Events::SettingsLoaded>([this](const auto& event) {
129+
if (g_emulator->settings.get<Emulator::SettingGadpServer>()) {
130+
startServer(g_emulator->settings.get<Emulator::SettingGadpServerPort>());
131+
}
132+
});
133+
m_listener.listen<Events::Quitting>([this](const auto& event) {
134+
if (m_serverStatus == SERVER_STARTED) stopServer();
135+
});
136+
}
137+
138+
void PCSX::GadpServer::stopServer() {
139+
assert(m_serverStatus == SERVER_STARTED);
140+
for (auto& client : m_clients) client.close();
141+
m_server->close();
142+
}
143+
144+
void PCSX::GadpServer::startServer(int port) {
145+
assert(m_serverStatus == SERVER_STOPPED);
146+
m_server = g_emulator->m_loop->resource<uvw::TCPHandle>();
147+
m_server->on<uvw::ListenEvent>([this](const uvw::ListenEvent&, uvw::TCPHandle& srv) { onNewConnection(); });
148+
m_server->on<uvw::CloseEvent>(
149+
[this](const uvw::CloseEvent&, uvw::TCPHandle& srv) { m_serverStatus = SERVER_STOPPED; });
150+
m_server->on<uvw::ErrorEvent>(
151+
[this](const uvw::ErrorEvent& event, uvw::TCPHandle& srv) { m_gotError = event.what(); });
152+
m_gotError = "";
153+
m_server->bind("0.0.0.0", port);
154+
if (!m_gotError.empty()) {
155+
g_system->printf("Error while trying to bind to port %i: %s\n", port, m_gotError.c_str());
156+
m_server->close();
157+
return;
158+
}
159+
m_server->listen();
160+
if (!m_gotError.empty()) {
161+
g_system->printf("Error while trying to listen to port %i: %s\n", port, m_gotError.c_str());
162+
m_server->close();
163+
return;
164+
}
165+
166+
m_serverStatus = SERVER_STARTED;
167+
}
168+
169+
void PCSX::GadpServer::onNewConnection() {
170+
GadpClient* client = new GadpClient(m_server);
171+
m_clients.push_back(client);
172+
client->accept(m_server);
173+
}
174+
175+
PCSX::GadpClient::GadpClient(std::shared_ptr<uvw::TCPHandle> srv)
176+
: m_tcp(srv->loop().resource<uvw::TCPHandle>()), m_listener(g_system->m_eventBus) {
177+
m_listener.listen<Events::ExecutionFlow::Pause>([this](const auto& event) {});
178+
m_listener.listen<Events::ExecutionFlow::ShellReached>([this](const auto& event) {});
179+
}
180+
181+
void PCSX::GadpClient::processData(const Slice& slice) {
182+
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(slice.data());
183+
auto size = slice.size();
184+
int v = 0;
185+
186+
while (size) {
187+
switch (m_state) {
188+
case WAIT_FOR_LEN:
189+
m_lenBuffer[m_length++] = *ptr++;
190+
size--;
191+
if (m_length == 4) {
192+
m_length = m_lenBuffer[0] | (m_lenBuffer[1] << 8) | (m_lenBuffer[2] << 16) | (m_lenBuffer[3] << 24);
193+
m_protoBuffer.clear();
194+
if (m_length != 0) {
195+
m_state = READING_DATA;
196+
} else {
197+
// process empty proto
198+
}
199+
}
200+
break;
201+
case READING_DATA: {
202+
auto copySize = std::min(size, m_length);
203+
m_protoBuffer += std::string((const char*)ptr, copySize);
204+
ptr += copySize;
205+
size -= copySize;
206+
m_length -= copySize;
207+
208+
if (m_length == 0) {
209+
m_state = WAIT_FOR_LEN;
210+
// process proto
211+
}
212+
}
213+
}
214+
}
215+
}

src/core/gadp-server.h

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/***************************************************************************
2+
* Copyright (C) 2021 PCSX-Redux authors *
3+
* *
4+
* This program is free software; you can redistribute it and/or modify *
5+
* it under the terms of the GNU General Public License as published by *
6+
* the Free Software Foundation; either version 2 of the License, or *
7+
* (at your option) any later version. *
8+
* *
9+
* This program is distributed in the hope that it will be useful, *
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12+
* GNU General Public License for more details. *
13+
* *
14+
* You should have received a copy of the GNU General Public License *
15+
* along with this program; if not, write to the *
16+
* Free Software Foundation, Inc., *
17+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
18+
***************************************************************************/
19+
20+
#pragma once
21+
22+
#include <assert.h>
23+
24+
#include "support/eventbus.h"
25+
#include "support/list.h"
26+
#include "support/slice.h"
27+
#include "uvw.hpp"
28+
29+
namespace PCSX {
30+
31+
class GadpClient : public Intrusive::List<GadpClient>::Node {
32+
public:
33+
GadpClient(std::shared_ptr<uvw::TCPHandle> srv);
34+
~GadpClient() { assert(m_requests.size() == 0); }
35+
typedef Intrusive::List<GadpClient> ListType;
36+
37+
void accept(std::shared_ptr<uvw::TCPHandle> srv) {
38+
assert(m_status == CLOSED);
39+
m_tcp->on<uvw::CloseEvent>([this](const uvw::CloseEvent&, uvw::TCPHandle&) { delete this; });
40+
m_tcp->on<uvw::EndEvent>([this](const uvw::EndEvent&, uvw::TCPHandle&) { close(); });
41+
m_tcp->on<uvw::ErrorEvent>([this](const uvw::ErrorEvent&, uvw::TCPHandle&) { close(); });
42+
m_tcp->on<uvw::DataEvent>([this](const uvw::DataEvent& event, uvw::TCPHandle&) { read(event); });
43+
m_tcp->on<uvw::WriteEvent>([this](const uvw::WriteEvent&, uvw::TCPHandle&) {
44+
auto top = m_requests.begin();
45+
if (top == m_requests.end()) return;
46+
top->gotWriteEvent();
47+
});
48+
srv->accept(*m_tcp);
49+
m_tcp->read();
50+
m_status = OPEN;
51+
}
52+
void close() {
53+
if (m_status != OPEN) return;
54+
m_status = CLOSING;
55+
m_tcp->close();
56+
m_requests.destroyAll();
57+
}
58+
59+
private:
60+
void write(const Slice& slice) {
61+
auto* req = new WriteRequest();
62+
req->m_slice = slice;
63+
req->enqueue(this);
64+
}
65+
66+
struct WriteRequest : public Intrusive::List<WriteRequest>::Node {
67+
void enqueue(GadpClient* client) {
68+
m_outstanding = 1;
69+
client->m_requests.push_back(this);
70+
client->m_tcp->write(static_cast<char*>(const_cast<void*>(m_slice.data())), m_slice.size());
71+
}
72+
void gotWriteEvent() {
73+
if (--m_outstanding == 0) delete this;
74+
}
75+
uv_write_t m_req;
76+
Slice m_slice;
77+
unsigned m_outstanding;
78+
};
79+
friend struct WriteRequest;
80+
Intrusive::List<WriteRequest> m_requests;
81+
void read(const uvw::DataEvent& event) {
82+
Slice slice;
83+
slice.borrow(event.data.get(), event.length);
84+
85+
processData(slice);
86+
}
87+
void processData(const Slice& slice);
88+
89+
std::shared_ptr<uvw::TCPHandle> m_tcp;
90+
enum { CLOSED, OPEN, CLOSING } m_status = CLOSED;
91+
92+
EventBus::Listener m_listener;
93+
94+
std::string m_protoBuffer;
95+
enum {
96+
WAIT_FOR_LEN,
97+
READING_DATA,
98+
} m_state = WAIT_FOR_LEN;
99+
uint8_t m_lenBuffer[4];
100+
uint32_t m_length = 0;
101+
};
102+
103+
class GadpServer {
104+
public:
105+
GadpServer();
106+
enum GadpServerStatus {
107+
SERVER_STOPPED,
108+
SERVER_STARTED,
109+
};
110+
GadpServerStatus getServerStatus() { return m_serverStatus; }
111+
112+
void startServer(int port = 15432);
113+
void stopServer();
114+
115+
private:
116+
void onNewConnection();
117+
GadpServerStatus m_serverStatus = SERVER_STOPPED;
118+
std::shared_ptr<uvw::TCPHandle> m_server;
119+
GadpClient::ListType m_clients;
120+
EventBus::Listener m_listener;
121+
std::string m_gotError;
122+
};
123+
124+
} // namespace PCSX

src/core/psxemulator.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "core/cdrom.h"
2323
#include "core/cheat.h"
2424
#include "core/debug.h"
25+
#include "core/gadp-server.h"
2526
#include "core/gdb-server.h"
2627
#include "core/gpu.h"
2728
#include "core/gte.h"

src/core/psxemulator.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class CDRom;
8585
class Cheats;
8686
class Counters;
8787
class Debug;
88+
class GadpServer;
8889
class GdbServer;
8990
class WebServer;
9091
class GPU;
@@ -141,6 +142,8 @@ class Emulator {
141142
typedef SettingString<TYPESTRING("Locale")> SettingLocale;
142143
typedef Setting<bool, TYPESTRING("Mcd1Inserted"), true> SettingMcd1Inserted;
143144
typedef Setting<bool, TYPESTRING("Mcd2Inserted"), true> SettingMcd2Inserted;
145+
typedef Setting<bool, TYPESTRING("GadpServer"), false> SettingGadpServer;
146+
typedef Setting<int, TYPESTRING("GadpServerPort"), 15432> SettingGadpServerPort;
144147
typedef Setting<bool, TYPESTRING("GdbServer"), false> SettingGdbServer;
145148
typedef Setting<bool, TYPESTRING("GdbManifest"), true> SettingGdbManifest;
146149
typedef Setting<int, TYPESTRING("GdbServerPort"), 3333> SettingGdbServerPort;
@@ -152,9 +155,9 @@ class Emulator {
152155
Settings<SettingStdout, SettingLogfile, SettingMcd1, SettingMcd2, SettingBios, SettingPpfDir, SettingPsxExe,
153156
SettingXa, SettingSioIrq, SettingSpuIrq, SettingBnWMdec, SettingAutoVideo, SettingVideo, SettingCDDA,
154157
SettingFastBoot, SettingDebug, SettingVerbose, SettingRCntFix, SettingIsoPath, SettingLocale,
155-
SettingMcd1Inserted, SettingMcd2Inserted, SettingBiosOverlay, SettingGdbServer, SettingGdbManifest,
156-
SettingGdbServerPort, SettingGdbServerTrace, SettingWebServer, SettingWebServerPort, SettingDynarec,
157-
Setting8MB>
158+
SettingMcd1Inserted, SettingMcd2Inserted, SettingBiosOverlay, SettingGadpServer, SettingGadpServerPort,
159+
SettingGdbServer, SettingGdbManifest, SettingGdbServerPort, SettingGdbServerTrace, SettingWebServer,
160+
SettingWebServerPort, SettingDynarec, Setting8MB>
158161
settings;
159162
class PcsxConfig {
160163
public:
@@ -207,6 +210,7 @@ class Emulator {
207210
std::unique_ptr<Cheats> m_cheats;
208211
std::unique_ptr<MDEC> m_mdec;
209212
std::unique_ptr<GPU> m_gpu;
213+
std::unique_ptr<GadpServer> m_gadpServer;
210214
std::unique_ptr<GdbServer> m_gdbServer;
211215
std::unique_ptr<WebServer> m_webServer;
212216
std::unique_ptr<Debug> m_debug;

0 commit comments

Comments
 (0)