From d633e5779ea16e2811b112314793678a0eb80231 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 20 Apr 2006 15:26:06 +0200 Subject: [PATCH] [PATCH] ktee-net: Add ktee-net This dupes data from stdin to a network host and stdout. --- Makefile | 2 +- ktee-net.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ktee.c | 7 +--- 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100755 ktee-net.c diff --git a/Makefile b/Makefile index e820dce..29d76a4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -O2 -g -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -PROGS = ktee splice-cp splice-in splice-out splice-net splice-test4c splice-test4s +PROGS = ktee ktee-net splice-cp splice-in splice-out splice-net splice-test4c splice-test4s all: depend $(PROGS) diff --git a/ktee-net.c b/ktee-net.c new file mode 100755 index 0000000..e2ebde0 --- /dev/null +++ b/ktee-net.c @@ -0,0 +1,107 @@ +/* + * A tee implementation using sys_tee. Sends out the data received over + * stdin to the given host:port and over stdout. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "splice.h" + +static int do_splice(int infd, int outfd, unsigned int len, char *msg) +{ + while (len) { + int written = splice(infd, NULL, outfd, NULL, len, 0); + + if (written <= 0) + return error(msg); + + len -= written; + } + + return 0; +} + +static int usage(char *name) +{ + fprintf(stderr, "%s: hostname:port\n", name); + return 1; +} + +int main(int argc, char *argv[]) +{ + struct sockaddr_in addr; + char *p, *hname; + struct stat sb; + int fd; + + if (argc < 2) + return usage(argv[0]); + + if (fstat(STDIN_FILENO, &sb) < 0) + return error("stat"); + if (!S_ISFIFO(sb.st_mode)) { + fprintf(stderr, "stdin must be a pipe\n"); + return 1; + } + + hname = strdup(argv[1]); + p = strstr(hname, ":"); + if (!p) + return usage(argv[0]); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(atoi(p + 1)); + *p = '\0'; + + if (inet_aton(hname, &addr.sin_addr) != 1) { + struct hostent *hent = gethostbyname(hname); + + if (!hent) + return error("gethostbyname"); + + memcpy(&addr.sin_addr, hent->h_addr, 4); + } + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + return error("socket"); + + fprintf(stderr, "connecting to %s, port %x\n", hname, addr.sin_port); + + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + return error("connect"); + + do { + int tee_len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK); + + if (tee_len < 0) { + if (errno == EAGAIN) { + usleep(1000); + continue; + } + return error("tee"); + } else if (!tee_len) + break; + + /* + * Send output to file, also consumes input pipe. + */ + if (do_splice(STDIN_FILENO, fd, tee_len, "splice-net")) + break; + } while (1); + + close(fd); + return 0; +} diff --git a/ktee.c b/ktee.c index 7b05361..1b934d5 100644 --- a/ktee.c +++ b/ktee.c @@ -1,9 +1,6 @@ /* - * A tee implementation using sys_tee. If only one argument is given, - * stdin output is stored in that file and sent to stdout as well. If a - * second argument is given, that must be in the form if host:port - in - * that case, output is stored in file and sent over the network to the - * given host at given port. + * A tee implementation using sys_tee. Stores stdin input in the given file + * and duplicates that to stdout. */ #include #include -- 2.25.1