int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules) { unsigned int i; unsigned int j; unsigned int plus; unsigned int fqdnlen; if (!stralloc_copy(fqdn,in)) return -1; for (j = i = 0;j < rules->len;++j) if (!rules->s[j]) { if (!doit(fqdn,rules->s + i)) return -1; i = j + 1; } fqdnlen = fqdn->len; plus = byte_chr(fqdn->s,fqdnlen,'+'); if (plus >= fqdnlen) return dns_ip6(out,fqdn); i = plus + 1; for (;;) { j = byte_chr(fqdn->s + i,fqdnlen - i,'+'); byte_copy(fqdn->s + plus,j,fqdn->s + i); fqdn->len = plus + j; if (dns_ip6(out,fqdn) == -1) return -1; if (out->len) return 0; i += j; if (i >= fqdnlen) return 0; ++i; } }
main(int argc,char **argv) { int i; dns_random_init(seed); if (*argv) ++argv; while (*argv) { if (!stralloc_copys(&fqdn,*argv)) strerr_die2x(111,FATAL,"out of memory"); if (dns_ip6(&out,&fqdn) == -1) strerr_die4sys(111,FATAL,"unable to find IPv6 address for ",*argv,": "); for (i = 0;i + 16 <= out.len;i += 16) { buffer_put(buffer_1,str,ip6_fmt(str,out.s + i)); buffer_puts(buffer_1," "); } buffer_puts(buffer_1,"\n"); ++argv; } buffer_flush(buffer_1); _exit(0); }
int main(int argc,char* argv[]) { char server[1024]; int* fds; int* avail; int* keepleft; long long* expected; unsigned long n=10000; /* requests */ unsigned long c=10; /* concurrency */ unsigned long t=0; /* time limit in seconds */ unsigned long k=0; /* keep-alive */ unsigned long K=1; /* keep-alive counter */ int report=0; unsigned long long errors=0; unsigned long long bytes=0; int v=0; unsigned long i,done; uint16 port=80; uint32 scope_id=0; stralloc ips={0}; char* request,* krequest; unsigned long rlen, krlen; tai6464 first,now,next,last; enum { SAME, REPLAY } mode; char* hostname; server[0]=0; errmsg_iam("bench"); #ifndef __MINGW32__ signal(SIGPIPE,SIG_IGN); #endif for (;;) { int i; int ch=getopt(argc,argv,"n:c:t:kvK:C:r"); if (ch==-1) break; switch (ch) { case 'r': report=1; break; case 'n': i=scan_ulong(optarg,&n); if (i==0) die(1,"could not parse -n argument \"",optarg,"\".\n"); break; case 'c': i=scan_ulong(optarg,&c); if (i==0) die(1,"could not parse -c argument \"",optarg,"\".\n"); break; case 't': i=scan_ulong(optarg,&t); if (i==0) die(1,"could not parse -t argument \"",optarg,"\".\n"); break; case 'k': k=1; break; case 'K': i=scan_ulong(optarg,&K); break; case 'v': v=1; break; case 'C': cookiefile(optarg); break; case '?': break; default: usage(); } } if (n<1 || c<1 || !argv[optind]) usage(); if (argv[optind][0]=='@') { mode=REPLAY; char* host; n=(unsigned long)-1; host=argv[optind]+1; { int tmp; tmp=str_chr(host,'/'); if (host[tmp]) { host[tmp]=0; if (!scan_ushort(host+tmp+1,&port)) usage(); } tmp=str_chr(host,'%'); if (host[tmp]) { host[tmp]=0; scope_id=socket_getifidx(host+tmp+1); if (scope_id==0) carp("warning: network interface \"",host+tmp+1,"\" not found."); } } { stralloc a={0}; stralloc_copys(&a,host); if (dns_ip6(&ips,&a)==-1) die(1,"could not find IP for \"",host,"\"!"); } hostname=host; request=krequest=0; rlen=krlen=0; } else { char* host=argv[optind]; int colon; int slash; char* c; mode=SAME; if (byte_equal(host,7,"http://")) host+=7; colon=str_chr(host,':'); slash=str_chr(host,'/'); if (host[0]=='[') { /* ipv6 IP notation */ int tmp; ++host; --colon; --slash; tmp=str_chr(host,']'); if (host[tmp]==']') host[tmp]=0; if (host[tmp+1]==':') colon=tmp+1; if (colon<tmp+1) colon=tmp+1+str_len(host+tmp+1); } if (colon<slash) { host[colon]=0; c=host+colon+1; if (c[scan_ushort(c,&port)]!='/') usage(); *c=0; } host[colon]=0; c=host+slash; *c=0; { char* tmp=alloca(str_len(host)+1); tmp[fmt_str(tmp,host)]=0; host=tmp; } *c='/'; { int tmp=str_chr(host,'%'); if (host[tmp]) { host[tmp]=0; scope_id=socket_getifidx(host+tmp+1); if (scope_id==0) carp("warning: network interface \"",host+tmp+1,"\" not found."); } } { stralloc a={0}; stralloc_copys(&a,host); if (dns_ip6(&ips,&a)==-1) die(1,"could not find IP for \"",host,"\"!"); } request=alloca(1300+str_len(host)+3*str_len(c)); krequest=alloca(1300+str_len(host)+3*str_len(c)); { int i,j; i=fmt_str(request,"GET "); i+=fmt_urlencoded(request+i,c,str_len(c)); i+=fmt_str(request+i," HTTP/1.0\r\nHost: "); i+=fmt_str(request+i,host); i+=fmt_str(request+i,":"); i+=fmt_ulong(request+i,port); i+=fmt_str(request+i,"\r\nUser-Agent: bench/1.0\r\nConnection: "); j=i; i+=fmt_str(request+i,"close\r\n\r\n"); rlen=i; request[rlen]=0; byte_copy(krequest,rlen,request); i=j+fmt_str(krequest+j,"keep-alive\r\n\r\n"); krlen=i; krequest[krlen]=0; } hostname=host; } fds=alloca(c*sizeof(*fds)); avail=alloca(c*sizeof(*avail)); expected=alloca(c*sizeof(*expected)); keepleft=alloca(c*sizeof(*keepleft)); last.sec.x=23; if (!k) K=1; for (i=0; i<c; ++i) { fds[i]=-1; avail[i]=1; keepleft[i]=K; } taia_now(&first); for (done=0; done<n; ) { if (t) { /* calculate timeout */ taia_now(&now); if (now.sec.x != last.sec.x) { byte_copy(&last,sizeof(now),&now); byte_copy(&next,sizeof(now),&now); next.sec.x += t; while ((i=io_timeouted())!=-1) { unsigned long j; char numbuf[FMT_ULONG]; numbuf[fmt_ulong(numbuf,i)]=0; carp("timeout on fd ",numbuf,"!"); j=(unsigned long)io_getcookie(i); io_close(i); avail[j]=1; fds[j]=-1; } } } /* first, fill available connections */ for (i=0; i<c; ++i) if (avail[i]==1 && fds[i]==-1) { fds[i]=make_connection(ips.s,port,scope_id,-1); if (fds[i]==-1) diesys(1,"socket/connect"); avail[i]=2; if (io_fd(fds[i])==0) diesys(1,"io_fd"); io_setcookie(fds[i],(void*)i); // io_wantread(fds[i]); io_wantwrite(fds[i]); } if (t) io_waituntil(next); else io_wait(); /* second, see if we can write on a connection */ while ((i=io_canwrite())!=-1) { int j; j=(unsigned long)io_getcookie(i); if (avail[j]==2) { if (make_connection(ips.s,port,scope_id,i)==-1) { ++errors; if (v) write(1,"!",1); io_close(i); avail[j]=1; fds[j]=-1; continue; } } { char* towrite; int writelen; if (mode==REPLAY) { static long lines; char line[1024]; char req[2048]; int len; int i; char* c; char* host; int hlen; if ((len=buffer_getline(buffer_0,line,sizeof(line)))) { ++lines; if (line[len]!='\n') die(0,"line too long: ",line); line[len]=0; c=line; if (str_start(line,"http://")) c+=7; if (c[0]=='/') { host=hostname; hlen=strlen(hostname); } else { host=c; c+=(hlen=str_chr(c,'/')); } if (!*c) c="/"; i=fmt_str(req,"GET "); i+=fmt_urlencoded(req+i,c,str_len(c)); i+=fmt_str(req+i," HTTP/1.0\r\nHost: "); byte_copy(req+i,hlen,host); i+=hlen; i+=fmt_str(req+i,":"); i+=fmt_ulong(req+i,port); if (cookies) { int j; i+=fmt_str(req+i,"\r\n"); j=nextcookie(req+i,sizeof(req)-i-100); if (j!=-1) i+=j; else i-=2; } i+=fmt_str(req+i,"\r\nUser-Agent: bench/1.0\r\nConnection: "); i+=fmt_str(req+i,keepleft[j]>1?"keep-alive\r\n\r\n":"close\r\n\r\n"); req[i]=0; towrite=req; writelen=i; } else { n=done; break; } } else { if (keepleft[j]>1) { towrite=krequest; writelen=krlen; } else { towrite=request; writelen=rlen; } if (cookies) { int i=writelen-2; int j=nextcookie(towrite+i,900); if (j!=-1) i+=j; i+=fmt_str(towrite+i,"\r\n\r\n"); writelen=i; } } if (io_trywrite(i,towrite,writelen)!=writelen) { ++errors; if (v) write(1,"-",1); io_close(i); avail[j]=1; fds[j]=-1; continue; } } io_dontwantwrite(i); io_wantread(i); expected[j]=-1; if (v) write(1,"+",1); } /* third, see if we got served */ while ((i=io_canread())!=-1) { char buf[8193]; int l,j; buf[8192]=0; j=(unsigned long)io_getcookie(i); if ((l=io_tryread(i,buf,sizeof(buf)-1))<=0) { if (l==0) { /* EOF. Mhh. */ if (expected[j]>0) { ++errors; if (v) write(1,"-",1); /* so whine a little */ } if (expected[j]==-2) ++done; io_close(i); avail[j]=1; fds[j]=-1; } else if (l==-3) { ++errors; if (v) write(1,"!",1); // carpsys("read"); } } else { bytes+=l; if (v) write(1,".",1); /* read something */ if (expected[j]==-1) { /* expecting header */ int k; /* OK, so this is a very simplistic header parser. No * buffering. At all. We expect the Content-Length header to * come in one piece. */ if (l>10 && !memcmp(buf,"HTTP/1.",7)) { if (buf[9]>='0' && buf[9]<='9') r[buf[9]-'0']++; else { write(1,buf,15); write(1,"\n",1); } } expected[j]=-2; if (!done) { for (k=0; k<l; ++k) if (str_start(buf+k,"\nServer: ")) { char* tmp=buf+(k+=9); for (; k<l; ++k) if (buf[k]=='\r') break; k=buf+k-tmp; if (k>sizeof(server)-1) k=sizeof(server)-1; byte_copy(server,k,tmp); server[k]=0; break; } } for (k=0; k<l; ++k) { if (str_start(buf+k,"\nContent-Length: ")) { k+=17; if (buf[k+scan_ulonglong(buf+k,(unsigned long long*)expected+j)] != '\r') die(1,"parse error in HTTP header!"); } else if (str_start(buf+k,"\r\n\r\n")) break; } if (expected[j]>0) { if (l-(k+4)>expected[j]) expected[j]=0; else expected[j]-=l-(k+4); } } else if (expected[j]==-2) { /* no content-length header, eat everything until EOF */ } else { if (l>expected[j]) { carp("got more than expected!"); expected[j]=0; } else expected[j]-=l; } if (expected[j]==0) { ++done; /* one down! */ avail[j]=1; // printf("fd %d: keepleft[%d]=%d\n",i,j,keepleft[j]); if (keepleft[j]>1) { --keepleft[j]; io_dontwantread(i); io_wantwrite(i); expected[j]=0; } else { keepleft[j]=K; io_close(i); fds[j]=-1; } } } } } taia_now(&now); taia_sub(&now,&now,&first); { char a[FMT_ULONG]; char b[FMT_ULONG]; char C[FMT_ULONG]; char d[FMT_ULONG]; char e[FMT_ULONG]; char f[FMT_ULONG]; char g[FMT_ULONG]; char h[FMT_ULONG]; char i[FMT_ULONG]; char j[FMT_ULONG]; unsigned long long l; a[fmt_ulong(a,now.sec.x)]=0; b[fmt_ulong0(b,(now.nano%1000000000)/100000,4)]=0; C[fmt_ulong(C,done)]=0; d[fmt_ulonglong(d,errors)]=0; e[fmt_ulonglong(e,bytes)]=0; /* let's say bytes = 10 MB, time = 1.2 sec. * then we want 10*1024*1024/1.2 == 8 MB/sec */ l = (now.sec.x * 1024) + now.nano/976562; if (l) { int i; l=bytes/l; if (report) i=fmt_ulong(f,l); else { i=fmt_humank(f,l*1024); i+=fmt_str(f+i,"iB/sec"); } f[i]=0; } else strcpy(f,"n/a"); l = (now.sec.x * 1000) + now.nano/1000000; l = l ? (done*10000) / l : 0; g[fmt_ulong(g,l/10)]=0; h[fmt_ulong(h,c)]=0; i[fmt_ulong(i,K)]=0; j[fmt_ulong(j,kaputt)]=0; if (server[0]) msg("Server: ",server); if (report) { errmsg_iam(0); msg("req\terr\tconcur\tkeep\tkbytes\tsec\ttput\tr/s\treset"); msg(C,"\t",d,"\t",h,"\t",i,"\t",e,"\t",a,".",b,"\t",f,"\t",g,"\t",j); } else { msg(C," requests, ",d," errors."); msg(e," bytes in ",a,".",b," seconds."); msg("Throughput: ",f); msg("Requests per second: ",g); msg("Connection refused/reset by peer: ",j); } { int i; for (i=0; i<9; ++i) { a[fmt_ulong(a,r[i])]=0; b[0]=i+'0'; b[1]=0; msg(b,"xx: ",a); } } } return 0; }
void doit(int t) { int fakev4=0; int j; SSL *ssl; int wstat; uint32 scope_id; int sslctl[2]; char *s; unsigned long tmp_long; char sslctl_cmd; stralloc ssl_env = { 0 }; buffer ssl_env_buf; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); switch(fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) strerr_die2x(111,DROPSSL,"unable to chroot"); if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,DROPSSL,"unable to set gid: "); if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,DROPSSL,"unable to set uid: "); /* This will exit on a fatal error or if the client quits * without activating SSL */ sslctl_cmd = ucspitls_master_wait_for_activation(sslctl[0]); /* If we got here, SSL must have been activated */ ssl = ssl_new(ctx,t); if (!ssl) strerr_die2x(111,DROP,"unable to create SSL instance"); if (ndelay_on(t) == -1) strerr_die2sys(111,DROP,"unable to set socket options: "); if (ssl_timeoutaccept(ssl,ssltimeout) == -1) strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: strerr_die2x(111,DROP,"no client certificate"); case -3: strerr_die2x(111,DROP,"client name does not match certificate"); default: break; } } if (sslctl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); stralloc_0(&ssl_env); /* Add another NUL */ buffer_init(&ssl_env_buf,buffer_unixwrite,sslctl[0],NULL,0); if (buffer_putflush(&ssl_env_buf, ssl_env.s, ssl_env.len) == -1) { strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } else if (sslctl_cmd != 'y') { strerr_die2x(111,DROP,"Protocol error on SSL control descriptor: invalid command character read"); } if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (ssl_io(ssl,pi[1],po[0],io_opt) != 0) strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); _exit(0); } /* Child-only below this point */ if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipstr,0); } if (socket_local6(t,localip,&localport,&scope_id) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if (fakev4) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name6(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } env("PROTO",fakev4?"SSL":"SSL6"); env("SSLLOCALIP",localipstr); env("SSL6LOCALIP",localipstr); env("SSLLOCALPORT",localportstr); env("SSL6LOCALPORT",localportstr); env("SSLLOCALHOST",localhost); env("SSL6LOCALHOST",localhost); if (!fakev4 && scope_id) env("SSL6INTERFACE",socket_getifname(scope_id)); if (flagtcpenv) { env("TCPLOCALIP",localipstr); env("TCP6LOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCP6LOCALPORT",localportstr); env("TCPLOCALHOST",localhost); env("TCP6LOCALHOST",localhost); if (!fakev4 && scope_id) env("TCP6INTERFACE",socket_getifname(scope_id)); } if (flagremotehost) if (dns_name6(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) { verifyhost = remoteipstr; if (dns_ip6(&tmp,&remotehostsa) == 0) for (j = 0;j + 16 <= tmp.len;j += 16) if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } } if (!flagparanoid) { if (!stralloc_0(&remotehostsa)) drop_nomem(); remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } env("SSLREMOTEIP",remoteipstr); env("SSL6REMOTEIP",remoteipstr); remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0; env("SSLREMOTEPORT",remoteportstr); env("SSL6REMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); env("SSL6REMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipstr); env("TCP6REMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCP6REMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); env("TCP6REMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("SSL6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (flagtcpenv) { env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); } if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { int fakev4=0; char* temp; if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipstr); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; setenv("SSLCTLFD",strnum,1); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; setenv("SSLREADFD",strnum,1); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; setenv("SSLWRITEFD",strnum,1); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { strnum[fmt_ulong(strnum,flagsslenv)] = 0; strerr_warn2("flagsslenv: ", strnum, 0); ucspitls(flagsslenv,0,1); } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
int main(int argc,char* argv[]) { unsigned long count=1000; unsigned long interval=10; unsigned long sample=5; int keepalive=0; char ip[16]; uint16 port=80; uint32 scope_id=0; stralloc ips={0}; int s; char* request; int rlen; signal(SIGPIPE,SIG_IGN); if (!geteuid()) { struct rlimit rl; long l; #ifdef RLIMIT_NPROC rl.rlim_cur=RLIM_INFINITY; rl.rlim_max=RLIM_INFINITY; setrlimit(RLIMIT_NPROC,&rl); #endif for (l=0; l<20000; l+=500) { rl.rlim_cur=l; rl.rlim_max=l; if (setrlimit(RLIMIT_NOFILE,&rl)==-1) break; } } for (;;) { int i; int c=getopt(argc,argv,"c:i:s:kb"); if (c==-1) break; switch (c) { case 'k': keepalive=1; break; case 'i': i=scan_ulong(optarg,&interval); if (i==0 || optarg[i]) { buffer_puts(buffer_2,"httpbench: warning: could not parse interval: "); buffer_puts(buffer_2,optarg+i+1); buffer_putsflush(buffer_2,"\n"); } break; case 'c': i=scan_ulong(optarg,&count); if (i==0 || optarg[i]) { buffer_puts(buffer_2,"httpbench: warning: could not parse count: "); buffer_puts(buffer_2,optarg+i+1); buffer_putsflush(buffer_2,"\n"); } break; case 's': i=scan_ulong(optarg,&sample); if (i==0 || optarg[i]) { buffer_puts(buffer_2,"httpbench: warning: could not parse sample size: "); buffer_puts(buffer_2,optarg+i+1); buffer_putsflush(buffer_2,"\n"); } break; case 'b': bindport=10000; break; case '?': usage: buffer_putsflush(buffer_2, "usage: httpbench [-hb] [-c count] [-i interval] [-s sample] url\n" "\n" "\t-h\tprint this help\n" "\t-c n\topen n connections total (default: 1000)\n" "\t-i n\tevery n connections, measure the latency (default: 10)\n" "\t-s n\tlatency == average of time to fetch an URL n times (default: 5)\n" "\t-k\tenable HTTP keep-alive\n" "\t-b\tbind the sockets ourselves, so the OS doesn't choose the ports\n" "Setting the number of connections to 1 measures the throughput\n" "instead of the latency (give URL to a large file).\n"); return 0; } } if (!argv[optind]) goto usage; if (byte_diff(argv[optind],7,"http://")) goto usage; { char* host=argv[optind]+7; int colon=str_chr(host,':'); int slash=str_chr(host,'/'); char* c; if (host[0]=='[') { /* ipv6 IP notation */ int tmp; ++host; --colon; --slash; tmp=str_chr(host,']'); if (host[tmp]==']') host[tmp]=0; if (host[tmp+1]==':') colon=tmp+1; if (colon<tmp+1) colon=tmp+1+str_len(host+tmp+1); } if (colon<slash) { host[colon]=0; c=host+colon+1; if (c[scan_ushort(c,&port)]!='/') goto usage; *c=0; } host[colon]=0; c=host+slash; *c=0; { char* tmp=alloca(str_len(host)+1); tmp[fmt_str(tmp,host)]=0; host=tmp; } *c='/'; { int tmp=str_chr(host,'%'); if (host[tmp]) { host[tmp]=0; scope_id=socket_getifidx(host+tmp+1); if (scope_id==0) { buffer_puts(buffer_2,"httpbench: warning: network interface "); buffer_puts(buffer_2,host+tmp+1); buffer_putsflush(buffer_2," not found.\n"); } } } { stralloc a={0}; stralloc_copys(&a,host); if (dns_ip6(&ips,&a)==-1) { buffer_puts(buffer_2,"httpbench: could not resolve IP: "); buffer_puts(buffer_2,host); buffer_putnlflush(buffer_2); return 1; } } request=malloc(300+str_len(host)+str_len(c)*3); if (!request) panic("malloc"); { int i; i=fmt_str(request,"GET "); i+=fmt_urlencoded(request+i,c,str_len(c)); i+=fmt_str(request+i," HTTP/1.0\r\nHost: "); i+=fmt_str(request+i,host); i+=fmt_str(request+i,":"); i+=fmt_ulong(request+i,port); i+=fmt_str(request+i,"\r\nUser-Agent: httpbench/1.0\r\nConnection: "); i+=fmt_str(request+i,keepalive?"keep-alive":"close"); i+=fmt_str(request+i,"\r\n\r\n"); rlen=i; request[rlen]=0; } } { int i; s=-1; for (i=0; i+16<=ips.len; i+=16) { char buf[IP6_FMT]; int v6=byte_diff(ips.s+i,12,V4mappedprefix); buffer_puts(buffer_1,"connecting to "); buffer_put(buffer_1,buf, v6? fmt_ip6(buf,ips.s+i): fmt_ip4(buf,ips.s+i+12)); buffer_puts(buffer_1," port "); buffer_putulong(buffer_1,port); buffer_putnlflush(buffer_1); s=make_connection(ips.s+i,port,scope_id); if (s!=-1) { byte_copy(ip,16,ips.s+i); break; } } if (s==-1) return 1; } if (write(s,request,rlen)!=rlen) panic("write"); if (readanswer(s,count==1)==-1) exit(1); close(s); if (count==1) return 0; { long i; long j; long err=0; int *socks; socks=malloc(sizeof(int)*count); if (!socks) panic("malloc"); for (i=j=0; i<count; ++i) { struct timeval a,b; long d; if (j==0) { int k,s=0; long x=0,y=0; for (k=0; k<sample; ++k) { if (!keepalive || !k) { gettimeofday(&a,0); s=make_connection(ip,port,scope_id); if (s==-1) panic("make_connection"); gettimeofday(&b,0); d=(b.tv_sec-a.tv_sec)*1000000; d=d+b.tv_usec-a.tv_usec; x+=d; } gettimeofday(&a,0); write(s,request,rlen); if (readanswer(s,0)==-1) { ++err; keepalive=0; } gettimeofday(&b,0); d=(b.tv_sec-a.tv_sec)*1000000; d=d+b.tv_usec-a.tv_usec; y+=d; if (!keepalive) close(s); } if (keepalive) close(s); buffer_puts(buffer_1,"sample "); buffer_putulong(buffer_1,x); buffer_puts(buffer_1," "); buffer_putulong(buffer_1,y/sample); buffer_putnlflush(buffer_1); } ++j; if (j==interval) j=0; gettimeofday(&a,0); socks[i]=make_connection(ip,port,scope_id); if (socks[i]==-1) panic("make_connection"); gettimeofday(&b,0); d=(b.tv_sec-a.tv_sec)*1000000; d=d+b.tv_usec-a.tv_usec; buffer_puts(buffer_1,"clat "); buffer_putulong(buffer_1,d); buffer_putnlflush(buffer_1); } } buffer_flush(buffer_1); return 0; }
void doit(int t) { int j; uint32 scope_id; if (ip6_isv4mapped(remoteip)) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; log(B("pid ",strnum," from ",remoteipstr,0)); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,write,t,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) errint(EHARD,"unable to print banner: "); } if (socket_local(t,localip,&localport,&scope_id) == -1) errint(EHARD,"unable to get local address: "); if (ip6_isv4mapped(localip)) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) errmem; localhost = localhostsa.s; } env("PROTO","TCP"); env("TCPLOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCPLOCALHOST",localhost); if (flagremotehost) if (dns_name(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) if (dns_ip6(&tmp,&remotehostsa) == 0) for (j = 0;j + 16 <= tmp.len;j += 16) if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } if (!flagparanoid) { if (!stralloc_0(&remotehostsa)) errmem; remotehost = remotehostsa.s; } } env("TCPREMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) errmem; } env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { char* temp; if (ip6_isv4mapped(remoteip)) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); // log(B("checking tcp rules for ",remotehost,": pass")); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"qmail-tcpsrv: ")) errmem; safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipstr); // cats(":<remote info>"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); }