Compare commits
6 Commits
89cfb9d850
...
b5c18cd0de
Author | SHA1 | Date |
---|---|---|
BodgeMaster | b5c18cd0de | |
BodgeMaster | a1ba08b7db | |
BodgeMaster | 1d7e98d0b3 | |
BodgeMaster | a7e07d2c3c | |
BodgeMaster | 7ae843039c | |
BodgeMaster | 5574cdb4bf |
|
@ -16,6 +16,7 @@
|
|||
//version 3 along with this program.
|
||||
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
@ -23,6 +24,10 @@
|
|||
#include <string>
|
||||
#include <sockpp/tcp_acceptor.h>
|
||||
#include <sockpp/tcp_connector.h>
|
||||
#include <sockpp/tcp6_acceptor.h>
|
||||
#include <sockpp/tcp6_connector.h>
|
||||
#include <sockpp/udp_socket.h>
|
||||
#include <sockpp/udp6_socket.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
@ -33,12 +38,22 @@
|
|||
#define EXIT_RUNTIME 1
|
||||
#define EXIT_USAGE 2
|
||||
#define EXIT_UNIMPLEMENTED 3
|
||||
#define EXIT_SIGNAL 4
|
||||
|
||||
// TCP v4 server
|
||||
sockpp::tcp_socket tcpSocket;
|
||||
sockpp::tcp_acceptor tcpAcceptor;
|
||||
// TCP v4 client
|
||||
sockpp::tcp_connector tcpConnector;
|
||||
// TCP v6 server
|
||||
sockpp::tcp6_socket tcp6Socket;
|
||||
sockpp::tcp6_acceptor tcp6Acceptor;
|
||||
// TCP v6 client
|
||||
sockpp::tcp6_connector tcp6Connector;
|
||||
// UDP v4 server and client
|
||||
sockpp::udp_socket udpSocket;
|
||||
// UDP v6 server and client
|
||||
sockpp::udp6_socket udp6Socket;
|
||||
|
||||
bool exitProgram = false;
|
||||
|
||||
|
@ -50,6 +65,44 @@ bool outgoing = false;
|
|||
std::string host;
|
||||
in_port_t port;
|
||||
|
||||
// This is probably bigger than the MTU on any given network.
|
||||
// This should allow us to read entire packets at once when they arrive
|
||||
// slowly enough to be read individually.
|
||||
const uint32_t bufferSize = 2048;
|
||||
uint8_t networkBuffer[bufferSize];
|
||||
|
||||
std::string readByteFromStdin() {
|
||||
std::string input = "";
|
||||
// read 2 characters from stdin
|
||||
char characterInput;
|
||||
bool readByte = false;
|
||||
uint16_t iterationsSinceLastInput = 0;
|
||||
while (input.length() < 2 && !exitProgram) {
|
||||
if (std::cin.good()) {
|
||||
std::cin.get(characterInput);
|
||||
readByte = true;
|
||||
} else {
|
||||
readByte = false;
|
||||
}
|
||||
// ignore space, tabs, and newlines
|
||||
if (readByte && characterInput!=' ' && characterInput!='\n' && characterInput!='\r' && characterInput!='\t') {
|
||||
input.push_back(characterInput);
|
||||
}
|
||||
|
||||
iterationsSinceLastInput++;
|
||||
if (readByte) {
|
||||
iterationsSinceLastInput = 0;
|
||||
}
|
||||
if (iterationsSinceLastInput>1024) {
|
||||
// prevent integer overflow
|
||||
iterationsSinceLastInput = 1024;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
}
|
||||
return exitProgram? "" : std::string(1, (char) std::stoi(input, nullptr, 16));
|
||||
}
|
||||
|
||||
void signalHandler(int signal) {
|
||||
// shut down gracefully
|
||||
exitProgram = true;
|
||||
|
@ -61,21 +114,136 @@ void signalHandler(int signal) {
|
|||
tcpSocket.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (tcpConnector) {
|
||||
tcpConnector.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (tcp6Socket) {
|
||||
tcp6Socket.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (tcp6Connector) {
|
||||
tcp6Connector.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (udpSocket) {
|
||||
udpSocket.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
if (udp6Socket) {
|
||||
udp6Socket.shutdown(SHUT_RD);
|
||||
}
|
||||
|
||||
std::cerr << "Received signal " << signal << ", bye!" << std::endl;
|
||||
std::exit(signal);
|
||||
std::exit(EXIT_SIGNAL);
|
||||
}
|
||||
|
||||
void readFromTCPSocket() {
|
||||
void readFromTCP() {
|
||||
ssize_t byteCount;
|
||||
uint8_t buffer[1536];
|
||||
while (!exitProgram && (outgoing? (byteCount = tcpConnector.read(buffer, sizeof(buffer))) > 0 : (byteCount = tcpSocket.read(buffer, sizeof(buffer))) > 0)) {
|
||||
while (!exitProgram && (outgoing? (byteCount = tcpConnector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcpSocket.read(networkBuffer, bufferSize)) > 0)) {
|
||||
for (ssize_t i=0; i<byteCount; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i] << " ";
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void writeToTCP() {
|
||||
while (!exitProgram) {
|
||||
if (outgoing) {
|
||||
if (tcpConnector.write(readByteFromStdin()) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
tcpConnector.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << tcpConnector.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (tcpSocket.write(readByteFromStdin()) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
tcpSocket.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << tcpSocket.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readFromTCP6() {
|
||||
ssize_t byteCount;
|
||||
while (!exitProgram && (outgoing? (byteCount = tcp6Connector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcp6Socket.read(networkBuffer, bufferSize)) > 0)) {
|
||||
for (ssize_t i=0; i<byteCount; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void writeToTCP6() {
|
||||
while (!exitProgram) {
|
||||
if (outgoing) {
|
||||
if (tcp6Connector.write(readByteFromStdin()) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
tcp6Connector.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << tcp6Connector.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (tcp6Socket.write(readByteFromStdin()) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
tcp6Socket.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << tcp6Socket.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readFromUDP() {
|
||||
ssize_t byteCount;
|
||||
sockpp::udp_socket::addr_t peer;
|
||||
while ((byteCount = udpSocket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
|
||||
std::cout << peer << ": ";
|
||||
for (ssize_t i=0; i<byteCount; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
|
||||
}
|
||||
std::cout << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void writeToUDP(sockpp::udp_socket::addr_t peer) {
|
||||
while (!exitProgram) {
|
||||
if (udpSocket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
udpSocket.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << udpSocket.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readFromUDP6() {
|
||||
ssize_t byteCount;
|
||||
sockpp::udp6_socket::addr_t peer;
|
||||
while ((byteCount = udp6Socket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
|
||||
std::cout << peer << ": ";
|
||||
for (ssize_t i=0; i<byteCount; i++) {
|
||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
|
||||
}
|
||||
std::cout << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void writeToUDP6(sockpp::udp6_socket::addr_t peer) {
|
||||
while (!exitProgram) {
|
||||
if (udp6Socket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
|
||||
exitProgram = true;
|
||||
udp6Socket.shutdown(SHUT_RD);
|
||||
std::cerr << "Error while sending data: " << udp6Socket.last_error_str() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
|
@ -90,11 +258,12 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
std::vector<CLI::Option> options;
|
||||
options.push_back(CLI::Option('c', "connect", "HOST", "make an outgoing connection to HOST instead of listening for an incoming connection"));
|
||||
options.push_back(CLI::Option('b', "bind", "ADDRESS", "(UDP only) bind to ADDRESS instead of localhost"));
|
||||
|
||||
std::vector<CLI::Argument> arguments;
|
||||
arguments.push_back(CLI::Argument("PORT", "the port to lsiten on (or connect to)"));
|
||||
|
||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary TCP/UDP connections in hex format", "Note: Make sure your terminal is set up so it doesn't buffer input and, if desired, disable input echoing.\n\tSomething like `stty -echo cbreak` should do but it will also disable some key combinations.");
|
||||
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary TCP/UDP connections in hex format", "Spaces, tabs, newlines, and carriage returns in the input are ignored.\n\tYou may want to disable input echoing using `stty -echo` (reenable using `stty echo`).\n\tNote that many terminals do line buffering on the input by default.");
|
||||
|
||||
if (cliParser.getFlag("help").value) {
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
|
@ -137,7 +306,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
if (!(ipv4 || ipv6) || (ipv4 && ipv6) || !(tcp || udp) || (tcp && udp)) {
|
||||
std::cout << cliParser.getUsage() << std::endl;
|
||||
std::cout << "Please specify which protocols to use (one of IPv4/IPv6, one of TCP/UDP)." << std::endl;
|
||||
return EXIT_USAGE;
|
||||
}
|
||||
|
||||
|
@ -155,26 +324,74 @@ int main(int argc, char* argv[]) {
|
|||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP = std::thread(readFromTCPSocket);
|
||||
//std::thread threadWriteToTCP = std::thread(writeToTCPSocket);
|
||||
std::thread threadReadFromTCP = std::thread(readFromTCP);
|
||||
std::thread threadWriteToTCP = std::thread(writeToTCP);
|
||||
|
||||
threadReadFromTCP.join();
|
||||
//threadWriteToTCP.join();
|
||||
threadWriteToTCP.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
// TCP v6 out
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
tcp6Connector = sockpp::tcp6_connector({host, port});
|
||||
if (!tcp6Connector) {
|
||||
std::cerr << "Error connecting to " << host << " on port " << port << std::endl;
|
||||
std::cerr << tcp6Connector.last_error_str() << std::endl;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
|
||||
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
|
||||
|
||||
threadReadFromTCP6.join();
|
||||
threadWriteToTCP6.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Connecting to " << host << " on port " << (int) port << " (UDP)..." << std::endl;
|
||||
std::cerr << "Talking to " << host << " on port " << (int) port << " (UDP)..." << std::endl;
|
||||
if (ipv4) {
|
||||
// UDP v4 out
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
if (!udpSocket) {
|
||||
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
|
||||
}
|
||||
// Btw: Did you know that UDP has no concept of a connection?
|
||||
sockpp::udp_socket::addr_t peer = sockpp::inet_address(host, port);
|
||||
if (!udpSocket.connect(peer)) {
|
||||
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
|
||||
std::cerr << udpSocket.last_error_str() << std::endl;
|
||||
}
|
||||
|
||||
std::thread threadReadFromUDP = std::thread(readFromUDP);
|
||||
std::thread threadWriteToUDP = std::thread(writeToUDP, peer);
|
||||
|
||||
threadReadFromUDP.join();
|
||||
threadWriteToUDP.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
// UDP v6 out
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
if (!udp6Socket) {
|
||||
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
|
||||
}
|
||||
// Btw: Did you know that UDP has no concept of a connection?
|
||||
sockpp::udp6_socket::addr_t peer = sockpp::inet6_address(host, port);
|
||||
if (!udp6Socket.connect(peer)) {
|
||||
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
|
||||
std::cerr << udp6Socket.last_error_str() << std::endl;
|
||||
}
|
||||
|
||||
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
|
||||
std::thread threadWriteToUDP6 = std::thread(writeToUDP6, peer);
|
||||
|
||||
threadReadFromUDP6.join();
|
||||
threadWriteToUDP6.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -196,26 +413,81 @@ int main(int argc, char* argv[]) {
|
|||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP = std::thread(readFromTCPSocket);
|
||||
//std::thread threadWriteToTCP = std::thread(writeToTCPSocket);
|
||||
std::thread threadReadFromTCP = std::thread(readFromTCP);
|
||||
std::thread threadWriteToTCP = std::thread(writeToTCP);
|
||||
|
||||
threadReadFromTCP.join();
|
||||
//threadWriteToTCP.join();
|
||||
threadWriteToTCP.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
// TCP v6 in
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
tcp6Acceptor = sockpp::tcp6_acceptor(port);
|
||||
if (!tcp6Acceptor) {
|
||||
std::cerr << "Error while creating TCP acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
sockpp::inet6_address peer;
|
||||
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;
|
||||
return EXIT_RUNTIME;
|
||||
}
|
||||
|
||||
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
|
||||
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
|
||||
|
||||
threadReadFromTCP6.join();
|
||||
threadWriteToTCP6.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Listening on port " << (int) port << " (UDP)..." << std::endl;
|
||||
std::string address = "localhost";
|
||||
if (cliParser.getOption("bind").errorCode != ErrorCodes::NOT_PRESENT) {
|
||||
address = cliParser.getOption("bind").value;
|
||||
}
|
||||
std::cerr << "Listening on " << address << " port " << (int) port << " (UDP)..." << std::endl;
|
||||
if (ipv4) {
|
||||
// UDP v4 in
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
if (!udpSocket) {
|
||||
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
|
||||
}
|
||||
if (!udpSocket.bind(sockpp::inet_address(address, port))) {
|
||||
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udpSocket.last_error_str() << std::endl;
|
||||
}
|
||||
|
||||
std::thread threadReadFromUDP = std::thread(readFromUDP);
|
||||
// Can't send bc we have no idea where to send to.
|
||||
//std::thread threadWriteToUDP = std::thread(writeToUDP);
|
||||
|
||||
threadReadFromUDP.join();
|
||||
//threadWriteToUDP.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
// UDP v6 in
|
||||
return EXIT_UNIMPLEMENTED;
|
||||
if (!udp6Socket) {
|
||||
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
|
||||
}
|
||||
if (!udp6Socket.bind(sockpp::inet6_address(address, port))) {
|
||||
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udp6Socket.last_error_str() << std::endl;
|
||||
}
|
||||
|
||||
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
|
||||
// Can't send bc we have no idea where to send to.
|
||||
//std::thread threadWriteToUDP6 = std::thread(writeToUDP6);
|
||||
|
||||
threadReadFromUDP6.join();
|
||||
//threadWriteToUDP6.join();
|
||||
|
||||
std::cout << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue