diff --git a/client/src/client_network.cpp b/client/src/client_network.cpp index 0b8e5ac..44ea328 100644 --- a/client/src/client_network.cpp +++ b/client/src/client_network.cpp @@ -62,7 +62,7 @@ void ClientNetwork::disconnect(void) { _context_thread.join(); } - /* Should be safe to close the socket no that thread is stoped */ + /* Should be safe to close the socket now that thread is stoped */ if(is_connected()) { /* Close the socket. Causes outstanding async operations * in TcpConnection to compete with an error, which in return diff --git a/common/src/command_processor.cpp b/common/src/command_processor.cpp index 81ed008..45dd038 100644 --- a/common/src/command_processor.cpp +++ b/common/src/command_processor.cpp @@ -1,18 +1,19 @@ -#include "command_processor.h" #include #include +#include "command_processor.h" #include "vfs.h" #include "lua_processor.h" -#include "vfs_manager.h" +#include "machine_manager.h" +#include "machine.h" -CommandProcessor::CommandProcessor(vfs_node* home_vfs, - std::map& world_vfs) : - _world_vfs(world_vfs) { +CommandProcessor::CommandProcessor(Machine* home_machine, + std::map& world_machines) : + _home_machine(home_machine), + _session_machine(home_machine), + _world_machines(world_machines) { _lua = new LuaProcessor(); - home_vfs_root = home_vfs; - session_vfs_root = home_vfs_root; - _current_dir = session_vfs_root; + _current_dir = _session_machine->vfs_root; } CommandProcessor::~CommandProcessor(void) { @@ -41,15 +42,12 @@ std::string CommandProcessor::process_command(const std::string& command) { args.push_back(arg); } - /* Search for script in the /bin directory. */ + /* Search for script in the /bin directory of the current session machine. */ std::string script_filename = command_name + ".lua"; - vfs_node* root = _current_dir; - while(root->parent != nullptr) { - root = root->parent; - } + vfs_node* root = _session_machine->vfs_root; if(root->children.count("bin") && root->children["bin"]->children.count(script_filename)) { vfs_node* script_node = root->children["bin"]->children[script_filename]; - bool is_remote = (session_vfs_root != home_vfs_root); + bool is_remote = (_session_machine != _home_machine); sol::object result = _lua->execute(script_node->content, _current_dir, args, is_remote); if(result.is()) { return result.as(); @@ -101,9 +99,9 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) { if(_current_dir->read_only) { std::string remote_ip = ""; /* Check if we are on a known remote system. */ - if(session_vfs_root != home_vfs_root) { - for(auto const& [ip, root_node] : _world_vfs) { - if(root_node == session_vfs_root) { + if(!_session_machine->is_vfs_a_copy) { + for(auto const& [ip, machine] : _world_machines) { + if(machine == _session_machine) { remote_ip = ip; break; } @@ -111,19 +109,29 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) { } if(!remote_ip.empty()) { - /* CoW for a remote system. */ + /* This machine is using a shared VFS. Copy it! ;) */ fprintf(stderr, "CoW: Write attempt on read-only remote system '%s'." "Creating persistant copy.\n", remote_ip.c_str()); std::string original_path = get_full_path(_current_dir); - vfs_node* new_root = copy_vfs_node(session_vfs_root, nullptr); - make_vfs_writable(new_root); - _world_vfs[remote_ip] = new_root; - session_vfs_root = new_root; - _current_dir = find_node_by_path(session_vfs_root, original_path); - if(!_current_dir) { _current_dir = session_vfs_root; } /* Just in case. */ + /* Copy the sh.t out of the VFS. */ + vfs_node* new_vfs_root = copy_vfs_node(_session_machine->vfs_root, nullptr); + make_vfs_writable(new_vfs_root); + + /* Create the new machine that will hold the copied VFS. */ + auto* new_machine = new Machine(_session_machine->id, _session_machine->hostname); + new_machine->vfs_root = new_vfs_root; + new_machine->services = _session_machine->services; + new_machine->is_vfs_a_copy = true; /* Mark as copy. */ + + /* Update the world map and the current session. */ + _world_machines[remote_ip] = new_machine; + _session_machine = new_machine; + + /* Update _current_dir to point to the equivalent dir in the new VFS. */ + _current_dir = find_node_by_path(_session_machine->vfs_root, original_path); + if(!_current_dir) { _current_dir = _session_machine->vfs_root; } } else { - /* If not a known remote system, i.e, player's own /bin, deny. */ - return "Permission denied: Filesystem is read-only."; + return "Permission denied: Filesystem is read-only and not part of the world."; } } } @@ -163,9 +171,9 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) { return ""; /* Success. */ } else if(action_name == "ssh") { std::string target_ip = action["target"].get_or(""); - if(_world_vfs.count(target_ip)) { - session_vfs_root = _world_vfs[target_ip]; - _current_dir = session_vfs_root; + if(_world_machines.count(target_ip)) { + _session_machine = _world_machines[target_ip]; + _current_dir = _session_machine->vfs_root; return "Connected to " + target_ip; } return "ssh: Could not resolve hostname " + target_ip + ": Name or service not known"; @@ -187,26 +195,26 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) { } return ""; /* Success. */ } else if(action_name == "disconnect") { - session_vfs_root = home_vfs_root; - _current_dir = home_vfs_root; + _session_machine = _home_machine; + _current_dir = _home_machine->vfs_root; return "Connection closed."; } else if(action_name == "close_terminal") { return "__CLOSE_CONNECTION__"; } else if(action_name == "scan") { std::string target_ip = action["target"].get_or(""); - if(!_world_vfs.count(target_ip)) { + if(!_world_machines.count(target_ip)) { return std::string("nmap: Could not resolve host: ") + target_ip; } - vfs_node* target_root = _world_vfs[target_ip]; - if(target_root->services.empty()) { + Machine* target_machine = _world_machines[target_ip]; + if(target_machine->services.empty()) { return std::string("No open ports for ") + target_ip; } std::stringstream ss; ss<<"Host: "<services) { + for(auto const& [port, service_name] : target_machine->services) { ss< #include +#include "machine.h" #include "vfs.h" class CommandProcessor { public: - CommandProcessor(vfs_node* home_vfs, std::map& world_vfs); + CommandProcessor(Machine* home_machine, std::map& world_machines); ~CommandProcessor(void); std::string process_command(const std::string& command); @@ -16,9 +17,9 @@ public: private: std::string _handle_vfs_action(sol::table action); - vfs_node* home_vfs_root; - vfs_node* session_vfs_root; + Machine* _home_machine; + Machine* _session_machine; vfs_node* _current_dir; - std::map& _world_vfs; + std::map& _world_machines; LuaProcessor* _lua; }; diff --git a/common/src/machine.h b/common/src/machine.h new file mode 100644 index 0000000..2ce282e --- /dev/null +++ b/common/src/machine.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include "vfs.h" + + +class Machine { +public: + Machine(uint32_t id, std::string hostname) : + id(id), + hostname(std::move(hostname)), + vfs_root(nullptr), + is_vfs_a_copy(false) {} + + /* TODO: Implement recursive deletion of vfs_root. */ + ~Machine(void); /* Clean up VFS tree. */ + + uint32_t id; + std::string hostname; + vfs_node* vfs_root; + std::map services; + bool is_vfs_a_copy; /* Flag for CoW mechanism. */ + + /* TODO: We'll add hardware and sh.t here. */ +}; diff --git a/common/src/vfs_manager.cpp b/common/src/machine_manager.cpp similarity index 74% rename from common/src/vfs_manager.cpp rename to common/src/machine_manager.cpp index 948829b..6b3e47d 100644 --- a/common/src/vfs_manager.cpp +++ b/common/src/machine_manager.cpp @@ -1,8 +1,10 @@ #include #include #include +#include -#include "vfs_manager.h" +#include "machine_manager.h" +#include "machine.h" #include "vfs.h" /* Create a new node. */ @@ -33,14 +35,14 @@ vfs_node* copy_vfs_node(vfs_node* original, vfs_node* new_parent) { return new_copy; } -VFSManager::VFSManager(void) { +MachineManager::MachineManager(void) { /* Create template VFS that holds shared, read-only directories. */ - _vfs_root = new_node("/", DIR_NODE, nullptr); - vfs_node* bin = new_node("bin", DIR_NODE, _vfs_root); - _vfs_root->children["bin"] = bin; + _vfs_template_root = new_node("/", DIR_NODE, nullptr); + vfs_node* bin = new_node("bin", DIR_NODE, _vfs_template_root); + _vfs_template_root->children["bin"] = bin; - _vfs_root->read_only = true; - bin->read_only = true; + _vfs_template_root->read_only = true; + bin->read_only = true; /* Load all scripts from assets/scripts/bin into the VFS. */ const std::string path = "assets/scripts/bin"; @@ -58,12 +60,15 @@ VFSManager::VFSManager(void) { } } -VFSManager::~VFSManager(void) { +MachineManager::~MachineManager(void) { /* TODO: Implement recursive deletion of all created VFS nodes.*/ //delete _vfs_root; } -vfs_node* VFSManager::create_vfs(const std::string& system_type) { +Machine* MachineManager::create_machine(uint32_t id, const std::string& hostname, + const std::string& system_type) { + auto* new_machine = new Machine(id, hostname); + vfs_node* root = new_node("/", DIR_NODE, nullptr); /* Create directories for this specific VFS. */ @@ -75,10 +80,13 @@ vfs_node* VFSManager::create_vfs(const std::string& system_type) { user->children["readme.txt"] = readme; /* Link to the shared directories from the template. */ - root->children["bin"] = copy_vfs_node(_vfs_root->children["bin"], root); + root->children["bin"] = copy_vfs_node(_vfs_template_root->children["bin"], root); + + /* Assign the VFS to the new machine. */ + new_machine->vfs_root = root; /* Default services. All machines have SSH currently. */ - root->services[22] = "SSH v1.2"; + new_machine->services[22] = "SSH v1.2"; if(system_type == "npc") { vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root); @@ -87,5 +95,5 @@ vfs_node* VFSManager::create_vfs(const std::string& system_type) { } - return root; + return new_machine; } diff --git a/common/src/machine_manager.h b/common/src/machine_manager.h new file mode 100644 index 0000000..2db9d84 --- /dev/null +++ b/common/src/machine_manager.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "machine.h" +#include "vfs.h" + +/* Recursive copy function for our Copy-on-Write behaviour. */ +vfs_node* copy_vfs_node(vfs_node* original, vfs_node* new_parent); + +class MachineManager { +public: + MachineManager(void); + ~MachineManager(void); /* TODO: Implement recursive VFS deletion. */ + + Machine* create_machine(uint32_t id, const std::string& hostname, + const std::string& system_type); +private: + vfs_node* _vfs_template_root; +}; + diff --git a/common/src/vfs.h b/common/src/vfs.h index 21d7a00..4e3d704 100644 --- a/common/src/vfs.h +++ b/common/src/vfs.h @@ -24,9 +24,6 @@ struct vfs_node { /* Directories. */ vfs_child_map children; vfs_node* parent; - - /* Services (for root nodes). */ - std::map services; }; std::string get_full_path(vfs_node* node); diff --git a/common/src/vfs_manager.h b/common/src/vfs_manager.h deleted file mode 100644 index 9f8b8fd..0000000 --- a/common/src/vfs_manager.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "vfs.h" - -/* Recursive copy function for our Copy-on-Write behaviour. */ -vfs_node* copy_vfs_node(vfs_node* original, vfs_node* new_parent); - -class VFSManager { -public: - VFSManager(void); - ~VFSManager(void); /* TODO: Implement recursive VFS deletion. */ - - vfs_node* create_vfs(const std::string& system_type); -private: - vfs_node* _vfs_root; -}; - diff --git a/server/src/network_manager.cpp b/server/src/network_manager.cpp index e9ff3fc..da7067a 100644 --- a/server/src/network_manager.cpp +++ b/server/src/network_manager.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "network_manager.h" @@ -9,19 +10,20 @@ #include "asio/ip/tcp.hpp" #include "command_processor.h" #include "player.h" +#include "machine.h" #include "net/tcp_connection.h" #include "vfs.h" NetworkManager::NetworkManager(void) : _acceptor(_io_context) { - /* VFS setup. */ - _world_vfs["8.8.8.8"] = _vfs_manager.create_vfs("npc"); - _world_vfs["10.0.2.15"] = _vfs_manager.create_vfs("npc"); + /* World setup. */ + _world_machines["8.8.8.8"] = _machine_manager.create_machine(1000, "dns.google", "npc"); + _world_machines["10.0.2.15"] = _machine_manager.create_machine(1001, "corp.internal", "npc"); /* Specific npc services. */ - _world_vfs["8.8.8.8"]->services[80] = "HTTPD v2.4"; - _world_vfs["10.0.2.15"]->services[21] = "FTPd v3.0"; + _world_machines["8.8.8.8"]->services[80] = "HTTPD v2.4"; + _world_machines["10.0.2.15"]->services[21] = "FTPd v3.0"; - fprintf(stderr, "Created world with %zu networks\n", _world_vfs.size()); + fprintf(stderr, "Created world with %zu networks\n", _world_machines.size()); } NetworkManager::~NetworkManager(void) { stop(); } @@ -64,7 +66,9 @@ void NetworkManager::start_accept(void) { /* Create a new player for this connection. */ uint32_t player_id = _next_player_id++; - auto new_player = std::make_unique(player_id, _vfs_manager, _world_vfs); + Machine* player_machine = _machine_manager.create_machine(player_id, "player.home", + "player"); + auto new_player = std::make_unique(player_id, player_machine, _world_machines); Player* new_player_ptr = new_player.get(); _players[player_id] = std::move(new_player); new_connection->set_id(player_id); diff --git a/server/src/network_manager.h b/server/src/network_manager.h index 6f57077..c0e5a0e 100644 --- a/server/src/network_manager.h +++ b/server/src/network_manager.h @@ -10,7 +10,7 @@ #include "asio/io_context.hpp" #include "net/tcp_connection.h" #include "player.h" -#include "vfs_manager.h" +#include "machine_manager.h" class NetworkManager { public: @@ -34,6 +34,6 @@ private: std::unordered_map> _players; uint32_t _next_player_id = 1; - std::map _world_vfs; /* For NPC's. */ - VFSManager _vfs_manager; + std::map _world_machines; /* For NPC's. */ + MachineManager _machine_manager; }; diff --git a/server/src/player.cpp b/server/src/player.cpp index 4bb95a7..43667eb 100644 --- a/server/src/player.cpp +++ b/server/src/player.cpp @@ -1,17 +1,15 @@ #include "player.h" #include "command_processor.h" +#include "machine.h" -Player::Player(uint32_t new_id, VFSManager& vfs_manager, - std::map& world_vfs) : +Player::Player(uint32_t new_id, Machine* home_machine, + std::map& world_machines) : id(new_id) { - vfs_node* player_vfs = vfs_manager.create_vfs("player"); - cmd_processor = new CommandProcessor(player_vfs, world_vfs); + cmd_processor = new CommandProcessor(home_machine, world_machines); } Player::~Player(void) { if(cmd_processor) { delete cmd_processor; } - - /* TODO: The VFSManager should handle deleting the player_vfs_root. */ } diff --git a/server/src/player.h b/server/src/player.h index fe71397..3900875 100644 --- a/server/src/player.h +++ b/server/src/player.h @@ -1,16 +1,15 @@ #pragma once #include +#include +#include #include "command_processor.h" -#include "vfs.h" -#include "vfs_manager.h" - -class CommandProcessor; +#include "machine.h" class Player { public: - Player(uint32_t id, VFSManager& vfs_manager, std::map& world_vfs); + Player(uint32_t id, Machine* home_machine, std::map& world_machines); ~Player(void); uint32_t id;