summaryrefslogtreecommitdiffstats
path: root/src/bidilink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bidilink.c')
-rw-r--r--src/bidilink.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/bidilink.c b/src/bidilink.c
new file mode 100644
index 0000000..3f421bf
--- /dev/null
+++ b/src/bidilink.c
@@ -0,0 +1,222 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <inttypes.h>
+
+#include "stream.h"
+
+#define BUFSIZE (64*1024)
+
+volatile int quit = 0;
+
+static void signal_handler(int s) {
+ quit = 1;
+}
+
+static void usage(FILE *f, const char *argv0) {
+ fprintf(f, "%s [STREAM1] [STREAM2]\n", argv0);
+}
+
+static int read_fd(struct stream *s, void *buf, size_t *buf_fill, size_t *buf_index) {
+ ssize_t r;
+ assert(s && buf && buf_fill && buf_index);
+
+ if ((r = read(s->input_fd, buf, BUFSIZE)) <= 0) {
+
+ if (r == 0)
+ return 0;
+
+ fprintf(stderr, "Failure to read(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ *buf_fill = r;
+ *buf_index = 0;
+ return 1;
+}
+
+
+static int write_fd(struct stream *s, void *buf, size_t *buf_fill, size_t *buf_index) {
+ ssize_t r;
+ assert(s && buf && buf_fill && buf_index);
+
+ if ((r = write(s->output_fd, buf+*buf_index, *buf_fill)) < 0) {
+
+ if (r == EPIPE)
+ return 0;
+
+ fprintf(stderr, "Failure to write(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ *buf_fill -= r;
+ *buf_index += r;
+ return 1;
+}
+
+const char *byte_str(uint64_t l) {
+ static char c[32];
+
+ if (l <= 1024)
+ snprintf(c, sizeof(c), "%llu B", l);
+ else if (l <= 1024*1024)
+ snprintf(c, sizeof(c), "%llu KB", l/1024);
+ else if (l <= 1024*1024*1024)
+ snprintf(c, sizeof(c), "%llu MB", l/1024/1024);
+ else
+ snprintf(c, sizeof(c), "%llu GB", l/1024/1024/1024);
+
+ return c;
+};
+
+int main(int argc, char *argv[]) {
+ struct stream *a = NULL, *b = NULL;
+
+ void *ab_buf = NULL, *ba_buf = NULL;
+ size_t ab_buf_fill = 0, ab_buf_index = 0,
+ ba_buf_fill = 0, ba_buf_index = 0;
+
+ uint64_t ab_count = 0, ba_count = 0;
+
+ int a_readable = 0,
+ a_writable = 0,
+ b_readable = 0,
+ b_writable = 0,
+ verbose = 0;
+
+ int ret = -1;
+ int ai;
+
+ if (argc < 2) {
+ usage(stderr, argv[0]);
+ ret = 0;
+ goto finish;
+ }
+
+ signal(SIGINT, signal_handler);
+ siginterrupt(SIGINT, 1);
+ signal(SIGTERM, signal_handler);
+ siginterrupt(SIGTERM, 1);
+ signal(SIGPIPE, SIG_IGN);
+
+ ai = 1;
+
+ if (!strcmp(argv[ai], "-v")) {
+ verbose = 1;
+ ai++;
+ }
+
+ if (!(a = stream_open(argv[ai++])))
+ goto finish;
+
+ if (!(b = stream_open(argc > ai ? argv[ai++] : NULL)))
+ goto finish;
+
+ ab_buf = malloc(BUFSIZE);
+ assert(ab_buf);
+ ba_buf = malloc(BUFSIZE);
+ assert(ba_buf);
+
+ for (;;) {
+ fd_set ifds, ofds;
+
+
+ FD_ZERO(&ifds);
+
+ if (!a_readable)
+ FD_SET(a->input_fd, &ifds);
+ if (!b_readable)
+ FD_SET(b->input_fd, &ifds);
+
+ FD_ZERO(&ofds);
+
+ if (!a_writable)
+ FD_SET(a->output_fd, &ofds);
+ if (!b_writable)
+ FD_SET(b->output_fd, &ofds);
+
+ if (select(FD_SETSIZE, &ifds, &ofds, NULL, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+
+ fprintf(stderr, "select() failed: %s\n", strerror(errno));
+ ret = -1;
+ break;
+ }
+
+ if (FD_ISSET(a->input_fd, &ifds))
+ a_readable = 1;
+ if (FD_ISSET(b->input_fd, &ifds))
+ b_readable = 1;
+
+ if (FD_ISSET(a->output_fd, &ofds))
+ a_writable = 1;
+ if (FD_ISSET(b->output_fd, &ofds))
+ b_writable = 1;
+
+
+ if (!ab_buf_fill && a_readable && b_writable) {
+ int r;
+ if ((r = read_fd(a, ab_buf, &ab_buf_fill, &ab_buf_index)) <= 0) {
+ ret = r < 0 ? 1 : 0;
+ break;
+ }
+ a_readable = 0;
+
+ ab_count += ab_buf_fill;
+ }
+
+ if (ab_buf_fill && b_writable) {
+ int r;
+ if ((r = write_fd(b, ab_buf, &ab_buf_fill, &ab_buf_index)) <= 0) {
+ ret = r < 0 ? 1 : 0;
+ break;
+ }
+ b_writable = 0;
+ }
+
+ if (!ba_buf_fill && b_readable && a_writable) {
+ int r;
+ if ((r = read_fd(b, ba_buf, &ba_buf_fill, &ba_buf_index)) <= 0) {
+ ret = r < 0 ? 1 : 0;
+ break;
+ }
+ b_readable = 0;
+ ba_count += ba_buf_fill;
+ }
+
+ if (ba_buf_fill && a_writable) {
+ int r;
+ if ((r = write_fd(a, ba_buf, &ba_buf_fill, &ba_buf_index)) <= 0) {
+ ret = r < 0 ? 1 : 0;
+ break;
+ }
+ a_writable = 0;
+ }
+
+ if (verbose) {
+ fprintf(stderr, "A: %s; ", byte_str(ab_count));
+ fprintf(stderr, "B: %s \r", byte_str(ba_count));
+ }
+ }
+
+finish:
+
+ free(ab_buf);
+ free(ba_buf);
+
+ if (a)
+ stream_close(a);
+ if (b)
+ stream_close(b);
+
+ return ret;
+
+}