splice-fromnet: add poll and size options
[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 unsigned int splice_size = SPLICE_SIZE;
21 static int wait_for_poll;
22
23 static int usage(char *name)
24 {
25         fprintf(stderr, "%s: [-s splice size] [-w wait for poll] port\n", name);
26         return 1;
27 }
28
29 static int splice_from_net(int fd)
30 {
31         while (1) {
32                 int ret;
33
34                 if (wait_for_poll) {
35                         struct pollfd pfd = {
36                                 .fd = fd,
37                                 .events = POLLIN,
38                         };
39
40                         ret = poll(&pfd, 1, -1);
41                         if (ret < 0)
42                                 return error("poll");
43                         else if (!ret)
44                                 continue;
45
46                         if (!(pfd.revents & POLLIN))
47                                 continue;
48                 }
49
50                 ret = ssplice(fd, NULL, STDOUT_FILENO, NULL, splice_size, 0);
51
52                 if (ret < 0)
53                         return error("splice");
54                 else if (!ret)
55                         break;
56         }
57
58         return 0;
59 }
60
61 static int get_connect(int fd, struct sockaddr_in *addr)
62 {
63         socklen_t socklen = sizeof(*addr);
64         int ret, connfd;
65
66         do {
67                 struct pollfd pfd = {
68                         .fd = fd,
69                         .events = POLLIN,
70                 };
71
72                 ret = poll(&pfd, 1, -1);
73                 if (ret < 0)
74                         return error("poll");
75                 else if (!ret)
76                         continue;
77
78                 connfd = accept(fd, (struct sockaddr *) addr, &socklen);
79                 if (connfd < 0)
80                         return error("accept");
81                 break;
82         } while (1);
83                         
84         return connfd;
85 }
86
87 static int parse_options(int argc, char *argv[])
88 {
89         int c, index = 1;
90
91         while ((c = getopt(argc, argv, "s:w:")) != -1) {
92                 switch (c) {
93                 case 's':
94                         splice_size = atoi(optarg);
95                         index++;
96                         break;
97                 case 'w':
98                         wait_for_poll = atoi(optarg);
99                         index++;
100                         break;
101                 default:
102                         return -1;
103                 }
104         }
105
106         return index;
107 }
108
109
110 int main(int argc, char *argv[])
111 {
112         struct sockaddr_in addr;
113         unsigned short port;
114         int connfd, opt, fd, index;
115
116         if (argc < 2)
117                 return usage(argv[0]);
118
119         if (check_output_pipe())
120                 return usage(argv[0]);
121
122         index = parse_options(argc, argv);
123         if (index == -1 || index + 1 > argc)
124                 return usage(argv[0]);
125
126         port = atoi(argv[index]);
127
128         fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
129         if (fd < 0)
130                 return error("socket");
131
132         opt = 1;
133         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
134                 return error("setsockopt");
135
136         memset(&addr, 0, sizeof(addr));
137         addr.sin_family = AF_INET;
138         addr.sin_addr.s_addr = htonl(INADDR_ANY);
139         addr.sin_port = htons(port);
140
141         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
142                 return error("bind");
143         if (listen(fd, 1) < 0)
144                 return error("listen");
145
146         connfd = get_connect(fd, &addr);
147         if (connfd < 0)
148                 return connfd;
149
150         return splice_from_net(connfd);
151 }