OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / tcpblast / tcpblast.c
1 /*      From FreeBSD: */
2 /*
3  *      tcpblast - test and estimate TCP thruput
4  *
5  *      Daniel Karrenberg   <dfk@nic.eu.net>
6  */
7
8 /*
9  *      Changes: Rafal Maszkowski <rzm@icm.edu.pl>
10  *
11  *      ftp://6bone-gw.6bone.pl/pub/blast/README
12  */
13
14 char *vdate=
15 #include "version.h"
16 , verstr[30]="FreeBSD + rzm ";
17
18 #include <sys/types.h>
19 #include <getopt.h>
20 #include <netdb.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>    /* for Solaris */
27 #include <sys/file.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <unistd.h>
31 #include <errno.h>
32
33 #if defined(__sunos__) || defined(__osf1__)
34 #define strerror(x)     atoi(x)
35 char * gettext(x) char *x; { return x; }
36 #endif
37
38 #define DEFBLKSIZE (1024)
39 #define MAXBLKSIZE (32*1024)
40
41 struct  sockaddr_in sock_in;
42 struct  servent *sp;
43 struct  hostent *host;
44
45 unsigned long starts, startms, stops, stopms, expms;
46 struct timeval ti; 
47 struct timezone tiz;
48
49 char    greet[MAXBLKSIZE], *ind;
50 int     nblocks, f;
51 int tcp=0, udp=0, randomb=0, blksize=DEFBLKSIZE, setbufsize=-1, dots=1, continuous=0, experimental=0;
52 char port[30]="9";
53
54 /* Long options.  */
55 static const struct option long_options[] =
56 {
57   { "help", no_argument, NULL, 'h' },
58   { "version", no_argument, NULL, 'V' },
59   { NULL, 0, NULL, 0 }
60 };
61
62 void usage(name)
63 char    *name;
64 {       
65         fprintf(stderr, "\n");
66         fprintf(stderr, "usage: %s [options] destination nblocks\n\n", name);
67         fprintf(stderr, "tcpblast/udpblast is a simple tool for probing network and estimating its\n");
68         fprintf(stderr, "throughput. It sends nblocks of %d B blocks of data to specified\n", blksize);
69         fprintf(stderr, "destination host\n\n");
70         fprintf(stderr, "Options:\n");
71         fprintf(stderr, "-b nnn         socket buf size (default: %d == %s)\n", setbufsize, setbufsize==-1 ? "don't change" : "change");
72         fprintf(stderr, "-c             display speed continuously\n");
73         fprintf(stderr, "-d nnn         print dot every nnn blocks, 0 disables (default %d)\n", dots);
74         fprintf(stderr, "-e             add experimental way of calculating throuput\n");
75 /*      fprintf(stderr, "-f FILE        send FILE instead of generated data\n"); */
76         fprintf(stderr, "-h, --help     this help\n");
77         fprintf(stderr, "-p xyz         use port #/name xyz instead of default %s\n", port);
78         fprintf(stderr, "-r             send random data\n");
79         fprintf(stderr, "-s nnn         block size (default %d bytes)\n", blksize);
80         fprintf(stderr, "-t             use TCP (%s)\n", ind[0]=='t' ? "default" : "default if named tcpblast" );
81         fprintf(stderr, "-u             use UDP (%s)\n", ind[0]=='u' ? "default" : "default if named udpblast" );
82         fprintf(stderr, "-V, --version  version\n");
83         fprintf(stderr, "destination    host name or address\n");
84         fprintf(stderr, "nblocks        number of blocks (1..9999)\n");
85         fprintf(stderr, "\n");
86         fprintf(stderr, "%s version: %s\n", name, verstr);
87         exit(1);
88 }
89
90 void usage_small(name)
91 char    *name;
92 {       
93         fprintf(stderr, "type %s --help for help\n", name);
94 }
95
96 /* randomize the buffer */
97 void
98 randbuff(blksize) 
99 int blksize;
100 {
101         int i;
102         for (i=0; i<blksize; i++) {
103                 greet[i]=rand() % 256;
104         }
105 }
106
107 long
108 gettdiff()
109 {
110         if (gettimeofday(&ti, &tiz) < 0)
111         {
112                 perror("tcp/udpblast time:");
113                 exit(11);
114         }
115         stops  = ti.tv_sec;
116         stopms = ti.tv_usec / 1000L;
117
118         return (stops-starts)*1000 + (stopms-startms);
119 }
120
121 void
122 printresult(expms, datasize, buffer)
123 long expms;
124 int datasize, buffer;
125 {
126         printf("%5d KB in %7ld msec", datasize/1024, expms);
127 #ifdef __uClinux__
128         /* Use integer arithmetic only. */
129         printf("  =  %8lld b/s", (unsigned long long) (datasize-buffer) * 8000 / expms);
130         printf("  =  %7lld B/s", (unsigned long long) (datasize-buffer) * 1000 / expms);
131         printf("  =  %7lld KB/s", 
132                 (unsigned long long) (datasize-buffer) * 1000 / (expms * 1024) );
133 #else
134         printf("  =  %8.1f b/s", ((double)datasize-buffer)/expms*8000);
135         printf("  =  %7.1f B/s", ((double)datasize-buffer)/expms*1000);
136         printf("  =  %7.2f KB/s", 
137                 ((double)datasize-buffer) / (double) (expms*1024.0) * 1000 );
138 #endif
139         fflush(stdout);
140 }
141
142 int
143 main(argc, argv)
144      int argc;
145      char **argv;
146 {       register int i;
147         int optchar;
148         struct servent *service;
149         int bufsize;
150
151         strcat(verstr, vdate);
152
153         /* non-random data - is modem compressing it? */
154         bzero(greet, MAXBLKSIZE);
155         memset(greet, 'a', MAXBLKSIZE); 
156
157         /* find first letter in the name - usage() needs it */
158         ind=rindex(argv[0], '/');
159         if (ind==NULL) ind=argv[0]; else ind++;
160
161         while ((optchar = getopt_long (argc, argv, "tup:rs:b:d:Vhc", long_options, NULL)) != EOF)
162         switch (optchar) {
163                 case '\0': break;
164                 case 't': if (tcp==0) tcp=1;            break;
165                 case 'u': if (udp==0) udp=1;            break;
166                 case 'r': srand(0 /* may be an option */); randomb=1;   break;
167                 case 's': blksize=abs(atoi(optarg));    break;
168                 case 'b': setbufsize=abs(atoi(optarg)); break;
169                 case 'c': continuous=1;                 break;
170                 case 'd': dots=abs(atoi(optarg));       break;
171                 case 'e': experimental=1;               break;
172                 case 'p': strncpy(port, optarg, sizeof(port)-1);        break;
173                 case 'V': printf("%s version: %s\n", argv[0], verstr);  return 0;       break;
174                 case 'h': usage(argv[0]);
175                 default: ;
176         }
177
178 /* correctness */
179         if (tcp && udp) {
180                 printf("cannot use both TCP and UDP\n");
181                 usage_small(argv[0]);
182                 exit(2);
183         }
184
185         /* if neither -t nor -u is chosen use first character of the
186            program name */
187                 if ( (tcp==0) && (udp==0) && (ind[0]=='t') ) tcp=1;
188                 if ( (tcp==0) && (udp==0) && (ind[0]=='u') ) udp=1;
189
190         if (!tcp && !udp) {
191                 printf("must use either TCP or UDP\n");
192                 usage_small(argv[0]);
193                 exit(3);
194         }
195
196         if (continuous) dots=0;
197
198         /* after options processing we need two args left */
199         if (argc - optind != 2) {
200                 if (argc - optind != 0) printf("give both hostname and block count\n");
201                 usage_small(argv[0]);
202                 exit(4);
203         }
204
205         nblocks = atoi(argv[optind+1]);
206         if (nblocks<=0 || nblocks>=INT_MAX) {
207                 fprintf(stderr, "%s: 1 < nblocks <= %d \n", argv[0], INT_MAX);
208                 exit(5);
209         }
210
211
212         bzero((char *)&sock_in, sizeof (sock_in));
213         sock_in.sin_family = AF_INET;
214         if (tcp) f = socket(AF_INET, SOCK_STREAM, 0);
215         else     f = socket(AF_INET, SOCK_DGRAM, 0);
216         if (f < 0) {
217                 perror("tcp/udpblast: socket");
218                 exit(6);
219         }
220
221         { int size=sizeof(int); /* getsockopt() should know how much space we have */
222                 /* get/setsockopt doesn't return any error really for SO_SNDBUF,
223                    at least on Linux; it limits the buffer to [2048..65536]
224                    (131070 for 2.1 (?) but you can manipulate with /proc/sys/net/core/wmem_max ) */
225                 if (getsockopt(f, SOL_SOCKET, SO_SNDBUF, &bufsize, &size)==-1)
226                         printf("tcp/udpblast getsockopt: %s", strerror(errno));
227                 printf("read SO_SNDBUF = %d\n", bufsize);
228                 if (setbufsize!=-1) {
229                         if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &setbufsize, sizeof(setbufsize))==-1)
230                                 printf("tcp/udpblast getsockopt: %s", strerror(errno));
231                         if (getsockopt(f, SOL_SOCKET, SO_SNDBUF, &bufsize, &size)==-1) /* size value's been set b4 */
232                                 printf("tcp/udpblast getsockopt: %s", strerror(errno));
233                         printf("set  SO_SNDBUF = %d\n", bufsize);
234                 }
235         }
236
237         if (bind(f, (struct sockaddr*)&sock_in, sizeof (sock_in)) < 0) {
238                 perror("tcp/udpblast: bind");
239                 exit(7);
240         }
241
242         host = gethostbyname(argv[optind]);
243         if (host) {
244                 sock_in.sin_family = host->h_addrtype;
245                 bcopy(host->h_addr, &sock_in.sin_addr, host->h_length);
246         } else {
247                 sock_in.sin_family = AF_INET;
248                 sock_in.sin_addr.s_addr = inet_addr(argv[optind]);
249                 if (sock_in.sin_addr.s_addr == -1) {
250                         fprintf(stderr, "%s: %s unknown host\n", argv[0], argv[optind]);
251                         exit(8);
252                 }
253         }
254
255 /* port # or name can be used */
256         service = getservbyname(port, tcp ? "tcp" : "udp");
257         if (service==NULL) sock_in.sin_port = htons(abs(atoi(port)));
258         else               sock_in.sin_port = service->s_port;
259
260         if (connect(f, (struct sockaddr*)&sock_in, sizeof(sock_in)) <0)
261         {
262                 perror("tcp/udpblast connect:");
263                 exit(9);
264         }
265
266         printf("Sending %s %s data using %d B blocks.\n",
267                 randomb ? "random":"non-random", tcp ? "TCP":"UDP", blksize);
268
269         if (gettimeofday(&ti, &tiz) < 0)
270         {
271                 perror("tcp/udpblast time:");
272                 exit(10);
273         }
274         starts  = ti.tv_sec;
275         startms = ti.tv_usec / 1000L;
276
277
278         for (i=0; i<nblocks; i++)
279         {
280                 if (randomb) randbuff(blksize);
281                 if (write(f, greet, (size_t)blksize) != blksize)
282                         perror("tcp/udpblast send:");
283                 if ( (dots!=0) && ( (dots==1) || (i%dots==1) ) ) write(1, ".", 1);
284                 if ( continuous == 1 ) {
285                         expms = gettdiff();
286                         printf("\r");
287                         printresult(expms, i*blksize, experimental ? bufsize : 0);
288                 }
289         }
290
291         expms = gettdiff();
292         if (dots!=0) printf("\n");
293         if (continuous) printf("\r");
294         printresult(expms, nblocks*blksize, 0);
295         if (experimental && (bufsize>0) && (nblocks*blksize>bufsize)) {
296                 printf("\nExperimentally taking into account %d B socket buffer:\n", bufsize);
297                 printresult(expms, nblocks*blksize, bufsize);
298         }
299         printf("\n");
300
301         return(0);
302 }