8 #include <netinet/in.h>
15 #include <sys/resource.h>
17 #include "../splice.h"
21 static unsigned int msg_size = 4096;
22 static int use_splice = 1;
23 static int splice_move;
25 static int usage(const char *name)
27 fprintf(stderr, "%s: [-s(ize)] [-m(ove)] [-r(ecv)] port\n", name);
31 unsigned long mtime_since(struct timeval *s, struct timeval *e)
35 sec = e->tv_sec - s->tv_sec;
36 usec = e->tv_usec - s->tv_usec;
37 if (sec > 0 && usec < 0) {
47 * time warp bug on some kernels?
55 unsigned long mtime_since_now(struct timeval *s)
59 gettimeofday(&t, NULL);
60 return mtime_since(s, &t);
63 static int get_connect(int fd, struct sockaddr_in *addr)
65 socklen_t socklen = sizeof(*addr);
68 fprintf(stderr, "Waiting for connect...\n");
76 ret = poll(&pfd, 1, -1);
82 connfd = accept(fd, (struct sockaddr *) addr, &socklen);
84 return error("accept");
88 fprintf(stderr, "Got connect!\n");
93 static int parse_options(int argc, char *argv[])
97 while ((c = getopt(argc, argv, "s:mr")) != -1) {
100 msg_size = atoi(optarg);
119 static int verify_crc(struct msg *m)
125 crc = crc32(data, m->msg_size - sizeof(*m));
130 fprintf(stderr, "crc error: got %lx, wanted %lx\n", crc, m->crc32);
134 static int do_recv(int fd, void *buf, unsigned int len)
137 int ret = recv(fd, buf, len, MSG_WAITALL);
140 return error("recv");
151 static int normal_recv_loop(int fd)
155 m = malloc(msg_size);
158 if (do_recv(fd, m, msg_size))
161 if (m->msg_size != msg_size) {
162 fprintf(stderr, "Bad packet length: wanted %u, got %lu\n", msg_size, m->msg_size);
177 static int splice_in(int sockfd, int pipefd, unsigned int size)
180 int ret = ssplice(sockfd, NULL, pipefd, NULL, size, 0);
183 return error("splice from net");
191 fprintf(stderr, "splice: %u resid\n", size);
196 static int vmsplice_unmap(int pipefd, void *buf, unsigned int len)
203 if (svmsplice(pipefd, &iov, 1, SPLICE_F_UNMAP) < 0)
204 return error("vmsplice unmap");
209 static int vmsplice_out(void **buf, int pipefd, unsigned int len)
218 flags |= SPLICE_F_MOVE;
221 ret = svmsplice(pipefd, &iov, 1, flags);
223 return error("vmsplice");
239 fprintf(stderr, "vmsplice: %u resid\n", len);
244 static int splice_recv_loop(int fd)
251 return error("pipe");
254 m = malloc(msg_size);
260 * fill pipe with network data
262 if (splice_in(fd, pipes[1], msg_size))
266 * move data to our address space
273 if (vmsplice_out(&buf, pipes[0], msg_size))
278 if (m->msg_size != msg_size) {
279 fprintf(stderr, "Bad packet length: wanted %u, got %lu\n", msg_size, m->msg_size);
289 if (splice_move && vmsplice_unmap(pipes[0], buf, msg_size))
301 static int recv_loop(int fd)
303 struct rusage ru_s, ru_e;
304 struct timeval start;
305 unsigned long ut, st, rt;
308 gettimeofday(&start, NULL);
309 getrusage(RUSAGE_SELF, &ru_s);
312 ret = splice_recv_loop(fd);
314 ret = normal_recv_loop(fd);
316 getrusage(RUSAGE_SELF, &ru_e);
318 ut = mtime_since(&ru_s.ru_utime, &ru_e.ru_utime);
319 st = mtime_since(&ru_s.ru_stime, &ru_e.ru_stime);
320 rt = mtime_since_now(&start);
322 printf("usr=%lu, sys=%lu, real=%lu\n", ut, st, rt);
327 int main(int argc, char *argv[])
329 struct sockaddr_in addr;
331 int connfd, fd, opt, index;
334 return usage(argv[0]);
336 index = parse_options(argc, argv);
337 if (index == -1 || index + 1 > argc)
338 return usage(argv[0]);
340 printf("recv: msg=%ukb, ", msg_size >> 10);
351 port = atoi(argv[index]);
353 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
355 return error("socket");
358 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
359 return error("setsockopt");
361 memset(&addr, 0, sizeof(addr));
362 addr.sin_family = AF_INET;
363 addr.sin_addr.s_addr = htonl(INADDR_ANY);
364 addr.sin_port = htons(port);
366 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
367 return error("bind");
368 if (listen(fd, 1) < 0)
369 return error("listen");
371 connfd = get_connect(fd, &addr);
375 return recv_loop(connfd);