示例#1
0
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 );
}
示例#2
0
static void init_conn(int fd, struct data *d)
{
	struct io_conn *conn;

	ok1(d->state == 0);
	d->state++;

	conn = io_new_conn(fd, io_read(d->buf, sizeof(d->buf), no_timeout, d));
	io_set_finish(conn, finish_ok, d);
	io_timeout(conn, time_from_usec(d->timeout_usec), timeout, d);
}
示例#3
0
ssize_t http_sendiovecdata( const int64 sock, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ) {
  struct http_data *cookie = io_getcookie( sock );
  char *header;
  int i;
  size_t header_size, size = iovec_length( &iovec_entries, &iovector );
  tai6464 t;

  /* No cookie? Bad socket. Leave. */
  if( !cookie ) {
    iovec_free( &iovec_entries, &iovector );
    HTTPERROR_500;
  }

  /* If this socket collected request in a buffer, free it now */
  array_reset( &cookie->request );

  /* If we came here, wait for the answer is over */
  cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;

  /* Our answers never are 0 vectors. Return an error. */
  if( !iovec_entries ) {
    HTTPERROR_500;
  }

  /* Prepare space for http header */
  header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING );
  if( !header ) {
    iovec_free( &iovec_entries, &iovector );
    HTTPERROR_500;
  }

  if( cookie->flag & STRUCT_HTTP_FLAG_GZIP )
    header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: gzip\r\nContent-Length: %zd\r\n\r\n", size );
  else if( cookie->flag & STRUCT_HTTP_FLAG_BZIP2 )
    header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: bzip2\r\nContent-Length: %zd\r\n\r\n", size );
  else
    header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size );

  iob_reset( &cookie->batch );
  iob_addbuf_free( &cookie->batch, header, header_size );

  /* Will move to ot_iovec.c */
  for( i=0; i<iovec_entries; ++i )
    iob_addbuf_munmap( &cookie->batch, iovector[i].iov_base, iovector[i].iov_len );
  free( iovector );

  /* writeable sockets timeout after 10 minutes */
  taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND );
  io_timeout( sock, t );
  io_dontwantread( sock );
  io_wantwrite( sock );
  return 0;
}
示例#4
0
static ssize_t http_handle_fullscrape( const int64 sock, struct ot_workstruct *ws ) {
  struct http_data* cookie = io_getcookie( sock );
  int format = 0;
  tai6464 t;

#ifdef WANT_MODEST_FULLSCRAPES
  {
    ot_scrape_log this_peer, *new_peer;
    int exactmatch;
    memcpy( this_peer.ip, cookie->ip, sizeof(ot_ip6));
    this_peer.last_fullscrape = g_now_seconds;
    pthread_mutex_lock(&g_modest_fullscrape_mutex);
    new_peer = vector_find_or_insert( &g_modest_fullscrape_timeouts, &this_peer, sizeof(ot_scrape_log), sizeof(ot_ip6), &exactmatch );
    if( !new_peer ) {
      pthread_mutex_unlock(&g_modest_fullscrape_mutex);
      HTTPERROR_500;
    }
    if( exactmatch && ( this_peer.last_fullscrape - new_peer->last_fullscrape ) < OT_MODEST_PEER_TIMEOUT ) {
      pthread_mutex_unlock(&g_modest_fullscrape_mutex);
      HTTPERROR_402_NOTMODEST;
    }
    memcpy( new_peer, &this_peer, sizeof(ot_scrape_log));
    pthread_mutex_unlock(&g_modest_fullscrape_mutex);
  }
#endif

#ifdef WANT_COMPRESSION_GZIP
  ws->request[ws->request_size-1] = 0;
  if( strstr( ws->request, "gzip" ) ) {
    cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
    format = TASK_FLAG_GZIP;
    stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, 0, (uintptr_t)cookie->ip );
  } else
#endif
    stats_issue_event( EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip );

#ifdef _DEBUG_HTTPERROR
  fprintf( stderr, "%s", ws->debugbuf );
#endif

  /* Pass this task to the worker thread */
  cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;
  /* Clients waiting for us should not easily timeout */
  taia_uint( &t, 0 ); io_timeout( sock, t );
  fullscrape_deliver( sock, TASK_FULLSCRAPE | format );
  io_dontwantread( sock );
  return ws->reply_size = -2;
}
示例#5
0
static void http_senddata( const int64 sock, struct ot_workstruct *ws ) {
  struct http_data *cookie = io_getcookie( sock );
  ssize_t written_size;

  if( !cookie ) { io_close(sock); return; }

  /* whoever sends data is not interested in its input-array */
  if( ws->keep_alive && ws->header_size != ws->request_size ) {
    size_t rest = ws->request_size - ws->header_size;
    if( array_start(&cookie->request) ) {
      memmove( array_start(&cookie->request), ws->request + ws->header_size, rest );
      array_truncate( &cookie->request, 1, rest );
    } else
      array_catb(&cookie->request, ws->request + ws->header_size, rest );    
  } else
    array_reset( &cookie->request );

  written_size = write( sock, ws->reply, ws->reply_size );
  if( ( written_size < 0 ) || ( ( written_size == ws->reply_size ) && !ws->keep_alive ) ) {
    array_reset( &cookie->request );
    free( cookie ); io_close( sock ); return;
  }

  if( written_size < ws->reply_size ) {
    char * outbuf;
    tai6464 t;

    if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) {
      array_reset( &cookie->request );
      free(cookie); io_close( sock );
      return;
    }

    memcpy( outbuf, ws->reply + written_size, ws->reply_size - written_size );
    iob_addbuf_free( &cookie->batch, outbuf, ws->reply_size - written_size );

    /* writeable short data sockets just have a tcp timeout */
    if( !ws->keep_alive ) {
      taia_uint( &t, 0 ); io_timeout( sock, t );
      io_dontwantread( sock );
    }
    io_wantwrite( sock );
  }
}
示例#6
0
static ssize_t http_handle_stats( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) {
static const ot_keywords keywords_main[] =
  { { "mode", 1 }, {"format", 2 }, { NULL, -3 } };
static const ot_keywords keywords_mode[] =
  { { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP }, { "tcp4", TASK_STATS_TCP },
    { "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE },
    { "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS }, { "completed", TASK_STATS_COMPLETED },
    { "top100", TASK_STATS_TOP100 }, { "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION },
    { "everything", TASK_STATS_EVERYTHING }, { "statedump", TASK_FULLSCRAPE_TRACKERSTATE }, { "fulllog", TASK_STATS_FULLLOG },
    { "woodpeckers", TASK_STATS_WOODPECKERS},
#ifdef WANT_LOG_NUMWANT
    { "numwants", TASK_STATS_NUMWANTS},
#endif
    { NULL, -3 } };
static const ot_keywords keywords_format[] =
  { { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED },
    { "txt", TASK_FULLSCRAPE_TPB_ASCII }, { NULL, -3 } };

  int mode = TASK_STATS_PEERS, scanon = 1, format = 0;

#ifdef WANT_RESTRICT_STATS
  struct http_data *cookie = io_getcookie( sock );

  if( !cookie || !accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) )
    HTTPERROR_403_IP;
#endif

  while( scanon ) {
    switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
    case -2: scanon = 0; break;   /* TERMINATOR */
    case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
    case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
    case  1: /* matched "mode" */
      if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
      break;
    case  2: /* matched "format" */
      if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
      break;
    }
  }

#ifdef WANT_FULLSCRAPE
  if( mode == TASK_FULLSCRAPE_TRACKERSTATE ) {
    format = mode; mode = TASK_STATS_TPB;
  }

  if( mode == TASK_STATS_TPB ) {
    struct http_data* cookie = io_getcookie( sock );
    tai6464 t;
#ifdef WANT_COMPRESSION_GZIP
    ws->request[ws->request_size] = 0;
#ifdef WANT_COMPRESSION_GZIP_ALWAYS
    if( strstr( read_ptr - 1, "gzip" ) ) {
#endif
      cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
      format |= TASK_FLAG_GZIP;
#ifdef WANT_COMPRESSION_GZIP_ALWAYS
    }
#endif
#endif
    /* Pass this task to the worker thread */
    cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;

    /* Clients waiting for us should not easily timeout */
    taia_uint( &t, 0 ); io_timeout( sock, t );
    fullscrape_deliver( sock, format );
    io_dontwantread( sock );
    return ws->reply_size = -2;
  }
#endif

  /* default format for now */
  if( ( mode & TASK_CLASS_MASK ) == TASK_STATS ) {
    tai6464 t;
    /* Complex stats also include expensive memory debugging tools */
    taia_uint( &t, 0 ); io_timeout( sock, t );
    stats_deliver( sock, mode );
    return ws->reply_size = -2;
  }

  /* Simple stats can be answerred immediately */
  return ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 );
}