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