citra/src/core/rpc/rpc_server.cpp

133 lines
4.1 KiB
C++
Raw Normal View History

Initial support for scripting (#4016) * Add ZeroMQ external submodule * ZeroMQ libzmq building on macOS * Added RPC namespace, settings and logging * Added request queue handling and new classes * Add C++ interface to ZeroMQ * Added start of ZeroMQ RPC Server implementation. * Request construction and callback request handling * Read and write memory implementation * Add ID to request format and send reply * Add RPC setting to macOS UI * Fixed initialization order bug and added exception handling * Working read-write through Python * Update CMakeLists for libzmq to resolve target name conflict on Windows * Platform-specific CMake definitions for Windows/non-Windows * Add comments * Revert "Add RPC setting to macOS UI" * Always run RPC server instead of configurable * Add Python scripting example. Updated .gitignore * Rename member variables to remove trailing underscore * Finally got libzmq external project building on macOS * Add missing dependency during libzmq build * Adding more missing dependencies [skip ci] * Only build what is required from libzmq * Extra length checks on client input * Call InvalidateCacheRange after memory write * Revert MinGW change. Fix clang-format. Improve error handling in request/reply. Allow any length of data read/write in Python. * Re-organized RPC static global state into a proper class. [skip ci] * Make sure libzmq always builds in Release mode * Renamed Request to Packet since Request and Reply are the same thing * Moved request fulfillment out of Packet and into RPCServer * Change request thread from sleep to condition variable * Remove non-blocking polling from ZMQ server code. Receive now blocks and terminates properly without sleeping. This change significantly improves script speed. * Move scripting files to dist/ instead of src/ * C++ code review changes for jroweboy [skip ci] * Python code review changes for jroweboy [skip ci] * Add docstrings and tests to citra.py [skip ci] * Add host OS check for libzmq build * Revert "Add host OS check for libzmq build" * Fixed a hang when emulation is stopped and restarted due to improper destruction order of ZMQ objects [skip ci] * Add scripting directory to archive packaging [skip ci] * Specify C/CXX compiler variables on MinGW build * Only specify compiler on Linux mingw * Use gcc and g++ on Windows mingw * Specify generator for mingw * Don't specify toolchain on windows mingw * Changed citra.py to support Python 3 instead of Python 2 * Fix bug where RPC wouldn't restart after Stop/Start emulation * Added copyright to headers and reorganized includes and forward declarations
2018-09-11 21:00:12 +01:00
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/memory.h"
#include "core/rpc/packet.h"
#include "core/rpc/rpc_server.h"
namespace RPC {
RPCServer::RPCServer() : server(*this) {
LOG_INFO(RPC_Server, "Starting RPC server ...");
Start();
LOG_INFO(RPC_Server, "RPC started.");
}
RPCServer::~RPCServer() {
LOG_INFO(RPC_Server, "Stopping RPC ...");
Stop();
LOG_INFO(RPC_Server, "RPC stopped.");
}
void RPCServer::HandleReadMemory(Packet& packet, u32 address, u32 data_size) {
if (data_size > MAX_READ_SIZE) {
return;
}
// Note: Memory read occurs asynchronously from the state of the emulator
Memory::ReadBlock(address, packet.GetPacketData().data(), data_size);
packet.SetPacketDataSize(data_size);
packet.SendReply();
}
void RPCServer::HandleWriteMemory(Packet& packet, u32 address, const u8* data, u32 data_size) {
// Only allow writing to certain memory regions
if ((address >= Memory::PROCESS_IMAGE_VADDR && address <= Memory::PROCESS_IMAGE_VADDR_END) ||
(address >= Memory::HEAP_VADDR && address <= Memory::HEAP_VADDR_END) ||
(address >= Memory::N3DS_EXTRA_RAM_VADDR && address <= Memory::N3DS_EXTRA_RAM_VADDR_END)) {
// Note: Memory write occurs asynchronously from the state of the emulator
Memory::WriteBlock(address, data, data_size);
// If the memory happens to be executable code, make sure the changes become visible
Core::CPU().InvalidateCacheRange(address, data_size);
}
packet.SetPacketDataSize(0);
packet.SendReply();
}
bool RPCServer::ValidatePacket(const PacketHeader& packet_header) {
if (packet_header.version <= CURRENT_VERSION) {
switch (packet_header.packet_type) {
case PacketType::ReadMemory:
case PacketType::WriteMemory:
if (packet_header.packet_size >= (sizeof(u32) * 2)) {
return true;
}
break;
default:
break;
}
}
return false;
}
void RPCServer::HandleSingleRequest(std::unique_ptr<Packet> request_packet) {
bool success = false;
if (ValidatePacket(request_packet->GetHeader())) {
// Currently, all request types use the address/data_size wire format
u32 address = 0;
u32 data_size = 0;
std::memcpy(&address, request_packet->GetPacketData().data(), sizeof(address));
std::memcpy(&data_size, request_packet->GetPacketData().data() + sizeof(address),
sizeof(data_size));
switch (request_packet->GetPacketType()) {
case PacketType::ReadMemory:
if (data_size > 0 && data_size <= MAX_READ_SIZE) {
HandleReadMemory(*request_packet, address, data_size);
success = true;
}
break;
case PacketType::WriteMemory:
if (data_size > 0 && data_size <= MAX_PACKET_DATA_SIZE - (sizeof(u32) * 2)) {
const u8* data = request_packet->GetPacketData().data() + (sizeof(u32) * 2);
HandleWriteMemory(*request_packet, address, data, data_size);
success = true;
}
break;
default:
break;
}
}
if (!success) {
// Send an empty reply, so as not to hang the client
request_packet->SetPacketDataSize(0);
request_packet->SendReply();
}
}
void RPCServer::HandleRequestsLoop() {
std::unique_ptr<RPC::Packet> request_packet;
LOG_INFO(RPC_Server, "Request handler started.");
2018-10-05 10:25:23 +01:00
while (request_queue.PopWait(request_packet)) {
if (!request_packet) {
Initial support for scripting (#4016) * Add ZeroMQ external submodule * ZeroMQ libzmq building on macOS * Added RPC namespace, settings and logging * Added request queue handling and new classes * Add C++ interface to ZeroMQ * Added start of ZeroMQ RPC Server implementation. * Request construction and callback request handling * Read and write memory implementation * Add ID to request format and send reply * Add RPC setting to macOS UI * Fixed initialization order bug and added exception handling * Working read-write through Python * Update CMakeLists for libzmq to resolve target name conflict on Windows * Platform-specific CMake definitions for Windows/non-Windows * Add comments * Revert "Add RPC setting to macOS UI" * Always run RPC server instead of configurable * Add Python scripting example. Updated .gitignore * Rename member variables to remove trailing underscore * Finally got libzmq external project building on macOS * Add missing dependency during libzmq build * Adding more missing dependencies [skip ci] * Only build what is required from libzmq * Extra length checks on client input * Call InvalidateCacheRange after memory write * Revert MinGW change. Fix clang-format. Improve error handling in request/reply. Allow any length of data read/write in Python. * Re-organized RPC static global state into a proper class. [skip ci] * Make sure libzmq always builds in Release mode * Renamed Request to Packet since Request and Reply are the same thing * Moved request fulfillment out of Packet and into RPCServer * Change request thread from sleep to condition variable * Remove non-blocking polling from ZMQ server code. Receive now blocks and terminates properly without sleeping. This change significantly improves script speed. * Move scripting files to dist/ instead of src/ * C++ code review changes for jroweboy [skip ci] * Python code review changes for jroweboy [skip ci] * Add docstrings and tests to citra.py [skip ci] * Add host OS check for libzmq build * Revert "Add host OS check for libzmq build" * Fixed a hang when emulation is stopped and restarted due to improper destruction order of ZMQ objects [skip ci] * Add scripting directory to archive packaging [skip ci] * Specify C/CXX compiler variables on MinGW build * Only specify compiler on Linux mingw * Use gcc and g++ on Windows mingw * Specify generator for mingw * Don't specify toolchain on windows mingw * Changed citra.py to support Python 3 instead of Python 2 * Fix bug where RPC wouldn't restart after Stop/Start emulation * Added copyright to headers and reorganized includes and forward declarations
2018-09-11 21:00:12 +01:00
break;
}
HandleSingleRequest(std::move(request_packet));
}
}
void RPCServer::QueueRequest(std::unique_ptr<RPC::Packet> request) {
request_queue.Push(std::move(request));
}
void RPCServer::Start() {
const auto threadFunction = [this]() { HandleRequestsLoop(); };
request_handler_thread = std::thread(threadFunction);
server.Start();
}
void RPCServer::Stop() {
server.Stop();
2018-10-05 10:25:23 +01:00
request_handler_thread.join();
Initial support for scripting (#4016) * Add ZeroMQ external submodule * ZeroMQ libzmq building on macOS * Added RPC namespace, settings and logging * Added request queue handling and new classes * Add C++ interface to ZeroMQ * Added start of ZeroMQ RPC Server implementation. * Request construction and callback request handling * Read and write memory implementation * Add ID to request format and send reply * Add RPC setting to macOS UI * Fixed initialization order bug and added exception handling * Working read-write through Python * Update CMakeLists for libzmq to resolve target name conflict on Windows * Platform-specific CMake definitions for Windows/non-Windows * Add comments * Revert "Add RPC setting to macOS UI" * Always run RPC server instead of configurable * Add Python scripting example. Updated .gitignore * Rename member variables to remove trailing underscore * Finally got libzmq external project building on macOS * Add missing dependency during libzmq build * Adding more missing dependencies [skip ci] * Only build what is required from libzmq * Extra length checks on client input * Call InvalidateCacheRange after memory write * Revert MinGW change. Fix clang-format. Improve error handling in request/reply. Allow any length of data read/write in Python. * Re-organized RPC static global state into a proper class. [skip ci] * Make sure libzmq always builds in Release mode * Renamed Request to Packet since Request and Reply are the same thing * Moved request fulfillment out of Packet and into RPCServer * Change request thread from sleep to condition variable * Remove non-blocking polling from ZMQ server code. Receive now blocks and terminates properly without sleeping. This change significantly improves script speed. * Move scripting files to dist/ instead of src/ * C++ code review changes for jroweboy [skip ci] * Python code review changes for jroweboy [skip ci] * Add docstrings and tests to citra.py [skip ci] * Add host OS check for libzmq build * Revert "Add host OS check for libzmq build" * Fixed a hang when emulation is stopped and restarted due to improper destruction order of ZMQ objects [skip ci] * Add scripting directory to archive packaging [skip ci] * Specify C/CXX compiler variables on MinGW build * Only specify compiler on Linux mingw * Use gcc and g++ on Windows mingw * Specify generator for mingw * Don't specify toolchain on windows mingw * Changed citra.py to support Python 3 instead of Python 2 * Fix bug where RPC wouldn't restart after Stop/Start emulation * Added copyright to headers and reorganized includes and forward declarations
2018-09-11 21:00:12 +01:00
}
}; // namespace RPC