From 68a3039598dc418b0fd25e971746bee31e28b3ea Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sun, 11 Dec 2022 10:56:56 -0800 Subject: Move boost asio socket interface to socketif_t This reduces dependencies on config.h in sim.h --- riscv/interactive.cc | 73 +++++++++------------------------------------------ riscv/riscv.mk.in | 4 ++- riscv/sim.cc | 25 +++++++++++++----- riscv/sim.h | 21 +++------------ riscv/socketif.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ riscv/socketif.h | 32 +++++++++++++++++++++++ spike_main/spike.cc | 27 +------------------ 7 files changed, 144 insertions(+), 112 deletions(-) create mode 100644 riscv/socketif.cc create mode 100644 riscv/socketif.h diff --git a/riscv/interactive.cc b/riscv/interactive.cc index 251a1ca..02ba227 100644 --- a/riscv/interactive.cc +++ b/riscv/interactive.cc @@ -1,10 +1,12 @@ // See LICENSE for license details. +#include "config.h" #include "sim.h" #include "decode.h" #include "disasm.h" #include "mmu.h" #include "vector_unit.h" +#include "socketif.h" #include #include #include @@ -247,58 +249,6 @@ static std::string readline(int fd) return s.substr(initial_s_len); } -#ifdef HAVE_BOOST_ASIO -// read input command string -std::string sim_t::rin(boost::asio::streambuf *bout_ptr) { - std::string s; - if (acceptor_ptr) { // if we are listening, get commands from socket - try { - socket_ptr.reset(new boost::asio::ip::tcp::socket(*io_service_ptr)); - acceptor_ptr->accept(*socket_ptr); // wait for someone to open connection - boost::asio::streambuf buf; - boost::asio::read_until(*socket_ptr, buf, "\n"); // wait for command - s = boost::asio::buffer_cast(buf.data()); - boost::erase_all(s, "\r"); // get rid off any cr and lf - boost::erase_all(s, "\n"); - // The socket client is a web server and it appends the IP of the computer - // that sent the command from its web browser. - - // For now, erase the IP if it is there. - boost::regex re(" ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}" - "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$"); - s = boost::regex_replace(s, re, (std::string)""); - - // TODO: check the IP against the IP used to upload RISC-V source files - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - // output goes to socket - sout_.rdbuf(bout_ptr); - } else { // if we are not listening on a socket, get commands from terminal - s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin - // output goes to stderr - sout_.rdbuf(std::cerr.rdbuf()); - } - return s; -} - -// write sout_ to socket (via bout) -void sim_t::wout(boost::asio::streambuf *bout_ptr) { - if (!cmd_file && acceptor_ptr) { // only if we are not getting command inputs from a file - // and if a socket has been created - try { - boost::system::error_code ignored_error; - boost::asio::write(*socket_ptr, *bout_ptr, boost::asio::transfer_all(), ignored_error); - socket_ptr->close(); // close the socket after each command input/ouput - // This is need to in order to make the socket interface - // acessible by HTTP GET via a socket client in a web server. - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - } -} -#endif - void sim_t::interactive() { typedef void (sim_t::*interactive_func)(const std::string&, const std::vector&); @@ -330,9 +280,6 @@ void sim_t::interactive() while (!done()) { -#ifdef HAVE_BOOST_ASIO - boost::asio::streambuf bout; // socket output -#endif std::string s; char cmd_str[MAX_CMD_STR+1]; // only used for following fscanf // first get commands from file, if cmd_file has been set @@ -345,10 +292,14 @@ void sim_t::interactive() // when there are no commands left from file or if there was no file from the beginning cmd_file = NULL; // mark file pointer as being not valid, so any method can test this easily #ifdef HAVE_BOOST_ASIO - s = rin(&bout); // get command string from socket or terminal -#else - s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin + if (socketif) { + s = socketif->rin(sout_); // get command string from socket or terminal + } + else #endif + { + s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin + } } std::stringstream ss(s); @@ -360,7 +311,8 @@ void sim_t::interactive() set_procs_debug(true); step(1); #ifdef HAVE_BOOST_ASIO - wout(&bout); // socket output, if required + if (socketif) + socketif->wout(); // socket output, if required #endif continue; } @@ -380,7 +332,8 @@ void sim_t::interactive() out << "Bad or missing arguments for command " << cmd << std::endl; } #ifdef HAVE_BOOST_ASIO - wout(&bout); // socket output, if required + if (socketif) + socketif->wout(); // socket output, if required #endif } ctrlc_pressed = false; diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 1eee43a..efe2bd0 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -42,7 +42,8 @@ riscv_hdrs = \ jtag_dtm.h \ csrs.h \ triggers.h \ - vector_unit.h + vector_unit.h \ + socketif.h \ riscv_install_hdrs = \ abstract_device.h \ @@ -96,6 +97,7 @@ riscv_srcs = \ csrs.cc \ triggers.cc \ vector_unit.cc \ + socketif.cc \ $(riscv_gen_srcs) \ riscv_test_srcs = diff --git a/riscv/sim.cc b/riscv/sim.cc index bb1d76b..8a65797 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -1,5 +1,6 @@ // See LICENSE for license details. +#include "config.h" #include "sim.h" #include "mmu.h" #include "dts.h" @@ -7,6 +8,7 @@ #include "byteorder.h" #include "platform.h" #include "libfdt.h" +#include "socketif.h" #include #include #include @@ -35,9 +37,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, const debug_module_config_t &dm_config, const char *log_path, bool dtb_enabled, const char *dtb_file, -#ifdef HAVE_BOOST_ASIO - boost::asio::io_service *io_service_ptr, boost::asio::ip::tcp::acceptor *acceptor_ptr, // option -s -#endif + bool socket_enabled, FILE *cmd_file) // needed for command line option --cmd : htif_t(args), isa(cfg->isa(), cfg->priv()), @@ -49,10 +49,6 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, dtb_enabled(dtb_enabled), log_file(log_path), cmd_file(cmd_file), -#ifdef HAVE_BOOST_ASIO - io_service_ptr(io_service_ptr), // socket interface - acceptor_ptr(acceptor_ptr), -#endif sout_(nullptr), current_step(0), current_proc(0), @@ -74,6 +70,21 @@ sim_t::sim_t(const cfg_t *cfg, bool halted, debug_module.add_device(&bus); + socketif = NULL; +#ifdef HAVE_BOOST_ASIO + if (socket_enabled) { + socketif = new socketif_t(); + } +#else + if (socket_enabled) { + fputs("Socket support requires compilation with boost asio; " + "please rebuild the riscv-isa-sim project using " + "\"configure --with-boost-asio\".\n", + stderr); + abort(); + } +#endif + #ifndef RISCV_ENABLE_DUAL_ENDIAN if (cfg->endianness != memif_endianness_little) { fputs("Big-endian support has not been prroperly enabled; " diff --git a/riscv/sim.h b/riscv/sim.h index 8ca06fe..b3b5d40 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -4,13 +4,6 @@ #define _RISCV_SIM_H #include "config.h" - -#ifdef HAVE_BOOST_ASIO -#include -#include -#include -#endif - #include "cfg.h" #include "debug_module.h" #include "devices.h" @@ -27,6 +20,7 @@ class mmu_t; class remote_bitbang_t; +class socketif_t; // this class encapsulates the processors and memory in a RISC-V machine. class sim_t : public htif_t, public simif_t @@ -38,9 +32,7 @@ public: const std::vector& args, const debug_module_config_t &dm_config, const char *log_path, bool dtb_enabled, const char *dtb_file, -#ifdef HAVE_BOOST_ASIO - boost::asio::io_service *io_service_ptr_ctor, boost::asio::ip::tcp::acceptor *acceptor_ptr_ctor, // option -s -#endif + bool socket_enabled, FILE *cmd_file); // needed for command line option --cmd ~sim_t(); @@ -89,14 +81,7 @@ private: FILE *cmd_file; // pointer to debug command input file -#ifdef HAVE_BOOST_ASIO - // the following are needed for command socket interface - boost::asio::io_service *io_service_ptr; - boost::asio::ip::tcp::acceptor *acceptor_ptr; - std::unique_ptr socket_ptr; - std::string rin(boost::asio::streambuf *bout_ptr); // read input command string - void wout(boost::asio::streambuf *bout_ptr); // write output to socket -#endif + socketif_t *socketif; std::ostream sout_; // used for socket and terminal interface processor_t* get_core(const std::string& i); diff --git a/riscv/socketif.cc b/riscv/socketif.cc new file mode 100644 index 0000000..0884752 --- /dev/null +++ b/riscv/socketif.cc @@ -0,0 +1,74 @@ +// See LICENSE for license details. + +#include "socketif.h" + +#ifdef HAVE_BOOST_ASIO + +#include + +socketif_t::socketif_t() +{ + try { // create socket server + using boost::asio::ip::tcp; + io_service_ptr = new boost::asio::io_service; + acceptor_ptr = new tcp::acceptor(*io_service_ptr, tcp::endpoint(tcp::v4(), 0)); + // acceptor is created passing argument port=0, so O.S. will choose a free port + std::string name = boost::asio::ip::host_name(); + std::cout << "Listening for debug commands on " << name.substr(0,name.find('.')) + << " port " << acceptor_ptr->local_endpoint().port() << " ." << std::endl; + // at the end, add space and some other character for convenience of javascript .split(" ") + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + exit(-1); + } +} + +socketif_t::~socketif_t() +{ + delete io_service_ptr; + delete acceptor_ptr; +} + +// read input command string +std::string socketif_t::rin(std::ostream &sout_) +{ + std::string s; + try { + socket_ptr.reset(new boost::asio::ip::tcp::socket(*io_service_ptr)); + acceptor_ptr->accept(*socket_ptr); // wait for someone to open connection + boost::asio::streambuf buf; + boost::asio::read_until(*socket_ptr, buf, "\n"); // wait for command + s = boost::asio::buffer_cast(buf.data()); + boost::erase_all(s, "\r"); // get rid off any cr and lf + boost::erase_all(s, "\n"); + // The socket client is a web server and it appends the IP of the computer + // that sent the command from its web browser. + + // For now, erase the IP if it is there. + boost::regex re(" ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}" + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$"); + s = boost::regex_replace(s, re, (std::string)""); + + // TODO: check the IP against the IP used to upload RISC-V source files + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + } + // output goes to socket + sout_.rdbuf(&bout); + return s; +} + +// write sout_ to socket (via bout) +void socketif_t::wout() { + try { + boost::system::error_code ignored_error; + boost::asio::write(*socket_ptr, bout, boost::asio::transfer_all(), ignored_error); + socket_ptr->close(); // close the socket after each command input/ouput + // This is need to in order to make the socket interface + // acessible by HTTP GET via a socket client in a web server. + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + } +} + +#endif diff --git a/riscv/socketif.h b/riscv/socketif.h new file mode 100644 index 0000000..7ce9142 --- /dev/null +++ b/riscv/socketif.h @@ -0,0 +1,32 @@ +// See LICENSE for license details. + +#ifndef _RISCV_SOCKETIF_H +#define _RISCV_SOCKETIF_H + +#include "config.h" + +#ifdef HAVE_BOOST_ASIO + +#include +#include +#include + +class socketif_t +{ +public: + socketif_t(); + ~socketif_t(); + + std::string rin(std::ostream &sout_); // read input command string + void wout(); // write output to socket + +private: + // the following are needed for command socket interface + boost::asio::io_service *io_service_ptr; + boost::asio::ip::tcp::acceptor *acceptor_ptr; + std::unique_ptr socket_ptr; + boost::asio::streambuf bout; +}; + +#endif +#endif diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 5815761..f0d6920 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -497,29 +497,6 @@ int main(int argc, char** argv) } } -#ifdef HAVE_BOOST_ASIO - boost::asio::io_service *io_service_ptr = NULL; // needed for socket command interface option -s - boost::asio::ip::tcp::acceptor *acceptor_ptr = NULL; - if (socket) { // if command line option -s is set - try - { // create socket server - using boost::asio::ip::tcp; - io_service_ptr = new boost::asio::io_service; - acceptor_ptr = new tcp::acceptor(*io_service_ptr, tcp::endpoint(tcp::v4(), 0)); - // aceptor is created passing argument port=0, so O.S. will choose a free port - std::string name = boost::asio::ip::host_name(); - std::cout << "Listening for debug commands on " << name.substr(0,name.find('.')) - << " port " << acceptor_ptr->local_endpoint().port() << " ." << std::endl; - // at the end, add space and some other character for convenience of javascript .split(" ") - } - catch (std::exception& e) - { - std::cerr << e.what() << std::endl; - exit(-1); - } - } -#endif - if (cfg.explicit_hartids) { if (nprocs.overridden() && (nprocs() != cfg.nprocs())) { std::cerr << "Number of specified hartids (" @@ -542,9 +519,7 @@ int main(int argc, char** argv) sim_t s(&cfg, halted, mems, plugin_devices, htif_args, dm_config, log_path, dtb_enabled, dtb_file, -#ifdef HAVE_BOOST_ASIO - io_service_ptr, acceptor_ptr, -#endif + socket, cmd_file); std::unique_ptr remote_bitbang((remote_bitbang_t *) NULL); std::unique_ptr jtag_dtm( -- cgit v1.1