/* * Author : WangBoJing , email : 1989wangbojing@gmail.com * * Copyright Statement: * -------------------- * This software is protected by Copyright and the information contained * herein is confidential. The software may not be copied and the information * contained herein may not be used or disclosed except with the written * permission of Author. (C) 2017 * * **** ***** ***** *** * ** *** *** * * * ** * ** * * ** ** * ** * * ** * * ** * ** ** * * ** * *** ** * ** * *********** ***** ***** ** **** * ** * ** ** ** ** ** ** * ** * ** ** * ** * ** * ** * ** * * ** ** ** * ** * ** ** * ** * ** * ** * ** * * ** ** ** * ** * ** ** * ** ** ** * ** * ** ** * ** ** ** * ** * ** * * ** ** ** * ** * ** ** * ** * ** ** * *** ** * * ** * ** ** * *** ** * ** * * ** ** * ** ** * ** ** * ** ** * ** ** * * ** * ** ** ***** * **** * ***** **** * * ***** **** * */ /* * (C) Radim Kolar 1997-2004 * This is free software, see GNU Public License version 2 for * details. * * Simple forking WWW Server benchmark: * * Usage: * webbench --help * * Return codes: * 0 - sucess * 1 - benchmark failed (server is not on-line) * 2 - bad param * 3 - internal error, fork failed * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nty_coroutine.h" #define ENABLE_NTYCO 1 #define MAX_BUFFER_LENGTH 1024 #define write(a, b, c) nty_send(a, b, c, 0) #define send(a, b, c, d) nty_send(a, b, c, d) #define read(a, b, c) nty_recv(a, b, c, 0) #define recv(a, b, c, d) nty_recv(a, b, c, d) #define connect(a, b, c) nty_connect(a, b, c) #define socket(a, b, c) nty_socket(a, b, c) #define close(a) nty_close(a) #define accept(a, b, c) nty_accept(a, b, c) int Socket(const char *host, int clientPort) { int sock; unsigned long inaddr; struct sockaddr_in ad; struct hostent *hp; memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; inaddr = inet_addr(host); if (inaddr != INADDR_NONE) memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); else { hp = gethostbyname(host); if (hp == NULL) return -1; memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); } ad.sin_port = htons(clientPort); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return sock; if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) return -1; return sock; } #include #include #include #include #include #include #include /* values */ volatile int timerexpired=0; int speed=0; int failed=0; int bytes=0; /* globals */ int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ /* Allow: GET, HEAD, OPTIONS, TRACE */ #define METHOD_GET 0 #define METHOD_HEAD 1 #define METHOD_OPTIONS 2 #define METHOD_TRACE 3 #define PROGRAM_VERSION "1.5" int method=METHOD_GET; int clients=1; #if ENABLE_NTYCO // clients --> fork num // nreqs --> http request // socket --> io num // socket per fork --> sockets / client // request per socket --> request / sockets int nreqs = 0; int sockets = 0; #endif int force=0; int force_reload=0; int proxyport=80; char *proxyhost=NULL; int benchtime=30; /* internal */ int mypipe[2]; char host[MAXHOSTNAMELEN]; #define REQUEST_SIZE 2048 char request[REQUEST_SIZE] = {0}; static const struct option long_options[]= { {"force",no_argument,&force,1}, {"reload",no_argument,&force_reload,1}, {"time",required_argument,NULL,'t'}, {"help",no_argument,NULL,'?'}, {"http09",no_argument,NULL,'9'}, {"http10",no_argument,NULL,'1'}, {"http11",no_argument,NULL,'2'}, {"get",no_argument,&method,METHOD_GET}, {"head",no_argument,&method,METHOD_HEAD}, {"options",no_argument,&method,METHOD_OPTIONS}, {"trace",no_argument,&method,METHOD_TRACE}, {"version",no_argument,NULL,'V'}, {"proxy",required_argument,NULL,'p'}, {"clients",required_argument,NULL,'c'}, {NULL,0,NULL,0} }; /* prototypes */ static void benchcore(const char* host,const int port, const char *request); static int bench(void); static void build_request(const char *url); static void alarm_handler(int signal) { timerexpired=1; } static void usage(void) { fprintf(stderr, "webbench [option]... URL\n" " -f|--force Don't wait for reply from server.\n" " -r|--reload Send reload request - Pragma: no-cache.\n" " -t|--time Run benchmark for seconds. Default 30.\n" " -n|--request Sum of requestion\n" " -s|--socket Sum of socket\n" " -p|--proxy Use proxy server for request.\n" " -c|--clients Run HTTP clients at once. Default one.\n" " -9|--http09 Use HTTP/0.9 style requests.\n" " -1|--http10 Use HTTP/1.0 protocol.\n" " -2|--http11 Use HTTP/1.1 protocol.\n" " --get Use GET request method.\n" " --head Use HEAD request method.\n" " --options Use OPTIONS request method.\n" " --trace Use TRACE request method.\n" " -?|-h|--help This information.\n" " -V|--version Display program version.\n" ); }; int main(int argc, char *argv[]) { int opt=0; int options_index=0; char *tmp=NULL; if(argc==1) { usage(); return 2; } while((opt=getopt_long(argc,argv,"912Vfrt:p:n:s:c:?h",long_options,&options_index))!=EOF ) { switch(opt) { case 0 : break; case 'f': force=1;break; case 'r': force_reload=1;break; case '9': http10=0;break; case '1': http10=1;break; case '2': http10=2;break; case 'V': printf(PROGRAM_VERSION"\n");exit(0); case 't': benchtime=atoi(optarg);break; case 'p': /* proxy server parsing server:port */ tmp=strrchr(optarg,':'); proxyhost=optarg; if(tmp==NULL) { break; } if(tmp==optarg) { fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg); return 2; } if(tmp==optarg+strlen(optarg)-1) { fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg); return 2; } *tmp='\0'; proxyport=atoi(tmp+1);break; case ':': case 'h': case '?': usage();return 2;break; case 'c': clients=atoi(optarg);break; #if ENABLE_NTYCO case 'n': nreqs=atoi(optarg);break; case 's': sockets=atoi(optarg);break; #endif } } if(optind==argc) { fprintf(stderr,"webbench: Missing URL!\n"); usage(); return 2; } if(clients==0) clients=1; if(benchtime==0) benchtime=60; #if ENABLE_NTYCO if (clients > 10) clients = 10; if (nreqs < 1000) nreqs = 1000; //if (sockets < clients) sockets = clients; if (sockets % clients != 0) sockets = sockets / clients * clients; #endif /* Copyright */ fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n" "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n" ); build_request(argv[optind]); /* print bench info */ printf("\nBenchmarking: "); switch(method) { case METHOD_GET: default: printf("GET");break; case METHOD_OPTIONS: printf("OPTIONS");break; case METHOD_HEAD: printf("HEAD");break; case METHOD_TRACE: printf("TRACE");break; } printf(" %s",argv[optind]); switch(http10) { case 0: printf(" (using HTTP/0.9)");break; case 2: printf(" (using HTTP/1.1)");break; } printf("\n"); if(clients==1) printf("1 client"); else printf("%d clients",clients); printf(", running %d sec", benchtime); if(force) printf(", early socket close"); if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport); if(force_reload) printf(", forcing reload"); printf(".\n"); return bench(); } void build_request(const char *url) { char tmp[10]; int i; bzero(host,MAXHOSTNAMELEN); bzero(request,REQUEST_SIZE); if(force_reload && proxyhost!=NULL && http10<1) http10=1; if(method==METHOD_HEAD && http10<1) http10=1; if(method==METHOD_OPTIONS && http10<2) http10=2; if(method==METHOD_TRACE && http10<2) http10=2; switch(method) { default: case METHOD_GET: strcpy(request,"GET");break; case METHOD_HEAD: strcpy(request,"HEAD");break; case METHOD_OPTIONS: strcpy(request,"OPTIONS");break; case METHOD_TRACE: strcpy(request,"TRACE");break; } strcat(request," "); if(NULL==strstr(url,"://")) { fprintf(stderr, "\n%s: is not a valid URL.\n",url); exit(2); } if(strlen(url)>1500) { fprintf(stderr,"URL is too long.\n"); exit(2); } if(proxyhost==NULL) if (0!=strncasecmp("http://",url,7)) { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n"); exit(2); } /* protocol/host delimiter */ i=strstr(url,"://")-url+3; /* printf("%d\n",i); */ if(strchr(url+i,'/')==NULL) { fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n"); exit(2); } if(proxyhost==NULL) { /* get port from hostname */ if(index(url+i,':')!=NULL && index(url+i,':')0) strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n"); if(proxyhost==NULL && http10>0) { strcat(request,"Host: "); strcat(request,host); strcat(request,"\r\n"); } if(force_reload && proxyhost!=NULL) { strcat(request,"Pragma: no-cache\r\n"); } if(http10>1) strcat(request,"Connection: close\r\n"); /* add empty line at end */ if(http10>0) strcat(request,"\r\n"); // printf("Req=%s\n",request); } /* vraci system rc error kod */ static int bench(void) { int i,j,k; pid_t pid=0; FILE *f; #if ENABLE_NTYCO == 0 /* check avaibility of target server */ i=Socket(proxyhost==NULL?host:proxyhost,proxyport); if(i<0) { fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n"); return 1; } close(i); #endif /* create pipe */ if(pipe(mypipe)) { perror("pipe failed."); return 3; } /* not needed, since we have alarm() in childrens */ /* wait 4 next system clock tick */ /* cas=time(NULL); while(time(NULL)==cas) sched_yield(); */ printf("bench enter\n"); /* fork childs */ for(i=0;i %d\n", sockfd, count); if (count < 0) { *ret = -1; break; } else if (count == 0) { *ret = 0; close(sockfd); break; } else { //printf("sockfd : %d, recv_buffer --> %d\n", sockfd, count); idx += count; } } if (idx > 0) *ret = 1; return idx; } void httprequest_commit(void *arg) { char buf[1500] = {0}; struct serv_host *shost = (struct serv_host *)arg; int slen = strlen(shost->req); int idx = 0; for (idx = 0;idx < (nreqs / sockets);idx ++) { int s = Socket(shost->host, shost->port); if (s < 0) { failed ++; continue ; } if (slen != send(s, shost->req, slen, 0)) { failed ++; close(s); continue; } memset(buf, 0, 1500); #if ENABLE_NTYCO int ret = 0; int rlen = recv_buffer(s, buf, 1500, &ret); #else int rlen = recv(s, buf, 1500, 0); #endif if (ret < 0) { failed ++; } else { if (testok(buf)) { speed ++; } else { failed ++; } bytes += rlen; } } return ; } void benchcore(const char *host,const int port,const char *req) { int rlen; char buf[1500]; int s,i; struct sigaction sa; /* setup alarm signal handler */ sa.sa_handler=alarm_handler; sa.sa_flags=0; if(sigaction(SIGALRM,&sa,NULL)) exit(3); alarm(benchtime); #if ENABLE_NTYCO //int i = 0; nty_coroutine *co = NULL; struct serv_host shost = {host, port, req}; for (i = 0;i < sockets / clients;i ++) { nty_coroutine_create(&co, httprequest_commit, &shost); } nty_schedule_run(); #else rlen=strlen(req); nexttry:while(1) { if(timerexpired) { if(failed>0) { /* fprintf(stderr,"Correcting failed by signal\n"); */ failed--; } return; } s=Socket(host,port); if(s<0) { failed++;continue;} if(rlen!=write(s, req, rlen)) {failed++;close(s);continue;} #if ENABLE_NTYCO if(http10==0) close(s); #else if(http10==0) if(shutdown(s,1)) { failed++;close(s);continue;} #endif if(force==0) { /* read all available data from socket */ while(1) { if(timerexpired) break; i=read(s,buf,1500); /* fprintf(stderr,"%d\n",i); */ if(i<0) { failed++; close(s); goto nexttry; } else if(i==0) break; else bytes+=i; } } if(close(s)) {failed++;continue;} speed++; } #endif }