Compare commits

..

22 Commits

Author SHA1 Message Date
BodgeMaster c9ec524db1 test/nbt_size_helpers: Implement tests for valid input 2022-08-13 17:32:47 +02:00
BodgeMaster 73ae58e522 test/assert: Add line number to assertion failed message 2022-08-13 17:32:47 +02:00
BodgeMaster acc19ae100 lib/nbt: Change behavior of totalTagSize to treat encounters of compounds and lists as errors
I stumbled over this when writing the unit test. Previously, it would return
an error code but explicitly mark it as not being an error. This was intended
behavior but I decided to change it because I didn’t anticipate it when writing
the test.

Technically `ErrorOr<T>` can be used to pass any message alongside `T`,
but practically, it is reasonable to assume that the error code is
`ErrorCodes::SUCCESS` when `isError` is false. Therefore, this feature
should be really only used in the weirdest edge cases - if at all.
Even then, it is most likely still preferable to flag it as an error and
just hand the resulting `T` back using the long constructor
`ErrorOr<T>(bool, uint8_t, T)`.
2022-08-13 17:32:47 +02:00
BodgeMaster 149285c357 lib/nbt: Finish implementing containedDataLength, rename nextTagTotalSize->totalTagSize and nextTagDataLength->containedDataLength 2022-08-13 17:32:47 +02:00
BodgeMaster 0c92bdf8fd test/nbt_size_helpers: begin adding unit tests for lib/nbt's new nextTag size helpers 2022-08-13 17:32:47 +02:00
BodgeMaster 86f1ef596f lib/nbt: Begin implementing nextTagDataLength 2022-08-13 17:32:47 +02:00
BodgeMaster 027f324f03 lib/nbt: Fix a bug in nextTagTotalSize and significantly improve readability by removing redundant code 2022-08-13 17:32:47 +02:00
BodgeMaster 7a2c1d7d57 scripts/test: Clean old unit tests before building new ones to avoid confusion
if a unit test fails to build and old unit tests remain in place, this can
lead to confusion when the old test is run anyway.

"Why are some test cases missing?"
"Huh, it failed to build but passed?"
2022-08-13 17:32:47 +02:00
BodgeMaster 6fecb2cdb7 scripts/test/hexnet: Add license information
Yeah, I forgot it again -_-
2022-08-13 17:32:47 +02:00
BodgeMaster e882a09099 Build system: Improve output readability and prepare for script based unit tests 2022-08-13 17:32:47 +02:00
BodgeMaster 748c91c375 scripts/test: change unit test file names 2022-08-13 17:32:47 +02:00
BodgeMaster f5d85da98c lib/nbt: Move the functions for getting tag sizes into the helper namespace, give up on handling lists the same as all other tags
I tried dealing with lists in the same way as with other more basic tags
but came to the conclusion that this is most likely not feasible in the same
way that it is not feasible for compounds. It would require a mini-parser
that can deal with all sorts of tags (including nested lists and compounds).

Instead, an approach more similar to the recursion for compound tags will
be used (using its own function to deal with the missing tag headers ofc).
2022-08-13 17:32:47 +02:00
BodgeMaster 396b9673fd lib/nbt: Various minor fixes to get the program to compile properly 2022-08-13 17:32:47 +02:00
BodgeMaster 68fbf3ae20 lib/nbt: remove a function used to get the next tag type which introduced unnecessary complexity 2022-08-13 17:32:47 +02:00
BodgeMaster 4363432025 Environment: don't unset PROJECT_BASE_DIR which is needed for the aliases to work properly 2022-08-13 17:32:47 +02:00
BodgeMaster 5400790e78 test/nbt*: rename files, move byte tag object test from helper test file into its own file 2022-08-13 17:32:47 +02:00
BodgeMaster c7dd5471dd lib/nbt: Start implementing NBT validator 2022-08-13 17:32:47 +02:00
BodgeMaster 8048dc8891 tools/hexnet: Put the new usage generator to use and remove prefixes for IPv4 and IPv6
The prefixes were part of a planned feature but since a connection is
either IPv4 or IPv6 but never both, it would have been completely useless
to specify which to use. Instead, only TCP and UDP will need to be specified.
2022-08-12 12:30:55 +02:00
BodgeMaster a1f16e6f6b lib/cli: Fix the usage text generator not dealing well with absent sections 2022-08-12 11:59:42 +02:00
Shwoomple cb7b5ddba7 lib/cli: Add usage generator. 2022-08-12 13:35:56 +05:30
Shwoomple e0648720bb tools/hexnet: Implement ipv6 support. 2022-08-11 22:55:12 +05:30
Shwoomple ebcf436a18 lib/cli: delete duplicate header file. 2022-08-11 18:57:22 +05:30
4 changed files with 337 additions and 151 deletions

View File

@ -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;
}
}

View File

@ -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();
};
}

View File

@ -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;
}

View File

@ -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;