vmm: Use VMM_CTL to set VMM flags (XCC)
[akaros.git] / tests / ttcp.c
1 /*
2  * ttcp. Modelled after the unix ttcp
3  *
4  * Copyright (c) 2012, Bakul Shah <bakul@bitblocks.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The author's name may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * This software is provided by the author AS IS.  The author DISCLAIMS
19  * any and all warranties of merchantability and fitness for a particular
20  * purpose.  In NO event shall the author be LIABLE for any damages
21  * whatsoever arising in any way out of the use of this software.
22  */
23
24 /*
25  * Options not supported (may be supported in future):
26  * +    -u      Use UDP instead of TCP
27  *      -D      don't want for TCP send (TCP_NODELAY)
28  *      -A num  align buffers on this boundary (default 16384)
29  *      -O off  start buffers at this offset (default 0)
30  * Misc:
31  *      - print calls, msec/call calls/sec
32  *      - print user/sys/real times
33  * May be:
34  *      - multicast support
35  *      - isochronous transfer
36  */
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <assert.h>
44 #include <parlib/net.h>
45 #include <sys/time.h>
46 #include <iplib/iplib.h>
47 #include <parlib/timing.h>
48
49 long ncalls;
50 char scale;
51
52 static void sysfatal(char *msg)
53 {
54         perror(msg);
55         exit(-1);
56 }
57
58 long nread(int fd, char *buf, long len)
59 {
60         int cnt, rlen = 0;
61         char *b = buf;
62         for (;;) {
63                 cnt = read(fd, b, len);
64                 ncalls++;
65                 if (cnt <= 0)
66                         break;
67                 rlen += cnt;
68                 len -= cnt;
69                 if (len == 0)
70                         break;
71                 b += cnt;
72         }
73         return rlen;
74 }
75
76 long nwrite(int fd, char *buf, long len)
77 {
78         int cnt, rlen = 0;
79         char *b = buf;
80         for (;;) {
81                 cnt = write(fd, b, len);
82                 ncalls++;
83                 if (cnt <= 0)
84                         break;
85                 rlen += cnt;
86                 len -= cnt;
87                 if (len == 0)
88                         break;
89                 b += cnt;
90         }
91         return rlen;
92 }
93
94 void pattern(char *buf, int buflen)
95 {
96         int i;
97         char ch = ' ';
98         char *b = buf;
99         for (i = 0; i < buflen; i++) {
100                 *b++ = ch++;
101                 if (ch == 127)
102                         ch = ' ';
103         }
104 }
105
106 char fmt = 'K';
107 char *unit;
108
109 double rate(long nbytes, double time)
110 {
111         switch (fmt) {
112         case 'k':
113                 unit = "Kbit";
114                 return nbytes * 8 / time / (1 << 10);
115         case 'K':
116                 unit = "KB";
117                 return nbytes / time / (1 << 10);
118         case 'm':
119                 unit = "Mbit";
120                 return nbytes * 8 / time / (1 << 20);
121         case 'M':
122                 unit = "MB";
123                 return nbytes / time / (1 << 20);
124         case 'g':
125                 unit = "Gbit";
126                 return nbytes * 8 / time / (1 << 30);
127         case 'G':
128                 unit = "GB";
129                 return nbytes / time / (1 << 30);
130         }
131         return 0.0;
132 }
133
134 void reader(int udp, char *addr, char *port, int buflen, int nbuf, int sink)
135 {
136         char *buf, adir[40], ldir[40];
137         char *ds, ds_store[256];
138         int fd, cnt, acfd, lcfd;
139         long nbytes = 0;
140         long now;
141         double elapsed;
142         int pd;
143         char peer[100];
144
145         fprintf(stderr, "ttcp-r: buflen=%d, nbuf=%d, port=%s %s\n",
146                 buflen, nbuf, port, udp ? "udp" : "tcp");
147
148         ds = netmkaddr(addr, udp ? "udp" : "tcp", port, ds_store, sizeof(ds_store));
149         acfd = announce9(ds, adir, 0);
150         if (acfd < 0)
151                 sysfatal("announce: %r");
152         buf = malloc(buflen);
153
154         lcfd = listen9(adir, ldir, 0);
155         if (lcfd < 0)
156                 sysfatal("listen: %r");
157
158         fd = accept9(lcfd, ldir);
159         if (fd < 0)
160                 return;
161
162         sprintf(peer, "%s/remote", ldir);
163         pd = open(peer, O_READ);
164         cnt = read(pd, peer, 100);
165         close(pd);
166
167         fprintf(stderr, "ttcp-r: accept from %*.*s", cnt, cnt, peer);
168         now = nsec();
169         if (sink) {
170                 while ((cnt = nread(fd, buf, buflen)) > 0)
171                         nbytes += cnt;
172         } else {
173                 while ((cnt = nread(fd, buf, buflen)) > 0 && write(1, buf, cnt) == cnt)
174                         nbytes += cnt;
175         }
176         elapsed = (nsec() - now) / 1E9;
177
178         fprintf(stderr, "ttcp-r: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
179                 nbytes, elapsed, rate(nbytes, elapsed), unit);
180 }
181
182 void writer(int udp, char *addr, char *port, int buflen, int nbuf, int src)
183 {
184         char *buf;
185         int fd, cnt;
186         long nbytes = 0;
187         long now;
188         double elapsed;
189         char netaddr[128];
190
191         fprintf(stderr, "ttcp-t: buflen=%d, nbuf=%d, port=%s %s -> %s\n",
192                     buflen, nbuf, port, udp ? "udp" : "tcp", addr);
193
194         buf = malloc(buflen);
195         snprintf(netaddr, sizeof(netaddr), "%s!%s!%s",
196                  udp ? "udp" : "tcp", addr, port);
197         fprintf(stderr, "dialing %s\n", netaddr);
198         fd = dial9(netaddr, 0, 0, 0, 0);
199         if (fd < 0)
200                 sysfatal("dial: %r");
201
202         fprintf(stderr, "ttcp-t: connect\n");
203
204         now = nsec();
205         if (src) {
206                 pattern(buf, buflen);
207                 while (nbuf-- && nwrite(fd, buf, buflen) == buflen)
208                         nbytes += buflen;
209         } else {
210                 while ((cnt = read(0, buf, buflen)) > 0 && nwrite(fd, buf, cnt) == cnt)
211                         nbytes += cnt;
212         }
213         elapsed = (nsec() - now) / 1E9;
214
215         fprintf(stderr, "ttcp-t: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
216                 nbytes, elapsed, rate(nbytes, elapsed), unit);
217 }
218
219 void usage(void)
220 {
221         fprintf(stderr, "usage:\tttcp -t [options] host\n"
222               "\t\tttcp -r [options]\n"
223               " options:\n"
224               "  -f fmt\trate format: k,m,g,K,M,G = {kilo,mega,giga}{bit,byte}\n"
225               "  -l\t\tlength of buf (default 8192)\n"
226               "  -p port\tport number (default 5001)\n"
227               "  -n num\tnumber of bufs written (default 2048)\n"
228               "  -s\t\t-t: source a pattern to network\n"
229               "\t\t-r: sink (discard) all data from network\n"
230               );
231         exit(0);
232 }
233
234 void main(int argc, char *argv[])
235 {
236         int buflen = 8192;
237         int nbuf = 2048;
238         int srcsink = 0;
239         char *port = "5001";
240         int udp = 0;
241         enum { none, recv, xmit } mode = none;
242         char c;
243
244         while ((c = getopt(argc, argv, "rstuf:l:n:p:")) != -1) {
245                 switch (c) {
246                 case 'f':
247                         fmt = *optarg;
248                         break;
249                 case 'l':
250                         buflen = atoi(optarg);
251                         break;
252                 case 'n':
253                         nbuf = atoi(optarg);
254                         break;
255                 case 'p':
256                         port = optarg;
257                         break;
258                 case 'r':
259                         mode = recv;
260                         break;
261                 case 's':
262                         srcsink = 1;
263                         break;
264                 case 't':
265                         mode = xmit;
266                         break;
267                 case 'u':
268                         udp = 1;
269                         break;
270                 default:
271                         usage();
272                 }
273         }
274         switch (mode) {
275         case none:
276                 usage();
277                 break;
278         case xmit:
279                 if (optind == argc)
280                         usage();
281                 writer(udp, argv[optind], port, buflen, nbuf, srcsink);
282                 break;
283         case recv:
284                 reader(udp, "*", port, buflen, nbuf, srcsink);
285                 break;
286         }
287         exit(0);
288 }