diff --git a/ethercat.c b/ethercat.c index c5a550e..e2e4193 100644 --- a/ethercat.c +++ b/ethercat.c @@ -2,12 +2,14 @@ #include #include #include +#include +#include #include #include #include #include -#define DEVICE_NODE_TUN /dev/net/tun +#define DEVICE_NODE_TUN "/dev/net/tun" #define BUFFER_SIZE 0x1000 #define EXIT_SUCCESS 0 @@ -17,6 +19,27 @@ int file_descriptor; char buffer[BUFFER_SIZE]; struct ifreq ifr; +bool stop_now = false; +ssize_t read_size; +ssize_t write_size; +bool just_created_dup; +int stdin_dup; + +void stop() { + stop_now = true; +} + +void yeet(int fd) { + if (fcntl(fd, F_GETFD) != -1) { + close(fd); + } +} + +void recreate_dup() { + just_created_dup = true; + yeet(stdin_dup); + stdin_dup = dup(fileno(stdin)); +} int main(int argc, char** argv) { if (argc != 2) { @@ -27,32 +50,88 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } + if (freopen(NULL, "rb", stdin) == NULL) { + fprintf(stderr, "Failed to set stdin to binary mode: %i\n", errno); + return EXIT_RUNTIME; + } + + stdin_dup = dup(fileno(stdin)); + if (stdin_dup == -1) { + fprintf(stderr, "Failed to dup() stdin: %i\n", errno); + } + + if (freopen(NULL, "wb", stdout) == NULL) { + fprintf(stderr, "Failed to set stdout to binary mode: %i\n", errno); + return EXIT_RUNTIME; + } + + file_descriptor = open(DEVICE_NODE_TUN, O_RDWR | O_NONBLOCK); + if (file_descriptor == -1) { + fprintf(stderr, "Failed to open %s: %i\n", DEVICE_NODE_TUN, errno); + return EXIT_RUNTIME; + } + memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, argv[1], IFNAMSIZ); - file_descriptor = open("/dev/net/tun", O_RDWR); - if (file_descriptor == -1) { - fprintf(stderr, "An error occurred while trying to open DEVICE_NODE_TUN: %i\n", errno); - return EXIT_RUNTIME; - } - if (ioctl(file_descriptor, TUNSETIFF, &ifr) == -1) { fprintf(stderr, "An error occurred while trying to ioctl: %i\n", errno); close(file_descriptor); return EXIT_RUNTIME; } - //TODO: - // while input not EOF - // and the tap is still a valid device (it might go away) - // read from tap to stdout - // read from stdin to tap + signal(SIGINT, stop); + signal(SIGTERM, stop); + signal(SIGALRM, recreate_dup); - //TODO: signal handler for SIGINT (and SIGHUP? maybe others?) + ualarm(500000, 500000); - if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) { - close(file_descriptor); + while (fcntl(file_descriptor, F_GETFD) != -1 && !stop_now) { + read_size = read(file_descriptor, buffer, BUFFER_SIZE); + if (read_size == -1) { + fprintf(stderr, "Failed to read from tap: %i\n", errno); + yeet(file_descriptor); + return EXIT_RUNTIME; + } + for ( + write_size = 0; + read_size > 0 && !stop_now; + read_size = read_size - write_size + ) { + // using read_size as the amount of remaining bytes + write_size = write(fileno(stdout), buffer, read_size); + if (write_size == -1) { + fprintf(stderr, "Failed to write stdout: %i\n", errno); + yeet(file_descriptor); + return EXIT_RUNTIME; + } + } + just_created_dup = false; + read_size = read(stdin_dup, buffer, BUFFER_SIZE); + if (read_size == -1) { + fprintf(stderr, "Failed to read from stdin: %i\n", errno); + yeet(file_descriptor); + return EXIT_RUNTIME; + } + if (read_size == 0 && !just_created_dup) { + // probably EOF + break; + } + for ( + write_size = 0; + read_size > 0 && !stop_now; + read_size = read_size - write_size + ) { + write_size = write(file_descriptor, buffer, read_size); + if (write_size == -1) { + fprintf(stderr, "Failed to write stdout: %i\n", errno); + yeet(file_descriptor); + return EXIT_RUNTIME; + } + } } + + yeet(file_descriptor); return EXIT_SUCCESS; }