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); | ||||
|     } | ||||
| 
 | ||||
|     std::cerr << "Received signal " << signal << ", bye!" << std::endl; | ||||
|     std::exit(signal); | ||||
|     if (tcpConnector) { | ||||
|         tcpConnector.shutdown(SHUT_RD); | ||||
|     } | ||||
| 
 | ||||
| void readFromTCPSocket() { | ||||
|     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(EXIT_SIGNAL); | ||||
| } | ||||
| 
 | ||||
| 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