[PATCH] ktee-net: Add ktee-net
[splice.git] / ktee-net.c
CommitLineData
d633e577
JA
1/*
2 * A tee implementation using sys_tee. Sends out the data received over
3 * stdin to the given host:port and over stdout.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <string.h>
9#include <fcntl.h>
10#include <string.h>
11#include <netinet/in.h>
12#include <arpa/inet.h>
13#include <netdb.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <errno.h>
17#include <limits.h>
18
19#include "splice.h"
20
21static int do_splice(int infd, int outfd, unsigned int len, char *msg)
22{
23 while (len) {
24 int written = splice(infd, NULL, outfd, NULL, len, 0);
25
26 if (written <= 0)
27 return error(msg);
28
29 len -= written;
30 }
31
32 return 0;
33}
34
35static int usage(char *name)
36{
37 fprintf(stderr, "%s: hostname:port\n", name);
38 return 1;
39}
40
41int main(int argc, char *argv[])
42{
43 struct sockaddr_in addr;
44 char *p, *hname;
45 struct stat sb;
46 int fd;
47
48 if (argc < 2)
49 return usage(argv[0]);
50
51 if (fstat(STDIN_FILENO, &sb) < 0)
52 return error("stat");
53 if (!S_ISFIFO(sb.st_mode)) {
54 fprintf(stderr, "stdin must be a pipe\n");
55 return 1;
56 }
57
58 hname = strdup(argv[1]);
59 p = strstr(hname, ":");
60 if (!p)
61 return usage(argv[0]);
62
63 memset(&addr, 0, sizeof(addr));
64 addr.sin_family = AF_INET;
65 addr.sin_port = htons(atoi(p + 1));
66 *p = '\0';
67
68 if (inet_aton(hname, &addr.sin_addr) != 1) {
69 struct hostent *hent = gethostbyname(hname);
70
71 if (!hent)
72 return error("gethostbyname");
73
74 memcpy(&addr.sin_addr, hent->h_addr, 4);
75 }
76
77 fd = socket(AF_INET, SOCK_STREAM, 0);
78 if (fd < 0)
79 return error("socket");
80
81 fprintf(stderr, "connecting to %s, port %x\n", hname, addr.sin_port);
82
83 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
84 return error("connect");
85
86 do {
87 int tee_len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
88
89 if (tee_len < 0) {
90 if (errno == EAGAIN) {
91 usleep(1000);
92 continue;
93 }
94 return error("tee");
95 } else if (!tee_len)
96 break;
97
98 /*
99 * Send output to file, also consumes input pipe.
100 */
101 if (do_splice(STDIN_FILENO, fd, tee_len, "splice-net"))
102 break;
103 } while (1);
104
105 close(fd);
106 return 0;
107}