Clang-format ttcp.c
[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 <libc.h>
39 #include <u.h>
40
41 long ncalls;
42 char scale;
43
44 long nread(int fd, char *buf, long len)
45 {
46         int cnt, rlen = 0;
47         char *b = buf;
48         for (;;) {
49                 cnt = read(fd, b, len);
50                 ncalls++;
51                 if (cnt <= 0)
52                         break;
53                 rlen += cnt;
54                 len -= cnt;
55                 if (len == 0)
56                         break;
57                 b += cnt;
58         }
59         return rlen;
60 }
61
62 long nwrite(int fd, char *buf, long len)
63 {
64         int cnt, rlen = 0;
65         char *b = buf;
66         for (;;) {
67                 cnt = write(fd, b, len);
68                 ncalls++;
69                 if (cnt <= 0)
70                         break;
71                 rlen += cnt;
72                 len -= cnt;
73                 if (len == 0)
74                         break;
75                 b += cnt;
76         }
77         return rlen;
78 }
79
80 void pattern(char *buf, int buflen)
81 {
82         int i;
83         char ch = ' ';
84         char *b = buf;
85         for (i = 0; i < buflen; i++) {
86                 *b++ = ch++;
87                 if (ch == 127)
88                         ch = ' ';
89         }
90 }
91
92 char fmt = 'K';
93 char *unit;
94
95 double rate(vlong nbytes, double time)
96 {
97         switch (fmt) {
98         case 'k':
99                 unit = "Kbit";
100                 return nbytes * 8 / time / (1 << 10);
101         case 'K':
102                 unit = "KB";
103                 return nbytes / time / (1 << 10);
104         case 'm':
105                 unit = "Mbit";
106                 return nbytes * 8 / time / (1 << 20);
107         case 'M':
108                 unit = "MB";
109                 return nbytes / time / (1 << 20);
110         case 'g':
111                 unit = "Gbit";
112                 return nbytes * 8 / time / (1 << 30);
113         case 'G':
114                 unit = "GB";
115                 return nbytes / time / (1 << 30);
116         }
117         return 0.0;
118 }
119
120 void reader(int udp, char *addr, char *port, int buflen, int nbuf, int sink)
121 {
122         char *buf, adir[40], ldir[40];
123         int fd, cnt, acfd, lcfd;
124         vlong nbytes = 0;
125         vlong now;
126         double elapsed;
127         int pd;
128         char peer[100];
129
130         print("ttcp-r: buflen=%d, nbuf=%d, port=%s %s\n", buflen, nbuf, port,
131               udp ? "udp" : "tcp");
132
133         acfd = announce(netmkaddr(addr, udp ? "udp" : "tcp", port), adir);
134         if (acfd < 0)
135                 sysfatal("announce: %r");
136         buf = malloc(buflen);
137
138         lcfd = listen(adir, ldir);
139         if (lcfd < 0)
140                 sysfatal("listen: %r");
141
142         fd = accept(lcfd, ldir);
143         if (fd < 0)
144                 return;
145
146         sprint(peer, "%s/remote", ldir);
147         pd = open(peer, OREAD);
148         cnt = read(pd, peer, 100);
149         close(pd);
150
151         print("ttcp-r: accept from %*.*s", cnt, cnt, peer);
152         now = nsec();
153         if (sink) {
154                 while ((cnt = nread(fd, buf, buflen)) > 0)
155                         nbytes += cnt;
156         } else {
157                 while ((cnt = nread(fd, buf, buflen)) > 0 && write(1, buf, cnt) == cnt)
158                         nbytes += cnt;
159         }
160         elapsed = (nsec() - now) / 1E9;
161
162         print("ttcp-r: %lld bytes in %.2f real seconds = %.2f %s/sec\n", nbytes,
163               elapsed, rate(nbytes, elapsed), unit);
164 }
165
166 void writer(int udp, char *addr, char *port, int buflen, int nbuf, int src)
167 {
168         char *buf;
169         int fd, cnt;
170         vlong nbytes = 0;
171         vlong now;
172         double elapsed;
173
174         print("ttcp-t: buflen=%d, nbuf=%d, port=%s %s -> %s\n", buflen, nbuf, port,
175               udp ? "udp" : "tcp", addr);
176
177         buf = malloc(buflen);
178         fd = dial(netmkaddr(addr, udp ? "udp" : "tcp", port), 0, 0, 0);
179         if (fd < 0)
180                 sysfatal("dial: %r");
181
182         print("ttcp-t: connect\n");
183
184         now = nsec();
185         if (src) {
186                 pattern(buf, buflen);
187                 while (nbuf-- && nwrite(fd, buf, buflen) == buflen)
188                         nbytes += buflen;
189         } else {
190                 while ((cnt = read(0, buf, buflen)) > 0 && nwrite(fd, buf, cnt) == cnt)
191                         nbytes += cnt;
192         }
193         elapsed = (nsec() - now) / 1E9;
194
195         print("ttcp-t: %lld bytes in %.2f real seconds = %.2f %s/sec\n", nbytes,
196               elapsed, rate(nbytes, elapsed), unit);
197 }
198
199 void usage(void)
200 {
201         print("usage:\tttcp -t [options] host\n"
202               "\t\tttcp -r [options]\n"
203               " options:\n"
204               //              "  -D\t\don't delay tcp (nodelay option)\n"
205               "  -f fmt\trate format: k,m,g,K,M,G = {kilo,mega,giga}{bit,byte}\n"
206               "  -l\t\tlength of buf (default 8192)\n"
207               "  -p port\tport number (default 5001)\n"
208               "  -n num\tnumber of bufs written (default 2048)\n"
209               "  -s\t\t-t: source a pattern to network\n"
210               "\t\t\-r: sink (discard) all data from network\n"
211               //              "  -u\t\tuse UDP instead of TCP\n"
212               );
213         exits(0);
214 }
215
216 void main(int argc, char *argv[])
217 {
218         int buflen = 8192;
219         int nbuf = 2048;
220         int srcsink = 0;
221         char *port = "5001";
222         int udp = 0;
223         enum { none, recv, xmit } mode = none;
224
225         ARGBEGIN
226         {
227         case 'f':
228                 fmt = EARGF(usage())[0];
229                 break;
230         case 'l':
231                 buflen = atoi(EARGF(usage()));
232                 break;
233         case 'n':
234                 nbuf = atoi(EARGF(usage()));
235                 break;
236         case 'p':
237                 port = EARGF(usage());
238                 break;
239         case 'r':
240                 mode = recv;
241                 break;
242         case 's':
243                 srcsink = 1;
244                 break;
245         case 't':
246                 mode = xmit;
247                 break;
248         case 'u':
249                 udp = 1;
250                 break;
251         default:
252                 usage();
253         }
254         ARGEND;
255
256         USED(buflen);
257         switch (mode) {
258         case none:
259                 usage();
260                 break;
261         case xmit:
262                 if (argv[0] == nil)
263                         usage();
264                 writer(udp, argv[0], port, buflen, nbuf, srcsink);
265                 break;
266         case recv:
267                 reader(udp, "*", port, buflen, nbuf, srcsink);
268                 break;
269         }
270         exits(0);
271 }