static void handle_accept( const int64 serversocket ) {
  struct http_data *h;
  unsigned char ip[4];
  uint16 port;
  tai6464 t;
  int64 i;

  while( ( i = socket_accept4( serversocket, (char*)ip, &port) ) != -1 ) {

    /* Put fd into a non-blocking mode */
    io_nonblock( i );

    if( !io_fd( i ) ||
        !( h = (struct http_data*)malloc( sizeof( struct http_data ) ) ) ) {
      io_close( i );
      continue;
    }
    io_setcookie( i, h );
    io_wantread( i );

    memset( h, 0, sizeof( struct http_data ) );
    memmove( h->ip, ip, sizeof( ip ) );

    stats_issue_event( EVENT_ACCEPT, 1, ntohl(*(uint32_t*)ip));

    /* That breaks taia encapsulation. But there is no way to take system
       time this often in FreeBSD and libowfat does not allow to set unix time */
    taia_uint( &t, 0 ); /* Clear t */
    tai_unix( &(t.sec), (g_now + OT_CLIENT_TIMEOUT) );
    io_timeout( i, t );
  }

  if( errno == EAGAIN )
    io_eagain( serversocket );
}
Exemple #2
0
static void handle_reconnects( void ) {
  int i;
  for( i=0; i<g_connection_count; ++i )
    if( PROXYPEER_NEEDSCONNECT( g_connections[i].state ) ) {
      int64 newfd = socket_tcp6( );
      fprintf( stderr, "(Re)connecting to peer..." );
      if( newfd < 0 ) continue; /* No socket for you */
      io_fd(newfd);
      if( socket_bind6_reuse(newfd,g_serverip,g_serverport,0) ) {
        io_close( newfd );
        continue;
      }
      if( socket_connect6(newfd,g_connections[i].ip,g_connections[i].port,0) == -1 &&
          errno != EINPROGRESS && errno != EWOULDBLOCK ) {
        close(newfd);
        continue;
      }
      io_wantwrite(newfd); /* So we will be informed when it is connected */
      io_setcookie(newfd,g_connections+i);

      /* Prepare connection info block */
      reset_info_block( g_connections+i );
      g_connections[i].fd            = newfd;
      PROXYPEER_SETCONNECTING( g_connections[i].state );
    }
  g_connection_reconn = time(NULL) + 30;
}
static void ot_try_bind( char ip[4], uint16 port, int is_tcp ) {
  int64 s = is_tcp ? socket_tcp4( ) : socket_udp4();

  if( socket_bind4_reuse( s, ip, port ) == -1 )
    panic( "socket_bind4_reuse" );

  if( is_tcp && ( socket_listen( s, SOMAXCONN) == -1 ) )
    panic( "socket_listen" );

  if( !io_fd( s ) )
    panic( "io_fd" );

  io_setcookie( s, is_tcp ? FLAG_TCP : FLAG_UDP );

  io_wantread( s );
}
Exemple #4
0
static int64_t ot_try_bind( ot_ip6 ip, uint16_t port ) {
  int64 sock = socket_tcp6( );

  if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 )
    panic( "socket_bind6_reuse" );

  if( socket_listen( sock, SOMAXCONN) == -1 )
    panic( "socket_listen" );

  if( !io_fd( sock ) )
    panic( "io_fd" );

  io_setcookie( sock, (void*)FLAG_SERVERSOCKET );
  io_wantread( sock );
  return sock;
}
Exemple #5
0
/* Handle incoming connection requests, check against whitelist */
static void handle_accept( int64 serversocket ) {
  int64 newfd;
  ot_ip6 ip;
  uint16 port;

  while( ( newfd = socket_accept6( serversocket, ip, &port, NULL ) ) != -1 ) {

    /* XXX some access control */

    /* Put fd into a non-blocking mode */
    io_nonblock( newfd );

    if( !io_fd( newfd ) )
      io_close( newfd );
    else {
      /* Find a new home for our incoming connection */
      int i;
      for( i=0; i<MAX_PEERS; ++i )
        if( g_connections[i].state == FLAG_DISCONNECTED )
          break;
      if( i == MAX_PEERS ) {
        fprintf( stderr, "No room for incoming connection." );
        close( newfd );
        continue;
      }

      /* Prepare connection info block */
      reset_info_block( g_connections+i );
      PROXYPEER_SETCONNECTING( g_connections[i].state );
      g_connections[i].port = port;
      g_connections[i].fd   = newfd;

      io_setcookie( newfd, g_connections + i );

      /* We expect the connecting side to begin with its tracker_id */
      io_wantread( newfd );
    }
  }

  return;
}
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;
}
Exemple #7
0
int
main(int argc, char* argv[]) {
  int s = socket_tcp6();
  uint32 scope_id;
  char ip[16];
  uint16 port;
  char hisip[16];
  uint16 hisport;
  uint32 hisscope_id;
  static char seed[128];
  static stralloc fqdn;
  static stralloc out;

  if(argc != 4) {
  usage:
    buffer_putsflush(buffer_2,
                     "usage: proxy myip myport hisip hisport\n"
                     "\n"
                     "e.g.: proxy 0 119 news.fu-berlin.de 119\n");
    return 0;
  }

  if(argv[1][scan_ip6if(argv[1], ip, &scope_id)]) {
    if(str_equal(argv[1], "0")) {
      byte_zero(ip, 16);
      scope_id = 0;
    } else
      goto usage;
  }
  if(argv[2][scan_ushort(argv[2], &port)])
    goto usage;
  if(argv[3][scan_ip6if(argv[3], hisip, &hisscope_id)]) {
    dns_random_init(seed);
    if(!stralloc_copys(&fqdn, argv[3]))
      goto nomem;
    if(dns_ip4(&out, &fqdn) == -1) {
      buffer_puts(buffer_2, "unable to find IP address for ");
      buffer_puts(buffer_2, argv[3]);
      buffer_puts(buffer_2, ": ");
      buffer_puterror(buffer_2);
      buffer_putnlflush(buffer_2);
      return 111;
    }
  } else if(!stralloc_catb(&out, hisip, 16)) {
  nomem:
    buffer_putsflush(buffer_2, "out of memory\n");
    return 111;
  }
  if(argv[4][scan_ushort(argv[4], &hisport)])
    goto usage;

  if(socket_bind6_reuse(s, ip, port, scope_id) == -1) {
    buffer_puts(buffer_2, "socket_bind6_reuse: ");
    buffer_puterror(buffer_2);
    buffer_putnlflush(buffer_2);
    return 111;
  }
  if(socket_listen(s, 16) == -1) {
    buffer_puts(buffer_2, "socket_listen: ");
    buffer_puterror(buffer_2);
    buffer_putnlflush(buffer_2);
    return 111;
  }
  if(!io_fd(s)) {
    buffer_puts(buffer_2, "io_fd: ");
    buffer_puterror(buffer_2);
    buffer_putnlflush(buffer_2);
    return 111;
  }
  io_wantread(s);
  for(;;) {
    int64 i;
    io_wait();
    while((i = io_canread()) != -1) {
      if(i == s) {
        /* the read event is on the server socket */
        /* that means it's an incoming connection */
        int n;
        while((n = socket_accept6(s, ip, &port, &scope_id)) != -1) {
          int x = socket_tcp6();
          if(x == -1) {
            buffer_puts(buffer_2, "socket_tcp6 failed: ");
          fail:
            buffer_puterror(buffer_2);
            buffer_putnlflush(buffer_2);
            io_close(n);
          } else {
            struct state* s = malloc(sizeof(struct state));
            if(!s)
              goto closefail;
            s->a = n;
            s->b = x;
            s->connected = 0;
            s->done = s->todo = 0;
            s->dir = UNDECIDED;
            io_nonblock(x);
            socket_connect6(x, out.s, hisport, hisscope_id);
            if(!io_fd(x) || !io_fd(n)) {
              buffer_puts(buffer_2, "io_fd failed: ");
            closefail:
              free(s);
              io_close(x);
              goto fail;
            }
            io_setcookie(x, s);
            io_setcookie(n, s);
            io_wantwrite(x);
          }
        }
        if(errno != EAGAIN) {
          buffer_puts(buffer_2, "socket_accept6 failed: ");
          buffer_puterror(buffer_2);
          buffer_putnlflush(buffer_2);
        }
      } else {
        /* read event on an established connection */
        struct state* s = io_getcookie(i);
        int l = io_tryread(i, s->buf, sizeof(s->buf));
        if(l == -1) {
          buffer_puts(buffer_2, "io_tryread(");
          buffer_putulong(buffer_2, i);
          buffer_puts(buffer_2, "): ");
          buffer_puterror(buffer_2);
          buffer_putnlflush(buffer_2);
          io_close(s->a);
          io_close(s->b);
        } else if(l == 0) {
          buffer_puts(buffer_2, "eof on fd #");
          buffer_putulong(buffer_2, i);
          buffer_putnlflush(buffer_2);
          io_close(i);
        } else {
          int r;
          switch(r = io_trywrite(i, s->buf, l)) {
            case -1:
              buffer_puts(buffer_2, "io_tryread(");
              buffer_putulong(buffer_2, i);
              buffer_puts(buffer_2, "): ");
              buffer_puterror(buffer_2);
              buffer_putnlflush(buffer_2);
              io_close(i);
              break;
            case 0:
              buffer_puts(buffer_2, "write eof on fd #");
              buffer_putulong(buffer_2, i);
              buffer_putnlflush(buffer_2);
              io_close(i);
            default:
              if(r != l) {
                buffer_puts(buffer_2, "short write on fd #");
                buffer_putulong(buffer_2, i);
                buffer_puts(buffer_2, ": wrote ");
                buffer_putulong(buffer_2, r);
                buffer_puts(buffer_2, ", wanted to write ");
                buffer_putulong(buffer_2, l);
                buffer_putsflush(buffer_2, ").\n");
              }
          }
        }
      }
    }
  }
  return 0;
}