Port ttcp to Akaros
[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         int fd, cnt, acfd, lcfd;
138         long nbytes = 0;
139         long now;
140         double elapsed;
141         int pd;
142         char peer[100];
143
144         fprintf(stderr, "ttcp-r: buflen=%d, nbuf=%d, port=%s %s\n",
145                 buflen, nbuf, port, udp ? "udp" : "tcp");
146
147         acfd = announce9(netmkaddr(addr, udp ? "udp" : "tcp", port), adir, 0);
148         if (acfd < 0)
149                 sysfatal("announce: %r");
150         buf = malloc(buflen);
151
152         lcfd = listen9(adir, ldir, 0);
153         if (lcfd < 0)
154                 sysfatal("listen: %r");
155
156         fd = accept9(lcfd, ldir);
157         if (fd < 0)
158                 return;
159
160         sprintf(peer, "%s/remote", ldir);
161         pd = open(peer, O_READ);
162         cnt = read(pd, peer, 100);
163         close(pd);
164
165         fprintf(stderr, "ttcp-r: accept from %*.*s", cnt, cnt, peer);
166         now = nsec();
167         if (sink) {
168                 while ((cnt = nread(fd, buf, buflen)) > 0)
169                         nbytes += cnt;
170         } else {
171                 while ((cnt = nread(fd, buf, buflen)) > 0 && write(1, buf, cnt) == cnt)
172                         nbytes += cnt;
173         }
174         elapsed = (nsec() - now) / 1E9;
175
176         fprintf(stderr, "ttcp-r: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
177                 nbytes, elapsed, rate(nbytes, elapsed), unit);
178 }
179
180 void writer(int udp, char *addr, char *port, int buflen, int nbuf, int src)
181 {
182         char *buf;
183         int fd, cnt;
184         long nbytes = 0;
185         long now;
186         double elapsed;
187         char netaddr[128];
188
189         fprintf(stderr, "ttcp-t: buflen=%d, nbuf=%d, port=%s %s -> %s\n",
190                     buflen, nbuf, port, udp ? "udp" : "tcp", addr);
191
192         buf = malloc(buflen);
193         snprintf(netaddr, sizeof(netaddr), "%s!%s!%s",
194                  udp ? "udp" : "tcp", addr, port);
195         fprintf(stderr, "dialing %s\n", netaddr);
196         fd = dial9(netaddr, 0, 0, 0, 0);
197         if (fd < 0)
198                 sysfatal("dial: %r");
199
200         fprintf(stderr, "ttcp-t: connect\n");
201
202         now = nsec();
203         if (src) {
204                 pattern(buf, buflen);
205                 while (nbuf-- && nwrite(fd, buf, buflen) == buflen)
206                         nbytes += buflen;
207         } else {
208                 while ((cnt = read(0, buf, buflen)) > 0 && nwrite(fd, buf, cnt) == cnt)
209                         nbytes += cnt;
210         }
211         elapsed = (nsec() - now) / 1E9;
212
213         fprintf(stderr, "ttcp-t: %lld bytes in %.2f real seconds = %.2f %s/sec\n",
214                 nbytes, elapsed, rate(nbytes, elapsed), unit);
215 }
216
217 void usage(void)
218 {
219         fprintf(stderr, "usage:\tttcp -t [options] host\n"
220               "\t\tttcp -r [options]\n"
221               " options:\n"
222               "  -f fmt\trate format: k,m,g,K,M,G = {kilo,mega,giga}{bit,byte}\n"
223               "  -l\t\tlength of buf (default 8192)\n"
224               "  -p port\tport number (default 5001)\n"
225               "  -n num\tnumber of bufs written (default 2048)\n"
226               "  -s\t\t-t: source a pattern to network\n"
227               "\t\t-r: sink (discard) all data from network\n"
228               );
229         exit(0);
230 }
231
232 void main(int argc, char *argv[])
233 {
234         int buflen = 8192;
235         int nbuf = 2048;
236         int srcsink = 0;
237         char *port = "5001";
238         int udp = 0;
239         enum { none, recv, xmit } mode = none;
240         char c;
241
242         while ((c = getopt(argc, argv, "rstuf:l:n:p:")) != -1) {
243                 switch (c) {
244                 case 'f':
245                         fmt = *optarg;
246                         break;
247                 case 'l':
248                         buflen = atoi(optarg);
249                         break;
250                 case 'n':
251                         nbuf = atoi(optarg);
252                         break;
253                 case 'p':
254                         port = optarg;
255                         break;
256                 case 'r':
257                         mode = recv;
258                         break;
259                 case 's':
260                         srcsink = 1;
261                         break;
262                 case 't':
263                         mode = xmit;
264                         break;
265                 case 'u':
266                         udp = 1;
267                         break;
268                 default:
269                         usage();
270                 }
271         }
272         switch (mode) {
273         case none:
274                 usage();
275                 break;
276         case xmit:
277                 if (optind == argc)
278                         usage();
279                 writer(udp, argv[optind], port, buflen, nbuf, srcsink);
280                 break;
281         case recv:
282                 reader(udp, "*", port, buflen, nbuf, srcsink);
283                 break;
284         }
285         exit(0);
286 }