2021-02-10 23:25:56 -05:00
|
|
|
#include "modernize/sockets.h"
|
|
|
|
#include "libraries/user_input.h"
|
|
|
|
#include "libraries/osyncstream.h"
|
|
|
|
#include "libraries/terminal.h"
|
2021-02-11 02:26:38 -05:00
|
|
|
#include "libraries/json.hpp"
|
|
|
|
#include "project/server.h"
|
|
|
|
#include "project/client.h"
|
2021-02-12 03:19:18 -05:00
|
|
|
#include "project/metrics.h"
|
2021-02-11 02:40:29 -05:00
|
|
|
#include <chrono>
|
2021-02-11 02:26:38 -05:00
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2021-02-10 23:25:56 -05:00
|
|
|
|
2021-02-20 00:44:06 -05:00
|
|
|
#include <locale>
|
|
|
|
#include <codecvt>
|
|
|
|
#include <string>
|
|
|
|
|
2021-02-11 02:26:38 -05:00
|
|
|
using json = nlohmann::json;
|
2021-02-09 23:02:05 -05:00
|
|
|
|
2021-04-18 16:02:33 -04:00
|
|
|
std::mutex metrics_mutex {};
|
|
|
|
|
2021-02-10 16:32:59 -05:00
|
|
|
auto onClientConnected(networked& client)
|
2021-02-09 23:02:05 -05:00
|
|
|
{
|
|
|
|
sscout << "Accepted Client on Server.\n";
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
auto onClientMessaged(networked& client, std::string& message)
|
|
|
|
{
|
2021-02-20 00:44:06 -05:00
|
|
|
std::string commands[6] = {"date", "uptime", "vmstat", "netstat -ant", "who", "ps"};
|
2021-02-12 12:42:47 -05:00
|
|
|
auto badOperand = []() {sscout << "Invalid OPCode, Ignored.\n";};
|
2021-02-10 16:32:59 -05:00
|
|
|
try
|
|
|
|
{
|
|
|
|
int operation = std::stoi(message);
|
2021-02-20 00:44:06 -05:00
|
|
|
sscout << "Received OPCode " << operation << " from Client.\n";
|
2021-02-12 12:42:47 -05:00
|
|
|
if (math::is_between<0,7>(operation))
|
2021-02-12 12:46:36 -05:00
|
|
|
client.send_message(net::system(commands[operation-1]));
|
2021-02-12 12:42:47 -05:00
|
|
|
else
|
|
|
|
badOperand();
|
|
|
|
}catch(std::invalid_argument& invalid_number) { badOperand(); }
|
2021-02-09 23:02:05 -05:00
|
|
|
client.disconnect();
|
2021-02-20 00:44:06 -05:00
|
|
|
sscout << "Disconnected Client.\n";
|
2021-02-09 23:02:05 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-10 16:32:59 -05:00
|
|
|
auto get_ip_port(int mode)
|
2021-02-09 23:02:05 -05:00
|
|
|
{
|
2021-02-10 16:32:59 -05:00
|
|
|
std::string ipaddress{};
|
|
|
|
std::uint16_t port{};
|
|
|
|
if (mode == 1)
|
|
|
|
ipaddress = "0.0.0.0";
|
|
|
|
else
|
2021-02-12 03:19:18 -05:00
|
|
|
ipaddress = get_input<std::string>("Enter IP: ", "Invalid IP", ip_validator());
|
2021-02-20 00:44:06 -05:00
|
|
|
port = get_input<std::uint16_t>("Enter Port: ");
|
2021-02-10 16:32:59 -05:00
|
|
|
return std::make_tuple(mode == 1 ? "Server" : mode == 2 ? "Client" : "Unknown", ipaddress, port);
|
2021-02-09 23:02:05 -05:00
|
|
|
}
|
|
|
|
|
2021-02-10 16:32:59 -05:00
|
|
|
auto execute_as_client(std::string ipaddress, std::uint16_t port)
|
2021-02-09 23:02:05 -05:00
|
|
|
{
|
2021-02-12 03:19:18 -05:00
|
|
|
while(true)
|
2021-02-09 23:02:05 -05:00
|
|
|
{
|
2021-02-12 12:46:36 -05:00
|
|
|
auto operation = get_input<int>("Pick Command\n\t1. Date\n\t2. Uptime\n\t3. Memory Use\n\t4. Netstat\n\t5. Current Users\n\t6. Running Processes\n\t7. Exit\n:>", "Invalid Selection", math::is_between<0, 8>);
|
2021-02-12 03:19:18 -05:00
|
|
|
if (operation == 7)
|
|
|
|
break;
|
2021-04-18 18:20:30 -04:00
|
|
|
auto num_clients = get_input<int>("Enter number of clients. (1-100): ", "Invalid Amount", math::is_between<0, 101>);
|
2021-02-12 03:19:18 -05:00
|
|
|
std::vector<std::thread> threads{};
|
|
|
|
threads.reserve(num_clients);
|
|
|
|
metrics::job this_job{};
|
|
|
|
this_job.operation = operation;
|
|
|
|
this_job.client_metrics.reserve(num_clients);
|
2021-02-20 00:44:06 -05:00
|
|
|
auto failures = 0;
|
2021-02-12 03:19:18 -05:00
|
|
|
for(int i = 0; i < num_clients; ++i)
|
2021-02-09 23:02:05 -05:00
|
|
|
{
|
2021-02-12 03:19:18 -05:00
|
|
|
threads.emplace_back(std::thread([&]()
|
2021-02-13 21:43:49 -05:00
|
|
|
{
|
|
|
|
client net_client{};
|
|
|
|
metrics::time_tracker clock{};
|
|
|
|
//Callback
|
|
|
|
net_client.message_received += [&](std::string& message)
|
|
|
|
{
|
|
|
|
auto elapsed = clock.elapsed<double, std::milli>();
|
2021-04-18 16:02:33 -04:00
|
|
|
const std::lock_guard<std::mutex> lock(metrics_mutex);
|
2021-02-13 21:43:49 -05:00
|
|
|
auto client_num = this_job.client_metrics.size()+1;
|
|
|
|
//UX
|
|
|
|
sscout << client_num << math::numerical_suffix(client_num) << " client response\n"
|
2021-02-20 00:44:06 -05:00
|
|
|
<< message
|
|
|
|
<< "Round Trip Was " << elapsed.count() << " ms\n"
|
|
|
|
<< term::hr;
|
2021-02-13 21:43:49 -05:00
|
|
|
//Metrics
|
|
|
|
metrics::client_message client_metric{};
|
|
|
|
client_metric.client_number = client_num;
|
|
|
|
client_metric.trip_time = elapsed.count();
|
|
|
|
this_job.client_metrics.emplace_back(client_metric); //this isn't thread safe!
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
auto res = net_client.connect(ipaddress, port);
|
|
|
|
if (res.joinable())
|
|
|
|
{
|
|
|
|
net_client.send_message(std::to_string(operation));
|
|
|
|
res.join();
|
2021-02-20 00:44:06 -05:00
|
|
|
}else{
|
|
|
|
++failures;
|
2021-02-13 21:43:49 -05:00
|
|
|
}
|
|
|
|
}));
|
2021-02-12 03:19:18 -05:00
|
|
|
}
|
2021-02-20 00:44:06 -05:00
|
|
|
sscout << "Client setup complete.\n" << term::hr;
|
2021-02-12 03:19:18 -05:00
|
|
|
for(auto&& thread : threads)
|
|
|
|
thread.join();
|
2021-02-20 00:44:06 -05:00
|
|
|
if (failures)
|
|
|
|
sscout << failures << " client(s) failed to connect.";
|
2021-02-12 03:19:18 -05:00
|
|
|
metrics::job_metrics.emplace_back(this_job);
|
|
|
|
sscout << "Finished!\n";
|
2021-02-10 16:32:59 -05:00
|
|
|
}
|
2021-02-12 03:19:18 -05:00
|
|
|
json metrics_json{metrics::job_metrics};
|
2021-02-11 02:26:38 -05:00
|
|
|
std::ofstream metrics;
|
|
|
|
metrics.open ("metrics.json", std::ios::out | std::ios::trunc); //again, metrics data
|
|
|
|
metrics << metrics_json;
|
|
|
|
metrics.close();
|
2021-02-20 00:44:06 -05:00
|
|
|
sscout << "Metrics Saved to metrics.json\n";
|
2021-02-10 16:32:59 -05:00
|
|
|
}
|
|
|
|
|
2021-02-10 23:25:56 -05:00
|
|
|
int main() {
|
2021-02-20 00:44:06 -05:00
|
|
|
term::use_unicode();
|
2021-02-20 01:03:11 -05:00
|
|
|
sscout
|
|
|
|
<< "┌───────────╖\n"
|
|
|
|
<< "│ Project 1 ║\n"
|
|
|
|
<< "╘═══════════╝\n";
|
2021-02-20 00:44:06 -05:00
|
|
|
|
2021-02-20 01:03:11 -05:00
|
|
|
sscout
|
|
|
|
<< "┌────────────────────╖\n"
|
|
|
|
<< "│ Riley Strickland ║\n"
|
|
|
|
<< "│ Jacob Jerris ║\n"
|
|
|
|
<< "│ Jacqueline Shrader ║\n"
|
|
|
|
<< "╘════════════════════╝\n";
|
2021-02-20 00:44:06 -05:00
|
|
|
|
2021-02-10 16:32:59 -05:00
|
|
|
net::prologue();
|
2021-02-10 23:25:56 -05:00
|
|
|
const auto mode = get_input<int>("Select Mode\n\t1. Server\n\t2. Client\n>:", "Invalid Choice!",
|
|
|
|
math::is_between<0, 3>);
|
2021-02-12 03:19:18 -05:00
|
|
|
auto[prefix, ipaddress, port] = get_ip_port(mode);
|
2021-02-20 00:44:06 -05:00
|
|
|
sscout << prefix << " selected, ip/port is " << ipaddress << ":" << port << ".\n";
|
2021-02-12 03:19:18 -05:00
|
|
|
if (mode == 2) {
|
|
|
|
execute_as_client(ipaddress, port);
|
|
|
|
} else {
|
|
|
|
server net_server{};
|
|
|
|
net_server.client_connected += onClientConnected;
|
|
|
|
net_server.message_received += onClientMessaged;
|
|
|
|
net_server.listen(ipaddress, port).join();
|
2021-02-09 23:02:05 -05:00
|
|
|
}
|
2021-02-12 03:19:18 -05:00
|
|
|
net::epilogue();
|
2021-02-20 00:44:06 -05:00
|
|
|
|
2021-02-20 01:03:11 -05:00
|
|
|
sscout
|
|
|
|
<< "┌────────────────────╖\n"
|
|
|
|
<< "│ Thanks for using ║\n"
|
|
|
|
<< "╘════════════════════╝\n";
|
2021-02-20 00:44:06 -05:00
|
|
|
|
2021-02-12 03:19:18 -05:00
|
|
|
return 0;
|
2021-04-18 16:02:33 -04:00
|
|
|
}
|