Compare commits
22 Commits
3ba4171da3
...
c9ec524db1
Author | SHA1 | Date |
---|---|---|
BodgeMaster | c9ec524db1 | |
BodgeMaster | 73ae58e522 | |
BodgeMaster | acc19ae100 | |
BodgeMaster | 149285c357 | |
BodgeMaster | 0c92bdf8fd | |
BodgeMaster | 86f1ef596f | |
BodgeMaster | 027f324f03 | |
BodgeMaster | 7a2c1d7d57 | |
BodgeMaster | 6fecb2cdb7 | |
BodgeMaster | e882a09099 | |
BodgeMaster | 748c91c375 | |
BodgeMaster | f5d85da98c | |
BodgeMaster | 396b9673fd | |
BodgeMaster | 68fbf3ae20 | |
BodgeMaster | 4363432025 | |
BodgeMaster | 5400790e78 | |
BodgeMaster | c7dd5471dd | |
BodgeMaster | 8048dc8891 | |
BodgeMaster | a1f16e6f6b | |
Shwoomple | cb7b5ddba7 | |
Shwoomple | e0648720bb | |
Shwoomple | ebcf436a18 |
|
@ -258,5 +258,66 @@ namespace CLI {
|
|||
// argument is not present, but this is not an error -> false, NOT_PRESENT, ""
|
||||
else return ErrorOr<std::string>(false, ErrorCodes::NOT_PRESENT, std::string(""));
|
||||
}
|
||||
//std::string ArgumentsParser::getUsage();
|
||||
|
||||
std::string ArgumentsParser::getUsage(){
|
||||
std::string usageString = "";
|
||||
if (this->description != "") {
|
||||
usageString += "Help: " + this->programName + "\n\n\t" + this->description + "\n\n";
|
||||
}
|
||||
usageString += "Usage: " + this->programName + " ";
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "[-";
|
||||
}
|
||||
|
||||
for(const auto& [key, value]: this->flagsByShortName){
|
||||
usageString.push_back(key);
|
||||
}
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "] ";
|
||||
}
|
||||
|
||||
for(const auto& [key, value]: this->optionsByShortName){
|
||||
usageString += "[-";
|
||||
usageString.push_back(key);
|
||||
usageString += " " + value->placeholder + "] ";
|
||||
}
|
||||
|
||||
for(const auto& argument: this->arguments){
|
||||
usageString += argument.placeholder + " ";
|
||||
}
|
||||
|
||||
usageString.push_back('\n');
|
||||
|
||||
if(!this->flagsByShortName.empty()){
|
||||
usageString += "\nFlags:\n";
|
||||
|
||||
for(const auto& [key, value]: this->flagsByShortName){
|
||||
usageString += "\t-";
|
||||
usageString.push_back(key);
|
||||
usageString += ", --" + value->longName + "\n\t\t" + value->description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!this->optionsByShortName.empty()){
|
||||
usageString += "\nOptions:\n";
|
||||
|
||||
for(const auto& [key, value]: this->optionsByShortName){
|
||||
usageString += "\t-";
|
||||
usageString.push_back(key);
|
||||
usageString += " " + value->placeholder + ", --" + value->longName + "=" + value->placeholder + "\n\t\t" + value->description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!this->arguments.empty()){
|
||||
usageString += "\nArguments:\n";
|
||||
|
||||
for(const auto& argument: this->arguments){
|
||||
usageString += "\t" + argument.placeholder + "\n\t\t" + argument.description + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return usageString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright 2022, FOSS-VG Developers and Contributers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, version 3.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied
|
||||
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// version 3 along with this program.
|
||||
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "error.hpp"
|
||||
|
||||
namespace CLI {
|
||||
|
||||
struct Flag {
|
||||
char shortName;
|
||||
std::string longName;
|
||||
// used for automatic usage generation
|
||||
std::string description;
|
||||
|
||||
bool present;
|
||||
|
||||
Flag();
|
||||
Flag(char shortName, std::string longName, std::string description);
|
||||
};
|
||||
|
||||
struct Option {
|
||||
char shortName;
|
||||
std::string longName;
|
||||
// used for automatic usage generation
|
||||
std::string description;
|
||||
std::string placeholder; // the "COUNT" in "ping [-c <COUNT>] <HOST>"
|
||||
|
||||
bool present;
|
||||
std::string value;
|
||||
|
||||
Option();
|
||||
Option(char shortName, std::string longName, std::string placeholder, std::string description);
|
||||
};
|
||||
|
||||
struct Argument {
|
||||
// used for automatic usage generation
|
||||
std::string description;
|
||||
std::string placeholder; // the "HOST" in "ping [-c <COUNT>] <HOST>"
|
||||
|
||||
bool present;
|
||||
std::string value;
|
||||
|
||||
Argument();
|
||||
Argument(std::string placeholder, std::string description);
|
||||
};
|
||||
|
||||
class ArgumentsParser {
|
||||
private:
|
||||
std::map<char, Flag*> flagsByShortName;
|
||||
std::map<std::string, Flag*> flagsByLongName;
|
||||
std::map<char, Option*> optionsByShortName;
|
||||
std::map<std::string, Option*> optionsByLongName;
|
||||
std::vector<Argument> arguments;
|
||||
std::string description;
|
||||
std::string additionalInfo;
|
||||
|
||||
public:
|
||||
std::string programName;
|
||||
bool wrongUsage;
|
||||
std::vector<std::string> wrongUsageMessages;
|
||||
|
||||
// using int here bc that's how main() is defined
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments);
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description);
|
||||
ArgumentsParser(int argc, const char* const argv[], std::vector<Flag> flags, std::vector<Option> options, std::vector<Argument> arguments, std::string description, std::string additionalInfo);
|
||||
~ArgumentsParser();
|
||||
|
||||
ErrorOr<bool> getFlag(char shortName);
|
||||
ErrorOr<bool> getFlag(std::string longName);
|
||||
ErrorOr<std::string> getArgument(std::vector<CLI::Argument>::size_type position);
|
||||
ErrorOr<std::string> getOption(char shortName);
|
||||
ErrorOr<std::string> getOption(std::string longName);
|
||||
|
||||
std::string getUsage();
|
||||
};
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
int main() {
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "CLI argument parser tests" << std::endl;
|
||||
std::cout << "CLI argument parsing tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
// Valid parameter test ############################################
|
||||
|
@ -636,5 +636,115 @@ int main() {
|
|||
delete[] tooManyArgumentsTestParameterList;
|
||||
std::cout << "Passed too many arguments test." << std::endl;
|
||||
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
std::cout << "CLI argument parser help tests" << std::endl;
|
||||
std::cout << "################################################################################" << std::endl;
|
||||
|
||||
// normal usage with all types of CLI input ########################
|
||||
std::vector<CLI::Flag> helpTestFlags;
|
||||
helpTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
helpTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> helpTestOptions;
|
||||
helpTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
helpTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> helpTestArguments;
|
||||
helpTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
helpTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** helpTestCommand = new const char*[1];
|
||||
helpTestCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser helpTestParser = CLI::ArgumentsParser(1, helpTestCommand, helpTestFlags, helpTestOptions, helpTestArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(helpTestParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
std::cout << "Passed normal usage test." << std::endl;
|
||||
|
||||
// no description ##################################################
|
||||
std::vector<CLI::Flag> usageOnlyTestFlags;
|
||||
usageOnlyTestFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
usageOnlyTestFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> usageOnlyTestOptions;
|
||||
usageOnlyTestOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
usageOnlyTestOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> usageOnlyTestArguments;
|
||||
usageOnlyTestArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
usageOnlyTestArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** usageOnlyTestCommand = new const char*[1];
|
||||
usageOnlyTestCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser usageOnlyTestParser = CLI::ArgumentsParser(1, usageOnlyTestCommand, usageOnlyTestFlags, usageOnlyTestOptions, usageOnlyTestArguments);
|
||||
|
||||
ASSERT(usageOnlyTestParser.getUsage() == "Usage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
std::cout << "Passed normal usage without description test." << std::endl;
|
||||
|
||||
// no flags ########################################################
|
||||
std::vector<CLI::Flag> noFlagsFlags;
|
||||
|
||||
std::vector<CLI::Option> noFlagsOptions;
|
||||
noFlagsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
noFlagsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> noFlagsArguments;
|
||||
noFlagsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
noFlagsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** noFlagsCommand = new const char*[1];
|
||||
noFlagsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noFlagsParser = CLI::ArgumentsParser(1, noFlagsCommand, noFlagsFlags, noFlagsOptions, noFlagsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noFlagsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-b BANANA] [-c CORNHUBBBBB] WASH SHAKE \n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
|
||||
// no options ######################################################
|
||||
std::vector<CLI::Flag> noOptionsFlags;
|
||||
noOptionsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
noOptionsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> noOptionsOptions;
|
||||
|
||||
std::vector<CLI::Argument> noOptionsArguments;
|
||||
noOptionsArguments.push_back(CLI::Argument("WASH", "Number of times to wash my shark."));
|
||||
noOptionsArguments.push_back(CLI::Argument("SHAKE", "Number of times to shake fist at cloud."));
|
||||
|
||||
const char** noOptionsCommand = new const char*[1];
|
||||
noOptionsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noOptionsParser = CLI::ArgumentsParser(1, noOptionsCommand, noOptionsFlags, noOptionsOptions, noOptionsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noOptionsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] WASH SHAKE \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nArguments:\n\tWASH\n\t\tNumber of times to wash my shark.\n\tSHAKE\n\t\tNumber of times to shake fist at cloud.\n");
|
||||
|
||||
// no arguments ####################################################
|
||||
std::vector<CLI::Flag> noArgumentsFlags;
|
||||
noArgumentsFlags.push_back(CLI::Flag('a', "apple", "throws an apple on Newton's head."));
|
||||
noArgumentsFlags.push_back(CLI::Flag('y', "yapple", "throws an yapple on Newton's head."));
|
||||
|
||||
std::vector<CLI::Option> noArgumentsOptions;
|
||||
noArgumentsOptions.push_back(CLI::Option('b', "banana", "BANANA", "smack someone with a ripe banana."));
|
||||
noArgumentsOptions.push_back(CLI::Option('c', "corn", "CORNHUBBBBB", "visit cornhub."));
|
||||
|
||||
std::vector<CLI::Argument> noArgumentsArguments;
|
||||
|
||||
const char** noArgumentsCommand = new const char*[1];
|
||||
noArgumentsCommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noArgumentsParser = CLI::ArgumentsParser(1, noArgumentsCommand, noArgumentsFlags, noArgumentsOptions, noArgumentsArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noArgumentsParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator [-ay] [-b BANANA] [-c CORNHUBBBBB] \n\nFlags:\n\t-a, --apple\n\t\tthrows an apple on Newton's head.\n\t-y, --yapple\n\t\tthrows an yapple on Newton's head.\n\nOptions:\n\t-b BANANA, --banana=BANANA\n\t\tsmack someone with a ripe banana.\n\t-c CORNHUBBBBB, --corn=CORNHUBBBBB\n\t\tvisit cornhub.\n");
|
||||
std::cout << "Passed absent section usage test." << std::endl;
|
||||
|
||||
// no CLI input ####################################################
|
||||
std::vector<CLI::Flag> noCLIFlags;
|
||||
|
||||
std::vector<CLI::Option> noCLIOptions;
|
||||
|
||||
std::vector<CLI::Argument> noCLIArguments;
|
||||
|
||||
const char** noCLICommand = new const char*[1];
|
||||
noCLICommand[0] = "universecreator";
|
||||
CLI::ArgumentsParser noCLIParser = CLI::ArgumentsParser(1, noCLICommand, noCLIFlags, noCLIOptions, noCLIArguments, "Create a universe with a banana and an apple.");
|
||||
|
||||
ASSERT(noCLIParser.getUsage() == "Help: universecreator\n\n\tCreate a universe with a banana and an apple.\n\nUsage: universecreator \n");
|
||||
std::cout << "Passed no CLI input usage test." << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <cstdint>
|
||||
#include <cctype>
|
||||
#include <sockpp/tcp_acceptor.h>
|
||||
#include <sockpp/tcp6_acceptor.h>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <csignal>
|
||||
|
@ -40,8 +41,11 @@ int64_t mtu = 1500;
|
|||
std::string host;
|
||||
in_port_t port;
|
||||
sockpp::tcp_socket* tcpSocket;
|
||||
sockpp::tcp6_socket* tcp6Socket;
|
||||
sockpp::tcp_acceptor tcpAcceptor;
|
||||
sockpp::tcp6_acceptor tcp6Acceptor;
|
||||
std::mutex tcpSocketMutex;
|
||||
std::mutex tcp6SocketMutex;
|
||||
std::mutex consoleMutex;
|
||||
// used for coordinated graceful exit across threads
|
||||
bool exitProgram = false;
|
||||
|
@ -50,12 +54,20 @@ void signalHandler(int signal) {
|
|||
exitProgram = true;
|
||||
// if still waiting for incoming connection, stop waiting
|
||||
tcpAcceptor.shutdown();
|
||||
tcp6Acceptor.shutdown();
|
||||
// tell sockpp to close TCP socket if open because it blocks when trying
|
||||
// to read and there is no data
|
||||
if (*tcpSocket) {
|
||||
|
||||
if (tcpSocket != nullptr && *tcpSocket) {
|
||||
// Intentionally not using the mutex here
|
||||
std::cout << "test\n";
|
||||
tcpSocket->shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (tcp6Socket != nullptr && *tcp6Socket) {
|
||||
// Intentionally not using the mutex here
|
||||
tcp6Socket->shutdown(SHUT_RD);
|
||||
}
|
||||
//TODO: figure out if - and how - this applies to UDP
|
||||
|
||||
// Priority is to finish up all unfinished business that can be finished up.
|
||||
|
@ -64,32 +76,71 @@ void signalHandler(int signal) {
|
|||
consoleMutex.lock();
|
||||
std::cerr << "Received signal " << signal << ", shutting down." << std::endl;
|
||||
consoleMutex.unlock();
|
||||
std::exit(signal);
|
||||
}
|
||||
|
||||
void readFromTCPSocket(sockpp::tcp_socket* socket, int64_t mtu) {
|
||||
ssize_t numBytes;
|
||||
uint8_t buffer[mtu];
|
||||
tcpSocketMutex.lock();
|
||||
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
||||
tcpSocketMutex.unlock();
|
||||
consoleMutex.lock();
|
||||
for (ssize_t i=0; i<numBytes; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
||||
}
|
||||
std::cout.flush();
|
||||
consoleMutex.unlock();
|
||||
tcpSocketMutex.lock();
|
||||
}
|
||||
ssize_t numBytes;
|
||||
uint8_t buffer[mtu];
|
||||
tcpSocketMutex.lock();
|
||||
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
||||
tcpSocketMutex.unlock();
|
||||
consoleMutex.lock();
|
||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||
for (ssize_t i=0; i<numBytes; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
||||
}
|
||||
std::cout.flush();
|
||||
consoleMutex.unlock();
|
||||
tcpSocketMutex.lock();
|
||||
}
|
||||
tcpSocketMutex.unlock();
|
||||
consoleMutex.lock();
|
||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||
consoleMutex.unlock();
|
||||
}
|
||||
|
||||
void readFromTCP6Socket(sockpp::tcp6_socket* socket, int64_t mtu){
|
||||
ssize_t numBytes;
|
||||
uint8_t buffer[mtu];
|
||||
tcp6SocketMutex.lock();
|
||||
while (!exitProgram && (numBytes = socket->read(buffer, sizeof(buffer))) > 0) {
|
||||
tcp6SocketMutex.unlock();
|
||||
consoleMutex.lock();
|
||||
for (ssize_t i=0; i<numBytes; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i];
|
||||
}
|
||||
std::cout.flush();
|
||||
consoleMutex.unlock();
|
||||
tcp6SocketMutex.lock();
|
||||
}
|
||||
tcp6SocketMutex.unlock();
|
||||
consoleMutex.lock();
|
||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||
consoleMutex.unlock();
|
||||
}
|
||||
|
||||
void writeToTCPSocket(sockpp::tcp_socket* socket){
|
||||
while (!exitProgram) {
|
||||
//TODO: Implement locking/unlocking/threading shenanigans
|
||||
}
|
||||
consoleMutex.lock();
|
||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||
consoleMutex.unlock();
|
||||
}
|
||||
|
||||
void writeToTCP6Socket(sockpp::tcp6_socket* socket){
|
||||
while (!exitProgram) {
|
||||
//TODO: Implement locking/unlocking/threading shenanigans
|
||||
}
|
||||
consoleMutex.lock();
|
||||
std::cerr << std::endl << "Connection closed." << std::endl;
|
||||
consoleMutex.unlock();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
|
||||
std::vector<CLI::Flag> flags;
|
||||
flags.push_back(CLI::Flag('4', "ipv4", "use IPv4, defaults to both when -4 and -6 are omitted, otherwise uses what is specified"));
|
||||
|
@ -98,84 +149,142 @@ int main(int argc, char* argv[]){
|
|||
flags.push_back(CLI::Flag('u', "udp", "use UDP, defaults to both when -t and -u are omitted, otherwise uses what is specified"));
|
||||
flags.push_back(CLI::Flag('n', "no-color", "disable coloring the output (intended for terminals that don't work well with color escape sequences)"));
|
||||
flags.push_back(CLI::Flag('e', "echo-back", "echo input back to stdout"));
|
||||
flags.push_back(CLI::Flag('h', "help", "print this information and exit"));
|
||||
flags.push_back(CLI::Flag('l', "license", "print license information and exit"));
|
||||
|
||||
std::vector<CLI::Option> options;
|
||||
options.push_back(CLI::Option('c', "connect", "HOST", "connect to HOST, listen for incoming connections if omitted"));
|
||||
options.push_back(CLI::Option('m', "mtu-optimize", "MTU", "Optimize for a specific maximum transfer unit by reading MTU bytes at a time."));
|
||||
options.push_back(CLI::Option(
|
||||
'p', "print-prefixes", "TCPv4i:UDPv4i:TCPv6i:UDPv6i:TCPv4o:UDPv4o:TCPv6o:UDPv6o",
|
||||
"override default prefixes for output (defaults to spaces + coloring the output or \"t4:u4:t6:u6:T4:U4:T6:U6\" in no-color mode)"
|
||||
'p', "print-prefixes", "TCPin:UDPin:TCPout:UDPout",
|
||||
"override default prefixes for output (defaults to spaces + coloring the output or \"t:u:T:U\" in no-color mode)"
|
||||
));
|
||||
options.push_back(CLI::Option(
|
||||
'i', "input-prefixes", "TCP:UDP:IPv4:IPv6",
|
||||
"override default prefixes for input (defaults to \"t:u:4:6\")"
|
||||
'i', "input-prefixes", "TCP:UDP",
|
||||
"override default prefixes for input (defaults to \"t:u\")"
|
||||
));
|
||||
|
||||
std::vector<CLI::Argument> arguments;
|
||||
arguments.push_back(CLI::Argument("PORT", "the port to use"));
|
||||
|
||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments);
|
||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary tcp/udp connections in hex format.");
|
||||
|
||||
if (cliParser.getFlag("help").value){
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (cliParser.getFlag("license").value){
|
||||
std::cout
|
||||
<< "Copyright 2022, FOSS-VG Developers and Contributers\n"
|
||||
<< "\n"
|
||||
<< "Hexnet is part of the FOSS-VG development tool suite.\n"
|
||||
<< "\n"
|
||||
<< "This program is free software: you can redistribute it and/or modify it\n"
|
||||
<< "under the terms of the GNU Affero General Public License as published\n"
|
||||
<< "by the Free Software Foundation, version 3.\n"
|
||||
<< "\n"
|
||||
<< "This program is distributed in the hope that it will be useful,\n"
|
||||
<< "but WITHOUT ANY WARRANTY; without even the implied\n"
|
||||
<< "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
<< "See the GNU Affero General Public License for more details.\n"
|
||||
<< "\n"
|
||||
<< "You should have received a copy of the GNU Affero General Public License\n"
|
||||
<< "version 3 along with this program.\n"
|
||||
<< "If not, see https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||
<< std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (cliParser.wrongUsage) {
|
||||
//TODO: spit out usage information generated by the parser
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
return EXIT_USAGE;
|
||||
}
|
||||
if (cliParser.getFlag('4').value || cliParser.getFlag('6').value) {
|
||||
ipv4 = cliParser.getFlag('4').value;
|
||||
ipv6 = cliParser.getFlag('6').value;
|
||||
if (cliParser.getFlag("ipv4").value || cliParser.getFlag("ipv6").value) {
|
||||
ipv4 = cliParser.getFlag("ipv4").value;
|
||||
ipv6 = cliParser.getFlag("ipv4").value;
|
||||
}
|
||||
if (cliParser.getFlag('t').value || cliParser.getFlag('u').value) {
|
||||
tcp = cliParser.getFlag('t').value;
|
||||
udp = cliParser.getFlag('u').value;
|
||||
if (cliParser.getFlag("tcp").value || cliParser.getFlag("udp").value) {
|
||||
tcp = cliParser.getFlag("tcp").value;
|
||||
udp = cliParser.getFlag("udp").value;
|
||||
}
|
||||
if (cliParser.getOption('c').errorCode == ErrorCodes::NOT_PRESENT) {
|
||||
listenMode = true;
|
||||
}
|
||||
if (cliParser.getOption('m').errorCode == ErrorCodes::SUCCESS) {
|
||||
mtu = std::stol(cliParser.getOption('m').value);
|
||||
if (cliParser.getOption("mtu-optimize").errorCode == ErrorCodes::SUCCESS) {
|
||||
mtu = std::stol(cliParser.getOption("mtu-optimize").value);
|
||||
}
|
||||
host = cliParser.getOption('c').value;
|
||||
host = cliParser.getOption("connect").value;
|
||||
//FIXME: use a function that returns a fixed-width data type instead,
|
||||
// ensure that the given value is a valid port
|
||||
port = (in_port_t) std::stoi(cliParser.getArgument(0).value);
|
||||
|
||||
if (listenMode) {
|
||||
if (ipv6) {
|
||||
std::cerr << "IPv6 support is not implented yet." << std::endl;
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
}
|
||||
if (udp) {
|
||||
std::cerr << "UDP support is not implemented yet." << std::endl;
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
}
|
||||
std::cerr << "Listening on port " << port << "." << std::endl;
|
||||
|
||||
sockpp::socket_initializer socketInitializer;
|
||||
tcpAcceptor = sockpp::tcp_acceptor(port);
|
||||
if (ipv6) {
|
||||
//std::cerr << "IPv6 support is not implented yet." << std::endl;
|
||||
//return EXIT_UNIMPLEMENTED;
|
||||
std::cerr << "Listening on port " << port << "." << std::endl;
|
||||
sockpp::socket_initializer socketInitializer;
|
||||
tcp6Acceptor = sockpp::tcp6_acceptor(port);
|
||||
|
||||
if (!tcpAcceptor) {
|
||||
std::cerr << "Error while creating TCP acceptor: " << tcpAcceptor.last_error_str() << std::endl;
|
||||
return EXIT_RUNTIME;
|
||||
if(!tcp6Acceptor){
|
||||
std::cerr << "Error while creating TCP6 acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
sockpp::inet6_address peer;
|
||||
tcp6Socket = new sockpp::tcp6_socket();
|
||||
*tcp6Socket = tcp6Acceptor.accept(&peer);
|
||||
|
||||
std::cerr << "Incoming connection from " << peer << std::endl;
|
||||
|
||||
if (!(*tcp6Socket)) {
|
||||
std::cerr << "Error on incoming connection: " << tcp6Acceptor.last_error_str() << std::endl;
|
||||
delete tcp6Socket;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP6 = std::thread(readFromTCP6Socket, tcp6Socket, mtu);
|
||||
threadReadFromTCP6.join();
|
||||
|
||||
delete tcp6Socket;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
sockpp::inet_address peer;
|
||||
tcpSocket = new sockpp::tcp_socket();
|
||||
*tcpSocket = tcpAcceptor.accept(&peer);
|
||||
if(ipv4){
|
||||
std::cerr << "Listening on port " << port << "." << std::endl;
|
||||
|
||||
std::cerr << "Incoming connection from " << peer << std::endl;
|
||||
sockpp::socket_initializer socketInitializer;
|
||||
tcpAcceptor = sockpp::tcp_acceptor(port);
|
||||
|
||||
if (!tcpAcceptor) {
|
||||
std::cerr << "Error while creating TCP acceptor: " << tcpAcceptor.last_error_str() << std::endl;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
sockpp::inet_address peer;
|
||||
tcpSocket = new sockpp::tcp_socket();
|
||||
*tcpSocket = tcpAcceptor.accept(&peer);
|
||||
|
||||
std::cerr << "Incoming connection from " << peer << std::endl;
|
||||
|
||||
if (!(*tcpSocket)) {
|
||||
std::cerr << "Error on incoming connection: " << tcpAcceptor.last_error_str() << std::endl;
|
||||
delete tcpSocket;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP = std::thread(readFromTCPSocket, tcpSocket, mtu);
|
||||
threadReadFromTCP.join();
|
||||
|
||||
if (!(*tcpSocket)) {
|
||||
std::cerr << "Error on incoming connection: " << tcpAcceptor.last_error_str() << std::endl;
|
||||
delete tcpSocket;
|
||||
return EXIT_RUNTIME;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::thread threadReadTCP = std::thread(readFromTCPSocket, tcpSocket, mtu);
|
||||
threadReadTCP.join();
|
||||
|
||||
delete tcpSocket;
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
} else {
|
||||
std::cerr << "Client mode is not implemented yet." << std::endl;
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
|
|
Loading…
Reference in New Issue