chiark / gitweb /
Add __oop-read-copy.c
[innduct.git] / contrib / newsresp.c
1 /* newsresp.c - EUnet - bilse */
2
3 /*
4  * From: Koen De Vleeschauwer <koen@eu.net>
5  * Subject: Re: innfeed-users: innfeed: measuring server response time
6  * To: jeff.garzik@spinne.com (Jeff Garzik)
7  * Date: Tue, 13 May 1997 16:33:27 +0200 (MET DST)
8  * Cc: innfeed-users@vix.com
9  * 
10  * > Is there an easy way to measure server response time, and print it out
11  * > on the innfeed status page?  Cyclone's nntpTime measures login banner
12  * > response time and an article add and lookup operation. 
13  * > 
14  * > It seems to me that innfeed could do something very similar.  It could
15  * > very easily sample gettimeofday() or Time.Now to determine a remote
16  * > server's average response time for lookups, lookup failures, article
17  * > send throughput, whatever.
18  * > 
19  * > These statistics might be invaluable to developers creating advanced
20  * > connection and article delivery algorithms.  If I knew, for example,
21  * > that a site's article send/save throughput was really fast, but history
22  * > lookups were really slow, my algorithm could reserve a channel or two
23  * > for TAKETHIS-only use.
24  * 
25  * We use a stand-alone program which opens up an additional nntp channel
26  * from time to time and takes a peek at the various response times.
27  * It's also interesting to tune one's own box.
28  * I've included the source code; please consider this supplied 'as is';
29  * bugs and features alike. SunOS, Solaris and Irix ought to be ok;
30  * eg. gcc -traditional -o newsresp ./newsresp.c -lnsl -lsocket on S0laris.
31  * If a host has an uncommonly long banner you may have to change a constant 
32  * somewhere; forget. Please note one has to interpret the output; 
33  * eg. whether one is measuring rtt or history lookup time.
34  * 
35  * Basic usage is:
36  * news 1 % newsresp -n 5 news.eu.net
37  * ---------------------------------
38  * news.eu.net is 134.222.90.2 port 119
39  *  elap  diff
40  *   0.0   0.0  Connecting ...
41  *   0.0   0.0  OK, waiting for prompt
42  *   0.0   0.0  <<< 200 EU.net InterNetNews server INN 1.5.1 17-Dec-1996 re [...]
43  *   0.0   0.0  >>> ihave <244796399@a>
44  *   0.0   0.0  <<< 335 
45  *   0.0   0.0  >>> .
46  *   0.0   0.0  <<< 437 Empty article 
47  *   0.0   0.0  >>> ihave <244796398@a>
48  *   0.0   0.0  <<< 335 
49  *   0.0   0.0  >>> .
50  *   0.0   0.0  <<< 437 Empty article 
51  *   0.0   0.0  >>> ihave <244796397@a>
52  *   0.0   0.0  <<< 335 
53  *   0.0   0.0  >>> .
54  *   0.0   0.0  <<< 437 Empty article 
55  *   0.0   0.0  >>> ihave <244796396@a>
56  *   0.1   0.0  <<< 335 
57  *   0.1   0.0  >>> .
58  *   0.1   0.0  <<< 437 Empty article 
59  *   0.1   0.0  >>> ihave <244796395@a>
60  *   0.1   0.0  <<< 335 
61  *   0.1   0.0  >>> .
62  *   0.1   0.0  <<< 437 Empty article 
63  *   0.1   0.0  >>> quit
64  *   0.1   0.0  <<< 205 . 
65  */
66
67 #include <stdio.h>
68 #include <sys/types.h>
69 #include <sys/time.h>
70 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #include <netdb.h>
73 #include <errno.h>
74
75 #define NNTPPORT 119
76 struct sockaddr_in sock_in;
77 int sock;
78 char buf[1024];
79
80 main(argc,argv)
81 int argc;
82 char *argv[];
83 {
84   int errflg = 0, c;
85   extern char *optarg;
86   extern int optind;
87   struct hostent *host;
88   unsigned long temp;
89   unsigned numart = 1;
90   struct protoent *tcp_proto;
91   char **whoP;
92
93   while ( (c = getopt(argc,argv,"n:")) != -1 )
94     switch ( c ) {
95     case 'n': sscanf(optarg,"%u",&numart); break;
96     default : errflg++;
97   }
98   if ( numart == 0 || optind == argc )
99     errflg++;
100   if ( errflg ) {
101     fprintf(stderr,"Usage: %s [-n articles] host ...\n",argv[0]);
102     exit(1);
103   }
104
105   if ( (tcp_proto = getprotobyname("tcp")) == 0 )
106     fatal("getprotobyname");
107   for ( whoP = argv+optind; *whoP != 0; whoP++ ) {
108     if ( (sock = socket(PF_INET,SOCK_STREAM,tcp_proto->p_proto)) < 0 )
109       fatal("socket");
110     temp = inet_addr(*whoP);
111     if ( temp != (unsigned long) -1 ) {
112       sock_in.sin_addr.s_addr = temp;
113       sock_in.sin_family = AF_INET;
114     }
115     else {
116       host = gethostbyname(*whoP);
117       if ( host ) {
118         sock_in.sin_family = host->h_addrtype;
119         memcpy(&sock_in.sin_addr,host->h_addr,host->h_length);
120       }
121       else {
122         fprintf(stderr,"gethostbyname can't find %s\n",*whoP);
123         exit(1);
124       }
125     }
126     sock_in.sin_port = htons(NNTPPORT);
127     printf("---------------------------------\n%s is %s port %d\n",
128                *whoP,inet_ntoa(sock_in.sin_addr),ntohs(sock_in.sin_port));
129     punt(numart);
130     close(sock);
131   }
132 }
133
134 error(what)
135 char *what;
136 {
137   ptime(); fflush(stdout);
138   perror(what);
139 }
140
141 fatal(what)
142 char *what;
143 {
144   error(what);
145   exit(2);
146 }
147
148 ierror(how,what)
149 char *how, *what;
150 {
151   printf("Expected %s, bailing out.\n",how);
152 }
153
154 ifatal(how,what)
155 char *how, *what;
156 {
157   ierror(how,what);
158   exit(1);
159 }
160
161 unsigned do_time(start)
162 unsigned start;
163 {
164   struct timeval now;
165
166   gettimeofday(&now,(struct timezone *)0);
167   return ( now.tv_sec*1000 + now.tv_usec/1000 - start );
168 }
169
170
171 unsigned start, elapsed, diff;
172
173 ptime()
174 {
175   diff = elapsed;
176   elapsed = do_time(start);
177   diff = elapsed - diff;
178   printf("%5.1f %5.1f  ",((float)elapsed)/1000.0,((float)diff)/1000.0);
179 }
180
181 massagebuff(bread,buf)
182 int bread;
183 char *buf;
184 {
185   char *p;
186
187   if ( bread > 55 )
188     strcpy(buf+55," [...]\n");
189   else
190     buf[bread] = '\0';
191   for ( p = buf; *p != '\0'; )
192     if ( *p != '\r' )  /* We like to do it RISC style. */
193       p++;
194     else {
195       *p = ' ';
196       p++;
197     }
198 }
199
200 punt(numart)
201 int numart;
202 {
203   static char ihave[32],
204               dot[] = ".\r\n",
205               quit[] = "quit\r\n";
206   struct timeval start_tv;
207   int bread;
208
209   printf(" elap  diff\n");
210   diff = elapsed = 0;
211   gettimeofday(&start_tv,(struct timezone *)0);
212   start = start_tv.tv_sec*1000 + start_tv.tv_usec/1000;
213
214   ptime();
215   printf("Connecting ...\n");
216   if ( connect(sock,(struct sockaddr*)&sock_in,sizeof(sock_in)) < 0 ) {
217     error("connect");
218     return(-1);
219   }
220   ptime();
221   printf("OK, waiting for prompt\n");
222
223   if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
224     error("read socket");
225     return(-1);
226   }
227   massagebuff(bread,buf);
228   ptime();
229   printf("<<< %s",buf);
230   if ( strncmp(buf,"200",3) != 0 && strncmp(buf,"201",3) != 0 ) {
231     ierror("200 or 201",buf);
232     return(-1);
233   }
234
235   do {
236     snprintf(ihave,sizeof(ihave),"ihave <%u@a>\r\n",start+numart);
237     ptime();
238     printf(">>> %s",ihave);
239     if ( write(sock,ihave,strlen(ihave)) != strlen(ihave) ) {
240       error("write socket");
241       return(-1);
242     }
243
244     if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
245       error("read socket");
246       return(-1);
247     }
248     massagebuff(bread,buf);
249     ptime();
250     printf("<<< %s",buf);
251     if ( strncmp(buf,"335",3) != 0 && strncmp(buf,"435",3) != 0 ) {
252       ierror("335 or 435 ",buf);
253       return(-1);
254     }
255
256     if ( strncmp(buf,"335",3) == 0 ) {
257       ptime();
258       printf(">>> %s",dot);
259       if ( write(sock,dot,sizeof(dot)-1) != sizeof(dot)-1 ) {
260         error("write socket");
261         return(-1);
262       }
263
264       if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
265         error("read socket");
266         return(-1);
267       }
268       massagebuff(bread,buf);
269       ptime();
270       printf("<<< %s",buf);
271       if ( strncmp(buf,"437",3) != 0 && strncmp(buf,"235",3) != 0 ) {
272         ierror("437 or 235",buf);
273         return(-1);
274       }
275     }
276   } while ( --numart != 0 );
277
278   ptime();
279   printf(">>> %s",quit);
280   if ( write(sock,quit,sizeof(quit)-1) != sizeof(quit)-1 ) {
281     error("write socket");
282     return(-1);
283   }
284
285   if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
286     error("read socket");
287     return(-1);
288   }
289   massagebuff(bread,buf);
290   ptime();
291   printf("<<< %s",buf);
292   if ( strncmp(buf,"205",3) != 0 ) {
293     ierror("205",buf);
294     return(-1);
295   }
296   return(0);
297 }