webbench
socket.c
1 /* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $ 2 * 3 * This module has been modified by Radim Kolar for OS/2 emx 4 */ 5 6 /*********************************************************************** 7 module: socket.c 8 program: popclient 9 SCCS ID: @(#)socket.c 1.5 4/1/94 10 programmer: Virginia Tech Computing Center 11 compiler: DEC RISC C compiler (Ultrix 4.1) 12 environment: DEC Ultrix 4.3 13 description: UNIX sockets code. 14 ***********************************************************************/ 15 16 #include <sys/types.h> 17 #include <sys/socket.h> 18 #include <fcntl.h> 19 #include <netinet/in.h> 20 #include <arpa/inet.h> 21 #include <netdb.h> 22 #include <sys/time.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <stdarg.h> 28 29 int Socket(const char *host, int clientPort) 30 { 31 int sock; 32 unsigned long inaddr; 33 struct sockaddr_in ad; 34 struct hostent *hp; 35 36 memset(&ad, 0, sizeof(ad)); 37 ad.sin_family = AF_INET; 38 39 inaddr = inet_addr(host); 40 if (inaddr != INADDR_NONE) 41 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); 42 else 43 { 44 hp = gethostbyname(host); 45 if (hp == NULL) 46 return -1; 47 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); 48 } 49 ad.sin_port = htons(clientPort); 50 51 sock = socket(AF_INET, SOCK_STREAM, 0); 52 if (sock < 0) 53 return sock; 54 if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) 55 return -1; 56 return sock; 57 }
webbench.c
1 /* 2 * (C) Radim Kolar 1997-2004 3 * This is free software, see GNU Public License version 2 for 4 * details. 5 * 6 * Simple forking WWW Server benchmark: 7 * 8 * Usage: 9 * webbench --help 10 * 11 * Return codes: 12 * 0 - sucess 13 * 1 - benchmark failed (server is not on-line) 14 * 2 - bad param 15 * 3 - internal error, fork failed 16 * 17 */ 18 #include "socket.c" 19 #include <unistd.h> 20 #include <sys/param.h> 21 #include <rpc/types.h> 22 #include <getopt.h> 23 #include <strings.h> 24 #include <time.h> 25 #include <signal.h> 26 27 /* values */ 28 volatile int timerexpired=0; 29 int speed=0; 30 int failed=0; 31 int bytes=0; 32 /* globals */ 33 int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ 34 /* Allow: GET, HEAD, OPTIONS, TRACE */ 35 #define METHOD_GET 0 36 #define METHOD_HEAD 1 37 #define METHOD_OPTIONS 2 38 #define METHOD_TRACE 3 39 #define PROGRAM_VERSION "1.5" 40 int method=METHOD_GET; 41 int clients=1; 42 int force=0; 43 int force_reload=0; 44 int proxyport=80; 45 char *proxyhost=NULL; 46 int benchtime=30; 47 /* internal */ 48 int mypipe[2]; 49 char host[MAXHOSTNAMELEN]; 50 #define REQUEST_SIZE 2048 51 char request[REQUEST_SIZE]; 52 53 static const struct option long_options[]= 54 { 55 {"force",no_argument,&force,1}, 56 {"reload",no_argument,&force_reload,1}, 57 {"time",required_argument,NULL,'t'}, 58 {"help",no_argument,NULL,'?'}, 59 {"http09",no_argument,NULL,'9'}, 60 {"http10",no_argument,NULL,'1'}, 61 {"http11",no_argument,NULL,'2'}, 62 {"get",no_argument,&method,METHOD_GET}, 63 {"head",no_argument,&method,METHOD_HEAD}, 64 {"options",no_argument,&method,METHOD_OPTIONS}, 65 {"trace",no_argument,&method,METHOD_TRACE}, 66 {"version",no_argument,NULL,'V'}, 67 {"proxy",required_argument,NULL,'p'}, 68 {"clients",required_argument,NULL,'c'}, 69 {NULL,0,NULL,0} 70 }; 71 72 /* prototypes */ 73 static void benchcore(const char* host,const int port, const char *request); 74 static int bench(void); 75 static void build_request(const char *url); 76 77 static void alarm_handler(int signal) 78 { 79 timerexpired=1; 80 } 81 82 static void usage(void) 83 { 84 fprintf(stderr, 85 "webbench [option]... URL\n" 86 " -f|--force Don't wait for reply from server.\n" 87 " -r|--reload Send reload request - Pragma: no-cache.\n" 88 " -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n" 89 " -p|--proxy <server:port> Use proxy server for request.\n" 90 " -c|--clients <n> Run <n> HTTP clients at once. Default one.\n" 91 " -9|--http09 Use HTTP/0.9 style requests.\n" 92 " -1|--http10 Use HTTP/1.0 protocol.\n" 93 " -2|--http11 Use HTTP/1.1 protocol.\n" 94 " --get Use GET request method.\n" 95 " --head Use HEAD request method.\n" 96 " --options Use OPTIONS request method.\n" 97 " --trace Use TRACE request method.\n" 98 " -?|-h|--help This information.\n" 99 " -V|--version Display program version.\n" 100 ); 101 }; 102 int main(int argc, char *argv[]) 103 { 104 int opt=0; 105 int options_index=0; 106 char *tmp=NULL; 107 108 if(argc==1) 109 { 110 usage(); 111 return 2; 112 } 113 114 while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ) 115 { 116 switch(opt) 117 { 118 case 0 : break; 119 case 'f': force=1;break; 120 case 'r': force_reload=1;break; 121 case '9': http10=0;break; 122 case '1': http10=1;break; 123 case '2': http10=2;break; 124 case 'V': printf(PROGRAM_VERSION"\n");exit(0); 125 case 't': benchtime=atoi(optarg);break; 126 case 'p': 127 /* proxy server parsing server:port */ 128 tmp=strrchr(optarg,':'); 129 proxyhost=optarg; 130 if(tmp==NULL) 131 { 132 break; 133 } 134 if(tmp==optarg) 135 { 136 fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg); 137 return 2; 138 } 139 if(tmp==optarg+strlen(optarg)-1) 140 { 141 fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg); 142 return 2; 143 } 144 *tmp='\0'; 145 proxyport=atoi(tmp+1);break; 146 case ':': 147 case 'h': 148 case '?': usage();return 2;break; 149 case 'c': clients=atoi(optarg);break; 150 } 151 } 152 153 if(optind==argc) { 154 fprintf(stderr,"webbench: Missing URL!\n"); 155 usage(); 156 return 2; 157 } 158 159 if(clients==0) clients=1; 160 if(benchtime==0) benchtime=60; 161 /* Copyright */ 162 fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n" 163 "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n" 164 ); 165 build_request(argv[optind]); 166 /* print bench info */ 167 printf("\nBenchmarking: "); 168 switch(method) 169 { 170 case METHOD_GET: 171 default: 172 printf("GET");break; 173 case METHOD_OPTIONS: 174 printf("OPTIONS");break; 175 case METHOD_HEAD: 176 printf("HEAD");break; 177 case METHOD_TRACE: 178 printf("TRACE");break; 179 } 180 printf(" %s",argv[optind]); 181 switch(http10) 182 { 183 case 0: printf(" (using HTTP/0.9)");break; 184 case 2: printf(" (using HTTP/1.1)");break; 185 } 186 printf("\n"); 187 if(clients==1) printf("1 client"); 188 else 189 printf("%d clients",clients); 190 191 printf(", running %d sec", benchtime); 192 if(force) printf(", early socket close"); 193 if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport); 194 if(force_reload) printf(", forcing reload"); 195 printf(".\n"); 196 return bench(); 197 } 198 199 void build_request(const char *url) 200 { 201 char tmp[10]; 202 int i; 203 204 bzero(host,MAXHOSTNAMELEN); 205 bzero(request,REQUEST_SIZE); 206 207 if(force_reload && proxyhost!=NULL && http10<1) http10=1; 208 if(method==METHOD_HEAD && http10<1) http10=1; 209 if(method==METHOD_OPTIONS && http10<2) http10=2; 210 if(method==METHOD_TRACE && http10<2) http10=2; 211 212 switch(method) 213 { 214 default: 215 case METHOD_GET: strcpy(request,"GET");break; 216 case METHOD_HEAD: strcpy(request,"HEAD");break; 217 case METHOD_OPTIONS: strcpy(request,"OPTIONS");break; 218 case METHOD_TRACE: strcpy(request,"TRACE");break; 219 } 220 221 strcat(request," "); 222 223 if(NULL==strstr(url,"://")) 224 { 225 fprintf(stderr, "\n%s: is not a valid URL.\n",url); 226 exit(2); 227 } 228 if(strlen(url)>1500) 229 { 230 fprintf(stderr,"URL is too long.\n"); 231 exit(2); 232 } 233 if(proxyhost==NULL) 234 if (0!=strncasecmp("http://",url,7)) 235 { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n"); 236 exit(2); 237 } 238 /* protocol/host delimiter */ 239 i=strstr(url,"://")-url+3; 240 /* printf("%d\n",i); */ 241 242 if(strchr(url+i,'/')==NULL) { 243 fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n"); 244 exit(2); 245 } 246 if(proxyhost==NULL) 247 { 248 /* get port from hostname */ 249 if(index(url+i,':')!=NULL && 250 index(url+i,':')<index(url+i,'/')) 251 { 252 strncpy(host,url+i,strchr(url+i,':')-url-i); 253 bzero(tmp,10); 254 strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1); 255 /* printf("tmp=%s\n",tmp); */ 256 proxyport=atoi(tmp); 257 if(proxyport==0) proxyport=80; 258 } else 259 { 260 strncpy(host,url+i,strcspn(url+i,"/")); 261 } 262 // printf("Host=%s\n",host); 263 strcat(request+strlen(request),url+i+strcspn(url+i,"/")); 264 } else 265 { 266 // printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport); 267 strcat(request,url); 268 } 269 if(http10==1) 270 strcat(request," HTTP/1.0"); 271 else if (http10==2) 272 strcat(request," HTTP/1.1"); 273 strcat(request,"\r\n"); 274 if(http10>0) 275 strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n"); 276 if(proxyhost==NULL && http10>0) 277 { 278 strcat(request,"Host: "); 279 strcat(request,host); 280 strcat(request,"\r\n"); 281 } 282 if(force_reload && proxyhost!=NULL) 283 { 284 strcat(request,"Pragma: no-cache\r\n"); 285 } 286 if(http10>1) 287 strcat(request,"Connection: close\r\n"); 288 /* add empty line at end */ 289 if(http10>0) strcat(request,"\r\n"); 290 // printf("Req=%s\n",request); 291 } 292 293 /* vraci system rc error kod */ 294 static int bench(void) 295 { 296 int i,j,k; 297 pid_t pid=0; 298 FILE *f; 299 300 /* check avaibility of target server */ 301 i=Socket(proxyhost==NULL?host:proxyhost,proxyport); 302 if(i<0) { 303 fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n"); 304 return 1; 305 } 306 close(i); 307 /* create pipe */ 308 if(pipe(mypipe)) 309 { 310 perror("pipe failed."); 311 return 3; 312 } 313 314 /* not needed, since we have alarm() in childrens */ 315 /* wait 4 next system clock tick */ 316 /* 317 cas=time(NULL); 318 while(time(NULL)==cas) 319 sched_yield(); 320 */ 321 322 /* fork childs */ 323 for(i=0;i<clients;i++) 324 { 325 pid=fork(); 326 if(pid <= (pid_t) 0) 327 { 328 /* child process or error*/ 329 sleep(1); /* make childs faster */ 330 break; 331 } 332 } 333 334 if( pid< (pid_t) 0) 335 { 336 fprintf(stderr,"problems forking worker no. %d\n",i); 337 perror("fork failed."); 338 return 3; 339 } 340 341 if(pid== (pid_t) 0) 342 { 343 /* I am a child */ 344 if(proxyhost==NULL) 345 benchcore(host,proxyport,request); 346 else 347 benchcore(proxyhost,proxyport,request); 348 349 /* write results to pipe */ 350 f=fdopen(mypipe[1],"w"); 351 if(f==NULL) 352 { 353 perror("open pipe for writing failed."); 354 return 3; 355 } 356 /* fprintf(stderr,"Child - %d %d\n",speed,failed); */ 357 fprintf(f,"%d %d %d\n",speed,failed,bytes); 358 fclose(f); 359 return 0; 360 } else 361 { 362 f=fdopen(mypipe[0],"r"); 363 if(f==NULL) 364 { 365 perror("open pipe for reading failed."); 366 return 3; 367 } 368 setvbuf(f,NULL,_IONBF,0); 369 speed=0; 370 failed=0; 371 bytes=0; 372 373 while(1) 374 { 375 pid=fscanf(f,"%d %d %d",&i,&j,&k); 376 if(pid<2) 377 { 378 fprintf(stderr,"Some of our childrens died.\n"); 379 break; 380 } 381 speed+=i; 382 failed+=j; 383 bytes+=k; 384 /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */ 385 if(--clients==0) break; 386 } 387 fclose(f); 388 389 printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n", 390 (int)((speed+failed)/(benchtime/60.0f)), 391 (int)(bytes/(float)benchtime), 392 speed, 393 failed); 394 } 395 return i; 396 } 397 398 void benchcore(const char *host,const int port,const char *req) 399 { 400 int rlen; 401 char buf[1500]; 402 int s,i; 403 struct sigaction sa; 404 405 /* setup alarm signal handler */ 406 sa.sa_handler=alarm_handler; 407 sa.sa_flags=0; 408 if(sigaction(SIGALRM,&sa,NULL)) 409 exit(3); 410 alarm(benchtime); 411 412 rlen=strlen(req); 413 nexttry:while(1) 414 { 415 if(timerexpired) 416 { 417 if(failed>0) 418 { 419 /* fprintf(stderr,"Correcting failed by signal\n"); */ 420 failed--; 421 } 422 return; 423 } 424 s=Socket(host,port); 425 if(s<0) { failed++;continue;} 426 if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;} 427 if(http10==0) 428 if(shutdown(s,1)) { failed++;close(s);continue;} 429 if(force==0) 430 { 431 /* read all available data from socket */ 432 while(1) 433 { 434 if(timerexpired) break; 435 i=read(s,buf,1500); 436 /* fprintf(stderr,"%d\n",i); */ 437 if(i<0) 438 { 439 failed++; 440 close(s); 441 goto nexttry; 442 } 443 else 444 if(i==0) break; 445 else 446 bytes+=i; 447 } 448 } 449 if(close(s)) {failed++;continue;} 450 speed++; 451 } 452 }
Makefile
1 CFLAGS?= -Wall -ggdb -W -O 2 CC?= gcc 3 LIBS?= 4 LDFLAGS?= 5 PREFIX?= /usr/local 6 VERSION=1.5 7 TMPDIR=/tmp/webbench-$(VERSION) 8 9 #all: webbench tags 10 all: webbench 11 12 #tags: *.c 13 # -ctags *.c 14 15 install: webbench 16 install -s webbench $(DESTDIR)$(PREFIX)/bin 17 install -m 644 webbench.1 $(DESTDIR)$(PREFIX)/man/man1 18 install -d $(DESTDIR)$(PREFIX)/share/doc/webbench 19 install -m 644 debian/copyright $(DESTDIR)$(PREFIX)/share/doc/webbench 20 install -m 644 debian/changelog $(DESTDIR)$(PREFIX)/share/doc/webbench 21 22 webbench: webbench.o Makefile 23 $(CC) $(CFLAGS) $(LDFLAGS) -o webbench webbench.o $(LIBS) 24 25 clean: 26 -rm -f *.o webbench *~ core *.core 27 # -rm -f *.o webbench *~ core *.core tags 28 29 tar: clean 30 -debian/rules clean 31 rm -rf $(TMPDIR) 32 install -d $(TMPDIR) 33 cp -p Makefile webbench.c socket.c webbench.1 $(TMPDIR) 34 install -d $(TMPDIR)/debian 35 -cp -p debian/* $(TMPDIR)/debian 36 ln -sf debian/copyright $(TMPDIR)/COPYRIGHT 37 ln -sf debian/changelog $(TMPDIR)/ChangeLog 38 -cd $(TMPDIR) && cd .. && tar cozf webbench-$(VERSION).tar.gz webbench-$(VERSION) 39 40 webbench.o: webbench.c socket.c Makefile 41 42 .PHONY: clean install all tar