Example #1
0
size_t scan_ip6if(const char* src,char* ip,uint32* scope_id) {
  size_t i=scan_ip6(src,ip);
  *scope_id=0;
  if (src[i]=='%') {
    size_t j;
    char* tmp;
    for (j=i+1; isalnum(src[j]); ++j) ;
    if (!src[j])
      tmp=(char*)src+i+1;
    else {
      tmp=alloca(j-i);
      byte_copy(tmp,j-(i+1),src+i+1);
      tmp[j-(i+1)]=0;
    }
    if (*tmp) {
      *scope_id=socket_getifidx(tmp);
      return j;
    }
  }
  return i;
}
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;
}
int main(int argc,char * const *argv) {
  const char *hostname;
  int opt;
  struct servent *se;
  char *x;
  unsigned long u;
  int s;
  int t;

  io_opt = ssl_io_opt_default;
  io_opt.timeout = 3600;

  while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:T:u:g:l:b:B:c:Z:pPoO3IiEeSsaAw:nNyYuUjJ")) != opteof)
    switch(opt) {
      case 'b': scan_ulong(optarg,&backlog); break;
      case 'c': scan_ulong(optarg,&limit); break;
      case 'X': flagallownorules = 1; break;
      case 'x': fnrules = optarg; break;
      case 'B': banner = optarg; break;
      case 'd': flagdelay = 1; break;
      case 'D': flagdelay = 0; break;
      case 'v': verbosity = 2; break;
      case 'q': verbosity = 0; break;
      case 'Q': verbosity = 1; break;
      case 'P': flagparanoid = 0; break;
      case 'p': flagparanoid = 1; break;
      case 'O': flagkillopts = 1; break;
      case 'o': flagkillopts = 0; break;
      case 'H': flagremotehost = 0; break;
      case 'h': flagremotehost = 1; break;
      case 'R': flagremoteinfo = 0; break;
      case 'r': flagremoteinfo = 1; break;
      case 't': scan_ulong(optarg,&timeout); break;
      case 'T': scan_ulong(optarg,&ssltimeout); break;
      case 'w': scan_uint(optarg,&io_opt.timeout); break;
      case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid);
		x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
      case 'u': scan_ulong(optarg,&uid); break;
      case 'g': scan_ulong(optarg,&gid); break;
      case 'Z': netif=socket_getifidx(optarg); break;
      case '1': flag1 = 1; break;
      case '4': noipv6 = 1; break;
      case '6': forcev6 = 1; break;
      case 'l': localhost = optarg; break;
      case '3': flag3 = 1; break;
      case 'I': flagclientcert = 0; break;
      case 'i': flagclientcert = 1; break;
      case 'S': flagsslenv = 0; break;
      case 's': flagsslenv = 1; break;
      case 'E': flagtcpenv = 0; break;
      case 'e': flagtcpenv = 1; break;
      case 'n': case 'y': flagsslwait = 1; break;
      case 'N': case 'Y': flagsslwait = 0; break;
      case 'j': io_opt.just_shutdown = 1; break;
      case 'J': io_opt.just_shutdown = 0; break;
      default: usage();
    }
  argc -= optind;
  argv += optind;

  if (!verbosity)
    buffer_2->fd = -1;
 
  hostname = *argv++;
  if (!hostname) usage();
  if (str_equal(hostname,"")) hostname = "0";

  x = *argv++;
  if (!x) usage();
  prog = argv;
  if (!*argv) usage();
  if (!x[scan_ulong(x,&u)])
    localport = u;
  else {
    se = getservbyname(x,"tcp");
    if (!se)
      strerr_die3x(111,FATAL,"unable to figure out port number for ",x);
    uint16_unpack_big((char*)&se->s_port,&localport);
  }

  if (x = env_get("VERIFYDEPTH")) {
    scan_ulong(x,&u);
    verifydepth = u;
  }

  if (x = env_get("CAFILE")) cafile = x;
  if (cafile && str_equal(cafile,"")) cafile = 0;

  if (x = env_get("CCAFILE")) ccafile = x;
  if (ccafile && str_equal(ccafile,"")) ccafile = 0;
  if (!flagclientcert) ccafile = 0;

  if (x = env_get("CADIR")) cadir = x;
  if (cadir && str_equal(cadir,"")) cadir= 0;

  if (x = env_get("CERTFILE")) certfile = x;
  if (certfile && str_equal(certfile,"")) certfile = 0;

  if (x = env_get("KEYFILE")) keyfile = x;
  if (keyfile && str_equal(keyfile,"")) keyfile = 0;

  if (x = env_get("DHFILE")) dhfile = x;
  if (dhfile && str_equal(dhfile,"")) dhfile = 0;

  if (x = env_get("CIPHERS")) ciphers = x;
  if (ciphers && str_equal(ciphers,"")) ciphers = 0;

  sig_block(sig_child);
  sig_catch(sig_child,sigchld);
  sig_catch(sig_term,sigterm);
  sig_ignore(sig_pipe);
 
  if (str_equal(hostname,"0")) {
    byte_zero(localip,sizeof localip);
  } else {
    if (!stralloc_copys(&tmp,hostname))
      strerr_die2x(111,FATAL,"out of memory");
    if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
      strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
    if (addresses.len < 16)
      strerr_die3x(111,FATAL,"no IP address for ",hostname);
    byte_copy(localip,16,addresses.s);
    if (ip6_isv4mapped(localip))
      noipv6=1;
  }

  s = socket_tcp6();
  if (s == -1)
    strerr_die2sys(111,FATAL,"unable to create socket: ");

  if (socket_bind6_reuse(s,localip,localport,netif) == -1)
    strerr_die2sys(111,FATAL,"unable to bind: ");

  if (socket_local6(s,localip,&localport,&netif) == -1)
    strerr_die2sys(111,FATAL,"unable to get local address: ");
  if (socket_listen(s,backlog) == -1)
    strerr_die2sys(111,FATAL,"unable to listen: ");
  ndelay_off(s);

  localportstr[fmt_ulong(localportstr,localport)] = 0;
  if (flag1) {
    buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace);
    buffer_puts(&b,localportstr);
    buffer_puts(&b,"\n");
    buffer_flush(&b);
  }
 
  if (flag3) read_passwd();

  ctx = ssl_server();
  ssl_errstr();
  if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context");

  switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) {
    case -1: strerr_die2x(111,FATAL,"unable to load certificate");
    case -2: strerr_die2x(111,FATAL,"unable to load key");
    case -3: strerr_die2x(111,FATAL,"key does not match certificate");
    default: break;
  }

  if (!ssl_ca(ctx,cafile,cadir,verifydepth))
    strerr_die2x(111,FATAL,"unable to load CA list");

  if (!ssl_cca(ctx,ccafile))
    strerr_die2x(111,FATAL,"unable to load client CA list");

  if (!ssl_params(ctx,dhfile,rsalen))
    strerr_die2x(111,FATAL,"unable to set cipher parameters");

  if (!ssl_ciphers(ctx,ciphers))
    strerr_die2x(111,FATAL,"unable to set cipher list");

  if (verbosity >= 2) {
    strnum[fmt_ulong(strnum,getpid())] = 0;
    strnum2[fmt_ulong(strnum2,rsalen)] = 0;
    strerr_warn4("sslserver: cafile ",strnum," ",cafile,0);
    strerr_warn4("sslserver: ccafile ",strnum," ",ccafile,0);
    strerr_warn4("sslserver: cadir ",strnum," ",cadir,0);
    strerr_warn4("sslserver: cert ",strnum," ",certfile,0);
    strerr_warn4("sslserver: key ",strnum," ",keyfile,0);
    strerr_warn6("sslserver: param ",strnum," ",dhfile," ",strnum2,0);
  }

  close(0); open_read("/dev/null");
  close(1); open_append("/dev/null");

  printstatus();
 
  for (;;) {
    while (numchildren >= limit) sig_pause();

    sig_unblock(sig_child);
    t = socket_accept6(s,remoteip,&remoteport,&netif);
    sig_block(sig_child);

    if (t == -1) continue;
    ++numchildren; printstatus();
 
    switch(fork()) {
      case 0:
        close(s);
        doit(t);
	strerr_die4sys(111,DROP,"unable to run ",*argv,": ");
      case -1:
        strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
        --numchildren; printstatus();
    }
    close(t);
  }
}
Example #4
0
main(int argc,char **argv)
{
  int fakev4=0;
  unsigned long u;
  int opt;
  char *x;
  int j;
  int s;
  int cloop;

  dns_random_init(seed);

  close(6);
  close(7);
  sig_ignore(sig_pipe);
 
  while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof)
    switch(opt) {
      case '4': noipv6 = 1; break;
      case '6': forcev6 = 1; break;
      case 'd': flagdelay = 1; break;
      case 'D': flagdelay = 0; break;
      case 'v': verbosity = 2; break;
      case 'q': verbosity = 0; break;
      case 'Q': verbosity = 1; break;
      case 'l': forcelocal = optarg; break;
      case 'H': flagremotehost = 0; break;
      case 'h': flagremotehost = 1; break;
      case 'R': flagremoteinfo = 0; break;
      case 'r': flagremoteinfo = 1; break;
      case 't': scan_ulong(optarg,&itimeout); break;
      case 'T': j = scan_ulong(optarg,&ctimeout[0]);
		if (optarg[j] == '+') ++j;
		scan_ulong(optarg + j,&ctimeout[1]);
		break;
      case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break;
      case 'I': netif=socket_getifidx(optarg); break;
      case 'p': scan_ulong(optarg,&u); portlocal = u; break;
      default: usage();
    }
  argv += optind;

  if (!verbosity)
    buffer_2->fd = -1;

  hostname = *argv;
  if (!hostname) usage();
  if (!hostname[0] || str_equal(hostname,"0"))
    hostname = (noipv6?"127.0.0.1":"::1");

  x = *++argv;
  if (!x) usage();
  if (!x[scan_ulong(x,&u)])
    portremote = u;
  else {
    struct servent *se;
    se = getservbyname(x,"tcp");
    if (!se)
      strerr_die3x(111,FATAL,"unable to figure out port number for ",x);
    portremote = ntohs(se->s_port);
    /* i continue to be amazed at the stupidity of the s_port interface */
  }

  if (!*++argv) usage();

  if (!stralloc_copys(&tmp,hostname)) nomem();
  if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
    strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
  if (addresses.len < 16)
    strerr_die3x(111,FATAL,"no IP address for ",hostname);

  if (addresses.len == 16) {
    ctimeout[0] += ctimeout[1];
    ctimeout[1] = 0;
  }

  for (cloop = 0;cloop < 2;++cloop) {
    if (!stralloc_copys(&moreaddresses,"")) nomem();
    for (j = 0;j + 16 <= addresses.len;j += 4) {
      s = socket_tcp6();
      if (s == -1)
        strerr_die2sys(111,FATAL,"unable to create socket: ");
      if (socket_bind6(s,iplocal,portlocal,netif) == -1)
        strerr_die2sys(111,FATAL,"unable to bind socket: ");
      if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
        goto CONNECTED;
      close(s);
      if (!cloop && ctimeout[1] && (errno == error_timeout)) {
	if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
      }
      else {
        strnum[fmt_ulong(strnum,portremote)] = 0;
	if (ip6_isv4mapped(addresses.s+j))
	  ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
	else
	  ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
        strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys);
      }
    }
    if (!stralloc_copy(&addresses,&moreaddresses)) nomem();
  }

  _exit(111);



  CONNECTED:

  if (!flagdelay)
    socket_tcpnodelay(s); /* if it fails, bummer */

  if (socket_local6(s,iplocal,&portlocal,&netif) == -1)
    strerr_die2sys(111,FATAL,"unable to get local address: ");

  if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any)))
    fakev4=1;

  if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem();

  strnum[fmt_ulong(strnum,portlocal)] = 0;
  if (!pathexec_env("TCPLOCALPORT",strnum)) nomem();
  if (fakev4)
    ipstr[ip4_fmt(ipstr,iplocal+12)] = 0;
  else
    ipstr[ip6_fmt(ipstr,iplocal)] = 0;
  if (!pathexec_env("TCPLOCALIP",ipstr)) nomem();

  x = forcelocal;
  if (!x)
    if (dns_name6(&tmp,iplocal) == 0) {
      if (!stralloc_0(&tmp)) nomem();
      x = tmp.s;
    }
  if (!pathexec_env("TCPLOCALHOST",x)) nomem();

  if (socket_remote6(s,ipremote,&portremote,&netif) == -1)
    strerr_die2sys(111,FATAL,"unable to get remote address: ");

  strnum[fmt_ulong(strnum,portremote)] = 0;
  if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem();
  if (fakev4)
    ipstr[ip4_fmt(ipstr,ipremote+12)] = 0;
  else
    ipstr[ip6_fmt(ipstr,ipremote)] = 0;
  if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem();
  if (verbosity >= 2)
    strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0);

  x = 0;
  if (flagremotehost)
    if (dns_name6(&tmp,ipremote) == 0) {
      if (!stralloc_0(&tmp)) nomem();
      x = tmp.s;
    }
  if (!pathexec_env("TCPREMOTEHOST",x)) nomem();

  x = 0;
  if (flagremoteinfo)
    if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) {
      if (!stralloc_0(&tmp)) nomem();
      x = tmp.s;
    }
  if (!pathexec_env("TCPREMOTEINFO",x)) nomem();

  if (fd_move(6,s) == -1)
    strerr_die2sys(111,FATAL,"unable to set up descriptor 6: ");
  if (fd_copy(7,6) == -1)
    strerr_die2sys(111,FATAL,"unable to set up descriptor 7: ");
  sig_uncatch(sig_pipe);
 
  pathexec(argv);
  strerr_die4sys(111,FATAL,"unable to run ",*argv,": ");
}
Example #5
0
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;
}
Example #6
0
int main(int argc,char **argv)
{
  char *hostname;
//  char *portname;
  int opt;
  struct servent *se;
  char *x;
  unsigned long u;
  int s;
  int t;

  while ((opt = getopt(argc,argv,"4dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof)
    switch(opt) {
      case 'b': scan_ulong(optarg,&backlog); break;
      case 'c': scan_ulong(optarg,&limit); break;
      case 'X': flagallownorules = 1; break;
      case 'x': fnrules = optarg; break;
      case 'B': banner = optarg; break;
      case 'd': flagdelay = 1; break;
      case 'D': flagdelay = 0; break;
      case 'v': verbosity = 2; break;
      case 'q': verbosity = 0; break;
      case 'Q': verbosity = 1; break;
      case 'P': flagparanoid = 0; break;
      case 'p': flagparanoid = 1; break;
      case 'O': flagkillopts = 1; break;
      case 'o': flagkillopts = 0; break;
      case 'H': flagremotehost = 0; break;
      case 'h': flagremotehost = 1; break;
//      case 'R': flagremoteinfo = 0; break;
      case 'r': flagremoteinfo = 1; break;
      case 't': scan_ulong(optarg,&timeout); break;
      case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid);
        x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
      case 'u': scan_ulong(optarg,&uid); break;
      case 'g': scan_ulong(optarg,&gid); break;
      case 'I': netif=socket_getifidx(optarg); break;
      case '1': flag1 = 1; break;
//      case '4': noipv6 = 1; break;
      case '4': ipv4socket = 1; break;
//      case '6': forcev6 = 1; break;
      case 'l': localhost = optarg; break;
      default: usage();
    }
  argc -= optind;
  argv += optind;

  if (!verbosity)
    buffer_2->fd = -1;

  hostname = *argv++;
  if (!hostname) usage();
  if (str_equal(hostname,"")) hostname = "0";

  x = *argv++;
  if (!x) usage();
  if (!x[scan_ulong(x,&u)])
    localport = u;
  else {
    se = getservbyname(x,"tcp");
    if (!se)
      errint(EHARD,B("unable to figure out port number for ",x));
    uint16_unpack_big((char*)&se->s_port,&localport);
  }

  if (!*argv) usage();

  sig_block(sig_child);
  sig_catch(sig_child,sigchld);
  sig_catch(sig_term,sigterm);
  sig_ignore(sig_pipe);

  if (str_equal(hostname,"0")) {
    byte_zero(localip,sizeof localip);
  } else {
    if (!stralloc_copys(&tmp,hostname)) errmem;
    if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
      errint(EHARD,B("temporarily unable to figure out IP address for ",hostname,": "));
    if (addresses.len < 16)
	  errint(EHARD,B("no IP address for ",hostname));
    byte_copy(localip,16,addresses.s);
    if (ip6_isv4mapped(localip))
      ipv4socket = 1;
  }

  s = socket_tcp();
  if (s == -1)
    errint(EHARD,"unable to create socket: ");
  if (socket_bind_reuse(s,localip,localport,netif) == -1)
    errint(EHARD,"unable to bind: ");

  if (!ipv4socket) ipv4socket = ip6_isv4mapped(localip);

  if (socket_local(s,localip,&localport,&netif) == -1)
    errint(EHARD,"unable to get local address: ");
  if (socket_listen(s,backlog) == -1)
    errint(EHARD,"unable to listen: ");
  ndelay_off(s);

  if (gid) if (prot_gid(gid) == -1)
    errint(EHARD,"unable to set gid: ");
  if (uid) if (prot_uid(uid) == -1)
    errint(EHARD,"unable to set uid: ");


  localportstr[fmt_ulong(localportstr,localport)] = 0;
  if (flag1) {
    buffer_init(&b,write,1,bspace,sizeof bspace);
    buffer_puts(&b,localportstr);
    buffer_puts(&b,"\n");
    buffer_flush(&b);
  }

  close(0);
  close(1);
  printstatus();

  for (;;) {
    while (numchildren >= limit) sig_pause();

    sig_unblock(sig_child);
    t = socket_accept(s,remoteip,&remoteport,&netif);
    sig_block(sig_child);

    if (t == -1) continue;
    ++numchildren; printstatus();

    switch(fork()) {
      case 0:
        close(s);
        doit(t);
        if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1))
          errint(EHARD,"unable to set up descriptors: ");
        sig_uncatch(sig_child);
        sig_unblock(sig_child);
        sig_uncatch(sig_term);
        sig_uncatch(sig_pipe);
        pathexec(argv);
        errint(EHARD,B("unable to run ",*argv,": "));
      case -1:
        errlog(ESOFT,NOTICE,"unable to fork: ");
        --numchildren; printstatus();
    }
    close(t);
  }
}