diff --git a/ethercat.c b/ethercat.c index 4cbbcc8..df54db9 100644 --- a/ethercat.c +++ b/ethercat.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -10,20 +11,25 @@ #include #define DEVICE_NODE_TUN "/dev/net/tun" +// This number mus be larger than the MTU. #define BUFFER_SIZE 0x1000 +#define NUMBER_OF_POLLED_FILES 2 +#define POLL_TIMEOUT 100 #define EXIT_SUCCESS 0 #define EXIT_USAGE 1 #define EXIT_RUNTIME 2 int file_descriptor; +int poll_result; 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; +// 0 file_descriptor +// 1 stdin +struct pollfd polls_pls[NUMBER_OF_POLLED_FILES]; void stop() { stop_now = true; @@ -35,12 +41,6 @@ void yeet(int 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) { fprintf(stderr, "Usage: %s TAP\n", argv[0]); @@ -55,18 +55,15 @@ int main(int argc, char** argv) { return EXIT_RUNTIME; } - stdin_dup = dup(fileno(stdin)); - if (stdin_dup == -1) { - fprintf(stderr, "Failed to dup() stdin: %s\n", strerror(errno)); - return EXIT_RUNTIME; - } + polls_pls[1].fd = fileno(stdin); + polls_pls[1].events = POLLIN; if (freopen(NULL, "wb", stdout) == NULL) { fprintf(stderr, "Failed to set stdout to binary mode: %s\n", strerror(errno)); return EXIT_RUNTIME; } - file_descriptor = open(DEVICE_NODE_TUN, O_RDWR | O_NONBLOCK); + file_descriptor = open(DEVICE_NODE_TUN, O_RDWR); if (file_descriptor == -1) { fprintf(stderr, "Failed to open %s: %s\n", DEVICE_NODE_TUN, strerror(errno)); return EXIT_RUNTIME; @@ -82,51 +79,64 @@ int main(int argc, char** argv) { return EXIT_RUNTIME; } + polls_pls[0].fd = file_descriptor; + polls_pls[0].events = POLLIN; + signal(SIGINT, stop); signal(SIGTERM, stop); - signal(SIGALRM, recreate_dup); - - ualarm(500000, 500000); 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: %s\n", strerror(errno)); + poll_result = poll(polls_pls, NUMBER_OF_POLLED_FILES, POLL_TIMEOUT); + if (poll_result == -1 && errno != EINTR) { + fprintf(stderr, "An error occurred while polling: %s\n", strerror(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: %s\n", strerror(errno)); + if (poll_result == 0) { + continue; + } + + if (polls_pls[0].revents & POLLIN) { + read_size = read(file_descriptor, buffer, BUFFER_SIZE); + if (read_size == -1) { + fprintf(stderr, "Failed to read from tap: %s\n", strerror(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: %s\n", strerror(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: %s\n", strerror(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 - ) { + + if (polls_pls[1].revents & POLLIN) { + read_size = read(fileno(stdin), buffer, BUFFER_SIZE); + if (read_size == -1) { + fprintf(stderr, "Failed to read from stdin: %s\n", strerror(errno)); + yeet(file_descriptor); + return EXIT_RUNTIME; + } + if (read_size == 0) { + //TODO: is this still how to check for eof with poll? + // or is there another way? + break; + } + + //TODO: How to properly deal with partial reads? + + // accepts exactly one complete packet (Ethernet Frame?) at a time write_size = write(file_descriptor, buffer, read_size); if (write_size == -1) { - fprintf(stderr, "Failed to write stdout: %s\n", strerror(errno)); + fprintf(stderr, "Failed to write tap: %s\n", strerror(errno)); yeet(file_descriptor); return EXIT_RUNTIME; }