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