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