#include #include #include #include #include #include #include #include #include #include "instrument.h" using namespace std; #define webapi_test_NOTNEED #define webapi_addfile_NOTNEED #define webapi_addfile_bob_NOTNEED #define webapi_appendfile_NOTNEED #define webapi_delfile_NOTNEED #define webapi_undelete_NOTNEED #define webapi_modifyfile_NOTNEED #define webapi_modifyfile_bob_NOTNEED #define webapi_rename_NOTNEED #define webapi_copy_NOTNEED #define webapi_readfile_NOTNEED #define webapi_readfile_bob_NOTNEED #define webapi_readmore_NOTNEED #define webapi_mkdir_NOTNEED #define webapi_rmdir_NOTNEED #define webapi_listdir_NOTNEED #define webapi_stat_NOTNEED #define webapi_set_access_NOTNEED #define webapi_markview_NOTNEED #define webapi_list_inboxes_NOTNEED #define webapi_list_msgs_NOTNEED #define webapi_sendmsg_NOTNEED #define webapi_sendmsg_project_NOTNEED #define webapi_replymsg_NOTNEED #define webapi_replymsg_project_NOTNEED #define webapi_sendattach_NOTNEED #define webapi_sendtalk_NOTNEED #define webapi_sendtalk_file_NOTNEED #define webapi_list_talk_NOTNEED #define webapi_public_listdir_NOTNEED #define webapi_public_readfile_NOTNEED #define webapi_public_list_talk_NOTNEED #define webapi_systempubkey_NOTNEED #define webapi_verifysign_NOTNEED #define webapi_getpubkey_NOTNEED #define webapi_registernode_NOTNEED #define webapi_remotelogin_NOTNEED #define webapi_remotepass_NOTNEED #define webapi_remote_interest_set_NOTNEED #define webapi_remote_interest_unset_NOTNEED #define webapi_nodelogin_NOTNEED #define webapi_nodepass_NOTNEED #define webapi_config_read_NOTNEED #define webapi_config_write_NOTNEED #define webapi_contact_request_NOTNEED #define webapi_contact_manage_NOTNEED #define webapi_contact_list_NOTNEED #define webapi_list_contacts_NOTNEED #define webapi_list_lists_NOTNEED #define webapi_list_groups_NOTNEED #include "proto/webapi.protoch" static DEBUG_KEY D_HEADER("header","Print request header"); static DEBUG_KEY D_PROTO("proto","HTTP protocol"); static void sendheader (CONNECT_HTTP_INFO &con, bool reuseconnection, const string &session, const char *file, const char *hostname) { string buf; if (strncmp(hostname,"http://",7)==0){ hostname += 7; }else if (strncmp(hostname,"https://",8)==0){ hostname += 8; } if (reuseconnection){ buf = string_f ("GET %s HTTP/1.1\r\nhost: %s\r\nUser-Agent: bo-webtest\r\n",file,hostname); }else{ buf = string_f ("GET %s HTTP/1.0\r\nhost: %s\r\nUser-Agent: bo-webtest\r\n",file,hostname); } if (session.size() > 0){ buf += string_f ("cookie: session=%s;\r\n",session.c_str()); } buf += string_f ("Content-Type: text/html; charset=UTF-8\r\n\r\n"); con.send (buf.c_str()); debug_printf (D_HEADER,"%s-----\n",buf.c_str()); } struct RESULT{ unsigned long nb; // Number of requests done unsigned long nbok; // Number of successful request RESULT(unsigned long _nb, unsigned long _nbok){ nb = _nb; nbok = _nbok; } RESULT(){ nb = 0; nbok = 0; } }; static void printrate (long long start, const vector &tbnb) { unsigned long total =0; unsigned long total_ok = 0; for (auto n:tbnb){ total += n.nb; total_ok += n.nbok; } long long duration = fdpass_getnow()-start; double rate = total/(duration/1000000.0); printf ("connections=%lu rate=%lf/s",total,rate); if (total_ok != total){ printf (" *** total_ok = %lu",total_ok); } printf ("\n"); } int main (int argc, char *argv[]) { glocal int ret = -1; glocal const char *bindaddr = "0.0.0.0"; glocal const char *host = "http://test1.bolixo.org"; glocal const char *file = "/index.hc"; glocal int nbproc = 1; glocal int nbrep=1; glocal bool keepcookie = false; glocal bool reuseconnection = false; glocal bool verbose = false; glocal bool stats = false; glocal bool endless = false; glocal const char *email = NULL; glocal const char *passwd = NULL; glocal bool nonstrict = false; glocal.ret = (argc,argv,"bolixo"); setproginfo ("bo-webtest",VERSION,"Web performance test"); setgrouparg ("Connection"); setarg ('h',"host","Web server url )(https://...)",glocal.host,false); setarg ('E',"email","Email for login",glocal.email,false); setarg ('P',"password","Password for login",glocal.passwd,false); setarg (' ',"nonstrict","Relaxed rules for SSL connections (certificate and hostname validation)",glocal.nonstrict,false); setgrouparg ("Tuning"); setarg ('n',"nbrep","Number of iteration",glocal.nbrep,false); setarg ('N',"nbproc","Process number",glocal.nbproc,false); setarg ('k',"keepsession","Keep the session cookie from next request",glocal.keepcookie,false); setarg ('r',"reusecon","Reuse HTTP connection",glocal.reuseconnection, false); setarg ('e',"endless","Runs forever and print stats",glocal.endless,false); setgrouparg ("Misc."); setarg ('f',"file","File to request from web server",glocal.file,false); setarg ('v',"verbose","Print the result",glocal.verbose,false); setarg ('s',"stats","Print some stats at the end",glocal.stats,false); glocal long long start = fdpass_getnow(); glocal vector tbnb; glocal unsigned chunk=0; glocal CONNECT_HTTP_INFO con; if (glocal.nonstrict) glocal.con.setnonstrictmode(); signal(SIGPIPE,SIG_IGN); signal(SIGCHLD,SIG_IGN); if (glocal.email == NULL) glocal.email = getenv("WEBTEST_EMAIL"); if (glocal.passwd == NULL) glocal.passwd = getenv("WEBTEST_PASSWORD"); if (glocal.email == NULL || glocal.passwd == NULL){ tlmp_error ("missing email and/or password, can't continue\n"); exit (-1); } // Used to receive the stats of the child processes (); if (getnbclients() <= 1){ endserver = true; printrate (glocal.start,glocal.tbnb); } //printf ("rec: no=%d %s\n",no,line); int nb = atoi(line); const char *pt = str_skip(str_skipdig(line)); int nbok = atoi(pt); if (nbok != nb) printf ("no=%d %d <> %d\n",no,nb,nbok); while (glocal.tbnb.size() <= (unsigned)no) glocal.tbnb.push_back(RESULT()); glocal.tbnb[no] = RESULT(nb,nbok); if (glocal.endless){ unsigned long total = 0; for (auto n:glocal.tbnb) total += n.nb; unsigned chunk = total/1000; if (chunk > glocal.chunk){ glocal.chunk=chunk; printrate(glocal.start,glocal.tbnb); } } fprintf (stderr,"Connecting to %s, getting file %s, doing %d process%s X %d request%s reusecon=%d email=%s\n" ,glocal.host,glocal.file ,glocal.nbproc,glocal.nbproc > 1 ? "es" : "" ,glocal.nbrep,glocal.nbrep > 1 ? "s" : "" ,glocal.reuseconnection,glocal.email); if (glocal.con.init (glocal.host)==-1){ tlmp_error ("Invalid host url: %s\n",glocal.host); exit(-1); } for (int p=0; p(glocal.con,glocal.email,glocal.passwd); if (!success){ tlmp_error ("login failed\n"); exit (-1); }else{ glocal.session = sessionid; } } for (glocal.i=0; glocal.endless || glocal.i(); int ret = glocal.con.receive (buf,size); if (ret <= 0){ debug_printf (D_PROTO,"fill i=%d received=%u ret=%d size=%u %d(%s)\n",glocal.i,glocal.received,ret,size,errno,strerror(errno)); ret = 0; }else{ glocal.received += ret; } return ret; int ret = 0; const char *line = (const char *)buf; const char *endbuf = line+len; const char *pt = line; while (pt < endbuf && *pt != '\n') pt++; //debug_printf (D_PROTO,"process len=%u %lu %d\n",len,pt-line,pt")==0){ glocal.nbok++; if (glocal.i > glocal.starti+50){ // We are in reuseconnection mode, probably endless mode // Every 50 connection we quit. The httpd seems to disconnect // anyway after some amount of request end = true; }else if (glocal.reuseconnection){ glocal.i++; if (glocal.i%30 == 1){ string tmp = string_f("%d %d\n",glocal.i,glocal.nbok); write (glocal.fdout,tmp.c_str(),tmp.size()); } if (glocal.endless || glocal.i < glocal.nbrep){ sendheader (glocal.con,glocal.reuseconnection,glocal.session,glocal.file,glocal.host); }else{ glocal.i--; // So the count is good, as the for loop will increment it end = true; } }else{ end = true; } } } return ret; //printf ("apres call %d %d\n",glocal.i,glocal.nbok); if (glocal.i%30 == 1){ string tmp = string_f("%d %d\n",glocal.i+1,glocal.nbok); write (glocal.fdout,tmp.c_str(),tmp.size()); } } { string tmp = string_f("%d %d\n",glocal.i,glocal.nbok); write (glocal.fdout,tmp.c_str(),tmp.size()); } if (glocal.stats) printf ("nblines=%d\n",glocal.nblines); if (glocal.nbok != glocal.nbrep) tlmp_error ("nbrep=%d nbok=%d\n",glocal.nbrep,glocal.nbok); if (glocal.session.size() > 0){ if (!glocal.reuseconnection) glocal.con.reconnect(); (glocal.con,glocal.session); } fflush (stdout); _exit (0); }else if (pid == (pid_t)-1){ tlmp_error ("Can't fork (%s)\n",strerror(errno)); exit (-1); }else{ close (tbfd[1]); o.inject(tbfd[0]); } } } o.loop(); return 0; return glocal.ret; }