Fix various compile warnings
[splice.git] / nettest / xmit.c
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
20 static void **buffers;
21 static int cur_buf, nr_bufs;
22
23 static unsigned int msg_size = 4096;
24 static int use_splice = 1;
25 static unsigned long packets = -1;
26
27 static unsigned long seed = 0x9e370001UL;
28
29 unsigned 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
53 unsigned 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
61 static 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
67 static 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
93 static 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
116 static 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
132 static 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  */
161 static int setup_buffers(void)
162 {
163         int i;
164
165         nr_bufs = 4 * SPLICE_SIZE / msg_size;
166
167         buffers = malloc(sizeof(void *) * nr_bufs);
168
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;
177 }
178
179 static 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
189 static 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
197         if (setup_buffers())
198                 return -1;
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
229 static 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
246 static 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
266 static 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
292 int 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 }