Fix various compile warnings
[splice.git] / nettest / xmit.c
CommitLineData
211f748c
JA
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <netdb.h>
5#include <unistd.h>
6#include <fcntl.h>
7#include <signal.h>
8#include <netinet/in.h>
9#include <arpa/inet.h>
10#include <string.h>
11#include <sys/time.h>
12#include <errno.h>
13#include <sys/time.h>
14#include <sys/resource.h>
15
16#include "../splice.h"
17#include "crc32.h"
18#include "msg.h"
19
20static void **buffers;
21static int cur_buf, nr_bufs;
22
23static unsigned int msg_size = 4096;
24static int use_splice = 1;
25static unsigned long packets = -1;
26
59292f8b 27static unsigned long seed = 0x9e370001UL;
211f748c
JA
28
29unsigned long mtime_since(struct timeval *s, struct timeval *e)
30{
31 long sec, usec, ret;
32
33 sec = e->tv_sec - s->tv_sec;
34 usec = e->tv_usec - s->tv_usec;
35 if (sec > 0 && usec < 0) {
36 sec--;
37 usec += 1000000;
38 }
39
40 sec *= 1000UL;
41 usec /= 1000UL;
42 ret = sec + usec;
43
44 /*
45 * time warp bug on some kernels?
46 */
47 if (ret < 0)
48 ret = 0;
49
50 return ret;
51}
52
53unsigned long mtime_since_now(struct timeval *s)
54{
55 struct timeval t;
56
57 gettimeofday(&t, NULL);
58 return mtime_since(s, &t);
59}
60
61static int usage(char *name)
62{
63 fprintf(stderr, "%s: [-s(ize)] [-p(ackets to send)] [-n(ormal send())] target port\n", name);
64 return 1;
65}
66
67static int parse_options(int argc, char *argv[])
68{
69 int c, index = 1;
70
71 while ((c = getopt(argc, argv, "s:np:")) != -1) {
72 switch (c) {
73 case 's':
74 msg_size = atoi(optarg);
75 index++;
76 break;
77 case 'n':
78 use_splice = 0;
79 index++;
80 break;
81 case 'p':
82 packets = atoi(optarg);
83 index++;
84 break;
85 default:
86 return -1;
87 }
88 }
89
90 return index;
91}
92
93static void fill_buf(struct msg *m, unsigned int len)
94{
95 void *p = m;
96 unsigned int left;
97 unsigned long *val;
98
99 m->msg_size = len;
100 len -= sizeof(*m);
101 p += sizeof(*m);
102
103 left = len;
104 val = p;
105 while (left) {
106 if (left < sizeof(*val))
107 break;
108 *val = rand() * seed;
109 val++;
110 left -= sizeof(*val);
111 }
112
113 m->crc32 = crc32(p, len);
114}
115
116static int splice_out(int sockfd, int pipefd, unsigned int len)
117{
118 while (len) {
119 int ret = ssplice(pipefd, NULL, sockfd, NULL, len, 0);
120
121 if (ret < 0)
122 return error("splice to network");
123 else if (!ret)
124 break;
125
126 len -= ret;
127 }
128
129 return len;
130}
131
132static int vmsplice_in(void *buf, int pipefd, unsigned int len)
133{
134 struct iovec iov = {
135 .iov_base = buf,
136 .iov_len = len,
137 };
138
139 while (len) {
140 int ret = svmsplice(pipefd, &iov, 1, 0);
141
142 if (ret < 0)
143 return error("vmsplice");
144 else if (!ret)
145 break;
146
147 len -= ret;
148 if (len) {
149 iov.iov_base += ret;
150 iov.iov_len -= ret;
151 }
152 }
153
154 return len;
155}
156
157/*
158 * Keep four pipes of buffers, that should be enough to ensure that
159 * we don't reuse
160 */
fb02ff37 161static int setup_buffers(void)
211f748c
JA
162{
163 int i;
164
165 nr_bufs = 4 * SPLICE_SIZE / msg_size;
166
167 buffers = malloc(sizeof(void *) * nr_bufs);
168
fb02ff37
JA
169 for (i = 0; i < nr_bufs; i++) {
170 if (posix_memalign(&buffers[i], 4096, msg_size)) {
171 printf("posix_memalign: %s\n", strerror(errno));
172 return -1;
173 }
174 }
175
176 return 0;
211f748c
JA
177}
178
179static void free_buffers(void)
180{
181 int i;
182
183 for (i = 0; i < nr_bufs; i++)
184 free(buffers[i]);
185
186 free(buffers);
187}
188
189static int splice_send_loop(int fd)
190{
191 struct msg *m = NULL;
192 int pipes[2];
193
194 if (pipe(pipes) < 0)
195 return error("pipe");
196
fb02ff37
JA
197 if (setup_buffers())
198 return -1;
211f748c
JA
199
200 while (packets--) {
201 m = buffers[cur_buf];
202 if (++cur_buf == nr_bufs)
203 cur_buf = 0;
204
205 /*
206 * fill with random data and crc sum it
207 */
208 fill_buf(m, msg_size);
209
210 /*
211 * map data to our pipe
212 */
213 if (vmsplice_in(m, pipes[1], msg_size))
214 break;
215
216 /*
217 * then transmit pipe to network
218 */
219 if (splice_out(fd, pipes[0], msg_size))
220 break;
221 }
222
223 free_buffers();
224 close(pipes[0]);
225 close(pipes[1]);
226 return 0;
227}
228
229static int do_send(int fd, void *buf, unsigned int len)
230{
231 while (len) {
232 int ret = send(fd, buf, len, 0);
233
234 if (ret < 0)
235 return error("send");
236 else if (!ret)
237 break;
238
239 len -= ret;
240 buf += ret;
241 }
242
243 return len;
244}
245
246static int normal_send_loop(int fd)
247{
248 struct msg *m;
249
250 m = malloc(msg_size);
251
252 while (packets--) {
253 /*
254 * fill with random data and crc sum it
255 */
256 fill_buf(m, msg_size);
257
258 if (do_send(fd, m, msg_size))
259 break;
260 }
261
262 free(m);
263 return 0;
264}
265
266static int send_loop(int fd)
267{
268 struct rusage ru_s, ru_e;
269 unsigned long ut, st, rt;
270 struct timeval start;
271 int ret;
272
273 gettimeofday(&start, NULL);
274 getrusage(RUSAGE_SELF, &ru_s);
275
276 if (use_splice)
277 ret = splice_send_loop(fd);
278 else
279 ret = normal_send_loop(fd);
280
281 getrusage(RUSAGE_SELF, &ru_e);
282
283 ut = mtime_since(&ru_s.ru_utime, &ru_e.ru_utime);
284 st = mtime_since(&ru_s.ru_stime, &ru_e.ru_stime);
285 rt = mtime_since_now(&start);
286
287 printf("usr=%lu, sys=%lu, real=%lu\n", ut, st, rt);
288 fflush(stdout);
289 return ret;
290}
291
292int main(int argc, char *argv[])
293{
294 struct sockaddr_in addr;
295 unsigned short port;
296 int fd, index;
297
298 if (argc < 3)
299 return usage(argv[0]);
300
301 index = parse_options(argc, argv);
302 if (index == -1 || index + 1 > argc)
303 return usage(argv[0]);
304
305 port = atoi(argv[index + 1]);
306
307 memset(&addr, 0, sizeof(addr));
308 addr.sin_family = AF_INET;
309 addr.sin_port = htons(port);
310
311 if (inet_aton(argv[index], &addr.sin_addr) != 1) {
312 struct hostent *hent = gethostbyname(argv[index]);
313
314 if (!hent)
315 return error("gethostbyname");
316
317 memcpy(&addr.sin_addr, hent->h_addr, 4);
318 }
319
320 printf("xmit: msg=%ukb, ", msg_size >> 10);
321 if (use_splice)
322 printf("vmsplice() -> splice()\n");
323 else
324 printf("send()\n");
325
326 printf("Connecting to %s/%d\n", argv[index], port);
327
328 fd = socket(AF_INET, SOCK_STREAM, 0);
329 if (fd < 0)
330 return error("socket");
331
332 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
333 return error("connect");
334
335 return send_loop(fd);
336}