2 * Splice from network to pipe. Currently splicing from a socket is not
3 * supported, so this test case demonstrates how to use read + vmsplice/splice
4 * to achieve the desired effect. This still involves a copy, so it's
5 * not as fast as real splice from socket would be.
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
23 #define MASK (PSIZE - 1)
25 #define ALIGN(buf) (void *) (((unsigned long) (buf) + MASK) & ~MASK)
27 static int splice_flags;
29 static int usage(char *name)
31 fprintf(stderr, "%s: [-g] port\n", name);
35 static unsigned long mtime_since(struct timeval *s, struct timeval *e)
39 sec = e->tv_sec - s->tv_sec;
40 usec = e->tv_usec - s->tv_usec;
41 if (sec > 0 && usec < 0) {
47 usec /= (double) 1000;
52 static unsigned long mtime_since_now(struct timeval *s)
56 gettimeofday(&t, NULL);
57 return mtime_since(s, &t);
60 static int recv_loop(int fd, char *buf)
62 unsigned long kb_recv = 0, spent;
67 gettimeofday(&s, NULL);
70 char *ptr = buf + idx * SPLICE_SIZE;
73 ret = recv(fd, ptr, SPLICE_SIZE, MSG_WAITALL);
77 } else if (ret != SPLICE_SIZE)
81 iov.iov_len = SPLICE_SIZE;
82 ret = vmsplice(STDOUT_FILENO, &iov, 1, splice_flags);
86 } else if (ret != SPLICE_SIZE) {
87 fprintf(stderr, "bad vmsplice %d\n", ret);
90 idx = (idx + 1) & 0x01;
91 kb_recv += (SPLICE_SIZE / 1024);
94 spent = mtime_since_now(&s);
95 fprintf(stderr, "%lu MiB/sec (%luKiB in %lu msec)\n", kb_recv / spent, kb_recv, spent);
100 static int parse_options(int argc, char *argv[])
104 while ((c = getopt(argc, argv, "g")) != -1) {
107 splice_flags = SPLICE_F_GIFT;
118 int main(int argc, char *argv[])
120 struct sockaddr_in addr;
123 int fd, opt, sk, index;
126 if (check_output_pipe())
127 return usage(argv[0]);
129 index = parse_options(argc, argv);
130 if (index == -1 || index + 1 > argc)
131 return usage(argv[0]);
133 port = atoi(argv[index]);
135 fd = socket(PF_INET, SOCK_STREAM, 0);
137 return error("socket");
140 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
141 return error("setsockopt");
143 memset(&addr, 0, sizeof(addr));
144 addr.sin_addr.s_addr = htonl(INADDR_ANY);
145 addr.sin_port = htons(port);
147 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
148 return error("bind");
150 if (listen(fd, 1) < 0)
151 return error("listen");
154 sk = accept(fd, &addr, &len);
156 return error("accept");
158 fprintf(stderr, "Connected\n");
160 buf = ALIGN(malloc(2 * SPLICE_SIZE - 1));
162 return recv_loop(sk, buf);