home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / tcpspray.zip / tcpspray.c < prev    next >
C/C++ Source or Header  |  1996-08-22  |  9KB  |  408 lines

  1. /*
  2.  *      tcpspray.c  - v1.1
  3.  *
  4.  *      measure throughput of half (via discard) and full (via echo) duplex
  5.  *      tcp connection
  6.  *
  7.  *      Greg Christy <gmc@quotron.com>
  8.  *
  9.  *     12/15/90 - initial hack  
  10.  *       8/7/91 - clean-up time, first real version 
  11.  *      1/15/92 - add inter-buffer delay option
  12.  *      1/16/92 - clean up echo mode code, add #ifdef for AIX
  13.  */
  14.  
  15.  
  16. #include <stdio.h>
  17.  
  18. #include <malloc.h>
  19.  
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <sys/time.h>
  23. #include <netdb.h>
  24.  
  25. #include <netinet/in.h>
  26.  
  27. #define DEFBLKSIZE 1024        /* default  blocksize is 1k */
  28. #define DEFNBLKS 100        /* default number of blocks is 100 */
  29.  
  30. extern char *optarg;        /* external vars used by getopt(3) */
  31. extern int optind, opterr;
  32.  
  33. /*
  34.  * neat macro from ka9q to "do the right thing" with ansi prototypes
  35.  */
  36.  
  37. #ifndef __ARGS
  38. #ifdef __STDC__
  39. #define __ARGS(x)       x
  40. #else
  41. #define __ARGS(x)       ()
  42. #endif
  43. #endif
  44.  
  45. static void usage  __ARGS((char *argv[]));        /* forward declaration */
  46.  
  47.  
  48. #if !defined(sun) && !defined(_AIX)    /* sunos and aix define pid_t, */
  49.                     /* do others? */ 
  50. typedef int pid_t;
  51. #endif
  52.  
  53. #ifndef TRUE
  54. #define TRUE (1)
  55. #endif /*TRUE*/
  56.  
  57. #ifndef FALSE
  58. #define FALSE (0)
  59. #endif /*FALSE*/
  60.  
  61. int
  62.   main(argc, argv)
  63. unsigned int argc;
  64. char *argv[];
  65. {
  66.  
  67.   int eflag = FALSE;           /* use echo instead of discard for full duplex*/
  68.   int vflag = FALSE;            /* verbosity*/
  69.   int fflag = FALSE;        /* preload buffer with file */
  70.   int delay = 0;        /* inter-buffer delay in usecs */
  71.   pid_t pid = 0;        /* pid of receiver child */
  72.   int status;            /* return status of child */
  73.  
  74.   struct timeval start, end;    /* used to store start and end time of I/O */
  75.  
  76. #ifndef sun
  77.   struct timeval timeout;    /* used for timeout in select call */
  78. #endif /*sun*/
  79.  
  80.   double delta;            /* stores delta of start and end in sec  */
  81.  
  82.   /* generic counter */
  83.   register int cnt;
  84.  
  85.   int c;        /* used to return options from getopt(3) */
  86.  
  87.   struct sockaddr_in sin;    /* sockaddr for socket */
  88.   struct hostent *hp;        /* hostent for host name lookups */
  89.   struct servent *serv;        /* service entry for port lookup */
  90.  
  91.   int sock;            /* socket descriptor */
  92.   int fd[2];            /* descriptors for pipe */
  93.  
  94.   unsigned int blksize = DEFBLKSIZE; /* block size (1k default) */
  95.   unsigned int nblks = DEFNBLKS;    /* number of blocks (100 default)*/
  96.   unsigned int nbytes;        /* number of bytes to transfer */
  97.   register unsigned int bytes_left;    /* keep track of bytes left to */
  98.                     /* read/write */ 
  99.   register char *buf;        /* input and output buffer (malloced) */
  100.   register char *bufp;        /* placeholder pointer */
  101.  
  102.   FILE *infile;            /* used to preload buffer */
  103.  
  104.   while ((c = getopt(argc, argv, "vehb:n:f:d:")) != -1) {
  105.     switch (c) {
  106.     case 'v':
  107.       vflag = TRUE;
  108.       break;
  109.  
  110.     case 'e':
  111.       eflag = TRUE;
  112.       break;
  113.             
  114.     case 'h':
  115.       usage(argv);
  116.       break;
  117.  
  118.     case 'n':
  119.       nblks = atoi(optarg);
  120.       break;
  121.  
  122.     case 'b':
  123.       blksize = atoi(optarg);
  124.       break;
  125.  
  126.     case 'f':
  127.       fflag = TRUE;
  128.       if ((infile = fopen(optarg, "r")) == NULL) {
  129.     fprintf(stderr, "%s: Can't open file %s.\n", argv[0], optarg);
  130.     exit(2);
  131.       }
  132.       break;
  133.  
  134.     case 'd':
  135.       delay = atoi(optarg);
  136. #ifndef sun
  137. /* we need to fake usleep() with select() on non-sun machines */
  138.  
  139.       timeout.tv_usec = atoi(optarg) ;
  140.       timeout.tv_sec = 0;
  141. #endif /*sun*/
  142.  
  143.       break;
  144.  
  145.     default:
  146.       usage(argv);
  147.       break;
  148.     }
  149.   }
  150.  
  151.   if ((argc - optind) != 1)    /* we better have a host name */
  152.     usage(argv);
  153.     
  154.   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)  {
  155.     perror("socket");
  156.     exit(1);
  157.   }
  158.  
  159.   bzero((char *) &sin, sizeof(sin));
  160.   sin.sin_family = AF_INET;
  161.  
  162.   if (bind(sock, &sin, sizeof (sin)) == -1) {
  163.     perror("bind");
  164.     exit(1);
  165.   }
  166.  
  167.   hp = gethostbyname(argv[optind]);
  168.  
  169.   if (hp) {           /* try name first */
  170.     sin.sin_family = hp->h_addrtype;
  171.     bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
  172.   }
  173.  
  174.   else {            /* maybe it's a numeric address ?*/
  175.     sin.sin_family = AF_INET;
  176.     
  177.     if ((sin.sin_addr.s_addr = inet_addr(argv[optind])) == -1)  { 
  178.       /* nope, sorry we lose */
  179.       fprintf(stderr, "host not found: %s\n", argv[optind]);
  180.       exit(1);
  181.     }
  182.     
  183.   }
  184.   
  185.   serv = getservbyname(eflag ? "echo" : "discard", "tcp"); /* get port */
  186.   sin.sin_port = serv->s_port;
  187.  
  188.   if (connect(sock, &sin, sizeof(sin)) == -1) {
  189.     perror("connect");
  190.     exit(1);
  191.   }
  192.  
  193.   nbytes = nblks * blksize;    /* number of bytes to send/receive */ 
  194.  
  195.   if (vflag)
  196.     printf("Sending %d bytes with blocksize %d bytes\n",
  197.        nbytes, blksize); 
  198.     
  199.   if ((buf =  malloc((blksize < 4096) ? 4096 : blksize)) == NULL) {
  200.     perror("malloc buf");
  201.     exit(1);
  202.   }
  203.  
  204.   bzero(buf, blksize);        /* clean out the buffer */
  205.  
  206.   if (fflag) {            /* preload buffer with file */
  207.     cnt = fread(buf, sizeof(u_char), blksize, infile);
  208.     if (cnt < blksize)
  209.       fprintf(stderr, "Warning! File is smaller than blocksize.\n");
  210.   }
  211.  
  212.  
  213.   if (eflag) {
  214.     if (pipe(fd) == -1) {    /* create pipe for return */
  215.       perror("pipe");
  216.       exit(1);
  217.     }
  218.     
  219.     if ((pid = fork()) == -1) { /* fork off a receiver */
  220.       perror("fork()");
  221.       exit(1);
  222.     }
  223.   }
  224.   if (eflag && pid != 0) {            /* we are the receiver */
  225.     close (fd[1]);
  226.     bytes_left = nblks * blksize;
  227.  
  228.     if (gettimeofday(&start, NULL) == -1) {
  229.       perror("gettimeofday");
  230.       exit(1);
  231.     }
  232.     if (vflag) {
  233.       register int flush_flag = FALSE, blk_boundry = bytes_left - blksize;
  234.  
  235.       while (bytes_left) {
  236.     if ((cnt = read(sock, buf, bytes_left)) == -1)  {
  237.       perror("receive:");
  238.       exit(2);
  239.     }
  240.  
  241.     bytes_left -= cnt;
  242.     
  243.     while (blk_boundry > bytes_left) {
  244.       fputs("\b \b", stdout);
  245.       flush_flag = TRUE;
  246.       blk_boundry -= blksize;
  247.     }
  248.     if (flush_flag) {
  249.       fflush(stdout);
  250.       flush_flag = FALSE;
  251.     }
  252.       }
  253.       if (gettimeofday(&end, NULL) == -1) {
  254.     perror("gettimeofday");
  255.     exit(1);
  256.       }
  257.       printf("\b");
  258.       fflush(stdout);
  259.     }
  260.     else {            /* not vflag */
  261.       while (bytes_left) {
  262.     
  263.     if ((cnt = read(sock, buf, bytes_left)) == -1)  {
  264.       perror("receive:");
  265.       exit(2);
  266.     }
  267.     bytes_left -= cnt;
  268.       
  269.       }
  270.       if (gettimeofday(&end, NULL) == -1) {
  271.     perror("gettimeofday");
  272.     _exit(1);
  273.       }
  274.     }
  275.     
  276.     delta = (double) (end.tv_sec - start.tv_sec) + (double)
  277.       ((double) (end.tv_usec - start.tv_usec) / 1000000.0);
  278.     printf("Received %d bytes in %f seconds (%0.3f kbytes/s)\n",
  279.        nbytes, delta, (double) (nbytes / delta) /1024);
  280.   
  281.     if (wait(&status) == -1) {/* wait for child lest we */
  282.                        /* unleash zombies */ 
  283.       perror("wait");
  284.       exit(1);
  285.     }
  286.     
  287.     if (status) {
  288.       fprintf(stderr, "child returned non-zero status %d\n", status);
  289.     }
  290.     /* get delta from transmitter process */
  291.     if ((cnt = read(fd[0], (char *) &delta, sizeof(delta))) == -1) {
  292.       perror("read pipe");
  293.       exit(1);
  294.     }
  295.     printf("Transmitted %d bytes in %f seconds (%0.3f kbytes/s)\n",
  296.        nbytes, delta, (double) (nbytes / delta) / 1024); 
  297.     
  298.   }
  299.   else {            /* we are the transmitter */
  300.  
  301.     if (vflag) {
  302.       if (gettimeofday(&start, NULL) == -1) {
  303.     perror("gettimeofday");
  304.     exit(1);
  305.       }
  306.     
  307.       while (nblks--) {
  308.     cnt = 0;
  309.     bufp = buf;
  310.     bytes_left = blksize;
  311.     do {
  312.       if ((cnt = write(sock, bufp, bytes_left)) == -1)  {
  313.         perror("receive:");
  314.         exit(2);
  315.       }
  316.       bufp += cnt;
  317.       bytes_left -= cnt;
  318.  
  319. #ifdef sun
  320.       if (delay)
  321.         usleep(delay);
  322. #else /*sun*/
  323.       if (delay)
  324.         select(0, NULL, NULL, NULL, timeout);
  325. #endif /*sun*/
  326.  
  327.     } while (bytes_left);
  328.     putchar('.');
  329.     fflush(stdout);
  330.       }
  331.   
  332.       if (gettimeofday(&end, NULL) == -1) {
  333.     perror("gettimeofday");
  334.     exit(1);
  335.       }
  336.     }
  337.     else {            /* not vflag */
  338.       if (gettimeofday(&start, NULL) == -1) {
  339.     perror("gettimeofday");
  340.     exit(1);
  341.       }
  342.       
  343.       while (nblks--) {
  344.     cnt = 0;
  345.     bufp = buf;
  346.     bytes_left = blksize;
  347.     do {
  348.       if ((cnt = write(sock, bufp, bytes_left)) == -1)  {
  349.         perror("receive:");
  350.         exit(2);
  351.       }
  352.       bufp += cnt;
  353.       bytes_left -= cnt;
  354.  
  355. #ifdef sun
  356.       if (delay)
  357.         usleep(delay);
  358. #else /*sun*/
  359.       if (delay)
  360.         select(0, NULL, NULL, NULL, timeout);
  361. #endif /*sun*/
  362.  
  363.     } while (bytes_left);
  364.       }
  365.  
  366.       if (gettimeofday(&end, NULL) == -1) {
  367.     perror("gettimeofday");
  368.     exit(1);
  369.       }
  370.     }
  371.     delta = (double) (end.tv_sec - start.tv_sec) + (double)
  372.       ((double) (end.tv_usec - start.tv_usec) / 1000000.0);
  373.  
  374.     /* write delta value to pipe */
  375.  
  376.     if (eflag) {
  377.       if ((cnt = write(fd[1], (char *) &delta, sizeof(delta))) == -1) {
  378.     perror("write pipe");
  379.     exit(1);
  380.       }
  381.       exit(0);
  382.     }
  383.     else
  384.       
  385.       printf("\nTransmitted %d bytes in %f seconds (%0.3f kbytes/s)\n",
  386.          nbytes, delta, (double) (nbytes / delta) / 1024); 
  387.  
  388.   }
  389.   
  390.   exit(0);
  391. }
  392.  
  393.  
  394. static void
  395.   usage(argv)
  396. char *argv[];
  397. {
  398.   fprintf(stderr, "usage: %s [-v] [-e] [-h] [-b blksize] [-n nblks] [-f file] host\n", argv[0]);
  399.   fprintf(stderr, "      -v verbose\n");
  400.   fprintf(stderr, "      -e use echo service for full duplex transfer\n");
  401.   fprintf(stderr, "      -h print this message\n");
  402.   fprintf(stderr, "      -b blocksize in bytes (default 1024)\n");
  403.   fprintf(stderr, "      -n number of blocks (default 100)\n");
  404.   fprintf(stderr, "      -f file to preload buffer (zero buffer by default)\n");
  405.   fprintf(stderr, "      -d inter-buffer transmission delay in usecs (default 0)\n");
  406.   exit(1);
  407. }
  408.