splice-fromnet: add poll and size options
[splice.git] / splice-fromnet.c
CommitLineData
beeecb44 1/*
27e4ade6 2 * Splice from network to stdout
beeecb44
JA
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>
27e4ade6 16#include <sys/poll.h>
beeecb44
JA
17
18#include "splice.h"
19
0b7e440c
JA
20static unsigned int splice_size = SPLICE_SIZE;
21static int wait_for_poll;
22
beeecb44
JA
23static int usage(char *name)
24{
0b7e440c 25 fprintf(stderr, "%s: [-s splice size] [-w wait for poll] port\n", name);
beeecb44
JA
26 return 1;
27}
28
27e4ade6 29static int splice_from_net(int fd)
beeecb44 30{
27e4ade6 31 while (1) {
27e4ade6 32 int ret;
beeecb44 33
0b7e440c
JA
34 if (wait_for_poll) {
35 struct pollfd pfd = {
36 .fd = fd,
37 .events = POLLIN,
38 };
beeecb44 39
0b7e440c
JA
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 }
beeecb44 49
0b7e440c 50 ret = ssplice(fd, NULL, STDOUT_FILENO, NULL, splice_size, 0);
beeecb44 51
27e4ade6
JA
52 if (ret < 0)
53 return error("splice");
54 else if (!ret)
beeecb44 55 break;
27e4ade6 56 }
beeecb44
JA
57
58 return 0;
59}
60
27e4ade6 61static int get_connect(int fd, struct sockaddr_in *addr)
beeecb44 62{
27e4ade6
JA
63 socklen_t socklen = sizeof(*addr);
64 int ret, connfd;
beeecb44 65
27e4ade6
JA
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;
beeecb44
JA
85}
86
0b7e440c
JA
87static 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
beeecb44
JA
110int main(int argc, char *argv[])
111{
112 struct sockaddr_in addr;
113 unsigned short port;
0b7e440c 114 int connfd, opt, fd, index;
beeecb44 115
27e4ade6 116 if (argc < 2)
beeecb44
JA
117 return usage(argv[0]);
118
27e4ade6 119 if (check_output_pipe())
beeecb44
JA
120 return usage(argv[0]);
121
0b7e440c
JA
122 index = parse_options(argc, argv);
123 if (index == -1 || index + 1 > argc)
124 return usage(argv[0]);
125
126 port = atoi(argv[index]);
beeecb44 127
27e4ade6 128 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
beeecb44
JA
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));
27e4ade6 137 addr.sin_family = AF_INET;
beeecb44
JA
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");
beeecb44
JA
143 if (listen(fd, 1) < 0)
144 return error("listen");
145
27e4ade6
JA
146 connfd = get_connect(fd, &addr);
147 if (connfd < 0)
148 return connfd;
beeecb44 149
27e4ade6 150 return splice_from_net(connfd);
beeecb44 151}