[Refactor] :O Machines now walk the earth!!
Old vfs_node was getting a bit big for its boots, trying to be a filesystem, network interface and the whole damn computer all at once. This server-side refactor introduces a 'Machine' class that rightfully owns the VFS, network services and other machine-state sh.t.
This commit is contained in:
parent
28804998d7
commit
59783d2408
@ -62,7 +62,7 @@ void ClientNetwork::disconnect(void) {
|
||||
_context_thread.join();
|
||||
}
|
||||
|
||||
/* Should be safe to close the socket no that thread is stoped <questionmark> */
|
||||
/* Should be safe to close the socket now that thread is stoped <questionmark> */
|
||||
if(is_connected()) {
|
||||
/* Close the socket. Causes outstanding async operations
|
||||
* in TcpConnection to compete with an error, which in return
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
#include "command_processor.h"
|
||||
#include <sol/types.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#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<std::string, vfs_node*>& world_vfs) :
|
||||
_world_vfs(world_vfs) {
|
||||
CommandProcessor::CommandProcessor(Machine* home_machine,
|
||||
std::map<std::string, Machine*>& 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<std::string>()) {
|
||||
return result.as<std::string>();
|
||||
@ -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<std::string>("");
|
||||
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<std::string>("");
|
||||
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: "<<target_ip<<"\n";
|
||||
ss<<"PORT\tSTATE\tSERVICE\n";
|
||||
for(auto const& [port, service_name] : target_root->services) {
|
||||
for(auto const& [port, service_name] : target_machine->services) {
|
||||
ss<<port<<"/tcp\t"<<"open\t"<<service_name<<"\n";
|
||||
}
|
||||
return ss.str();
|
||||
|
||||
@ -4,11 +4,12 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "machine.h"
|
||||
#include "vfs.h"
|
||||
|
||||
class CommandProcessor {
|
||||
public:
|
||||
CommandProcessor(vfs_node* home_vfs, std::map<std::string, vfs_node*>& world_vfs);
|
||||
CommandProcessor(Machine* home_machine, std::map<std::string, Machine*>& 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<std::string, vfs_node*>& _world_vfs;
|
||||
std::map<std::string, Machine*>& _world_machines;
|
||||
LuaProcessor* _lua;
|
||||
};
|
||||
|
||||
28
common/src/machine.h
Normal file
28
common/src/machine.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
#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<int, std::string> services;
|
||||
bool is_vfs_a_copy; /* Flag for CoW mechanism. */
|
||||
|
||||
/* TODO: We'll add hardware and sh.t here. */
|
||||
};
|
||||
@ -1,8 +1,10 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "vfs_manager.h"
|
||||
#include "machine_manager.h"
|
||||
#include "machine.h"
|
||||
#include "vfs.h"
|
||||
|
||||
/* Create a new node. */
|
||||
@ -33,13 +35,13 @@ 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;
|
||||
_vfs_template_root->read_only = true;
|
||||
bin->read_only = true;
|
||||
|
||||
/* Load all scripts from assets/scripts/bin into the VFS. */
|
||||
@ -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;
|
||||
}
|
||||
21
common/src/machine_manager.h
Normal file
21
common/src/machine_manager.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
@ -24,9 +24,6 @@ struct vfs_node {
|
||||
/* Directories. */
|
||||
vfs_child_map children;
|
||||
vfs_node* parent;
|
||||
|
||||
/* Services (for root nodes). */
|
||||
std::map<int, std::string> services;
|
||||
};
|
||||
|
||||
std::string get_full_path(vfs_node* node);
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#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>(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>(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);
|
||||
|
||||
@ -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<uint32_t, std::unique_ptr<Player>> _players;
|
||||
uint32_t _next_player_id = 1;
|
||||
|
||||
std::map<std::string, vfs_node*> _world_vfs; /* For NPC's. */
|
||||
VFSManager _vfs_manager;
|
||||
std::map<std::string, Machine*> _world_machines; /* For NPC's. */
|
||||
MachineManager _machine_manager;
|
||||
};
|
||||
|
||||
@ -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<std::string, vfs_node*>& world_vfs) :
|
||||
Player::Player(uint32_t new_id, Machine* home_machine,
|
||||
std::map<std::string, Machine*>& 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. */
|
||||
}
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#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<std::string, vfs_node*>& world_vfs);
|
||||
Player(uint32_t id, Machine* home_machine, std::map<std::string, Machine*>& world_machines);
|
||||
~Player(void);
|
||||
|
||||
uint32_t id;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user