splice-fromnet: really splice from network
[splice.git] / splice-fromnet.c
1 /*
2  * Splice from network to stdout
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <netdb.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 #include <string.h>
14 #include <sys/time.h>
15 #include <errno.h>
16 #include <sys/poll.h>
17
18 #include "splice.h"
19
20 static int usage(char *name)
21 {
22         fprintf(stderr, "%s: port\n", name);
23         return 1;
24 }
25
26 static int splice_from_net(int fd)
27 {
28         while (1) {
29                 struct pollfd pfd = {
30                         .fd = fd,
31                         .events = POLLIN,
32                 };
33                 int ret;
34
35                 ret = poll(&pfd, 1, -1);
36                 if (ret < 0)
37                         return error("poll");
38                 else if (!ret)
39                         continue;
40
41                 if (!(pfd.revents & POLLIN))
42                         continue;
43
44                 ret = splice(fd, NULL, STDOUT_FILENO, NULL, SPLICE_SIZE, 0);
45
46                 if (ret < 0)
47                         return error("splice");
48                 else if (!ret)
49                         break;
50         }
51
52         return 0;
53 }
54
55 static int get_connect(int fd, struct sockaddr_in *addr)
56 {
57         socklen_t socklen = sizeof(*addr);
58         int ret, connfd;
59
60         do {
61                 struct pollfd pfd = {
62                         .fd = fd,
63                         .events = POLLIN,
64                 };
65
66                 ret = poll(&pfd, 1, -1);
67                 if (ret < 0)
68                         return error("poll");
69                 else if (!ret)
70                         continue;
71
72                 connfd = accept(fd, (struct sockaddr *) addr, &socklen);
73                 if (connfd < 0)
74                         return error("accept");
75                 break;
76         } while (1);
77                         
78         return connfd;
79 }
80
81 int main(int argc, char *argv[])
82 {
83         struct sockaddr_in addr;
84         unsigned short port;
85         int connfd, opt, fd;
86
87         if (argc < 2)
88                 return usage(argv[0]);
89
90         if (check_output_pipe())
91                 return usage(argv[0]);
92
93         port = atoi(argv[1]);
94
95         fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
96         if (fd < 0)
97                 return error("socket");
98
99         opt = 1;
100         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
101                 return error("setsockopt");
102
103         memset(&addr, 0, sizeof(addr));
104         addr.sin_family = AF_INET;
105         addr.sin_addr.s_addr = htonl(INADDR_ANY);
106         addr.sin_port = htons(port);
107
108         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
109                 return error("bind");
110         if (listen(fd, 1) < 0)
111                 return error("listen");
112
113         connfd = get_connect(fd, &addr);
114         if (connfd < 0)
115                 return connfd;
116
117         return splice_from_net(connfd);
118 }