/* http_load - multiprocessing http test client
**
** Copyright � 1998,1999,2001,2016 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#ifdef USE_SSL
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#endif
#include "version.h"
#include "port.h"
#include "timers.h"
#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
#define USE_IPV6
#endif
#define max(a,b) ((a)>=(b)?(a):(b))
#define min(a,b) ((a)<=(b)?(a):(b))
/* How long a connection can stay idle before we give up on it. */
#define IDLE_SECS 60
/* Default max bytes/second in throttle mode. */
#define THROTTLE 3360
/* How often to show progress reports. */
#define PROGRESS_SECS 60
/* How many file descriptors to not use. */
#define RESERVED_FDS 3
typedef struct {
char* url_str;
int protocol;
char* hostname;
unsigned short port;
#ifdef USE_IPV6
struct sockaddr_in6 sa_in;
#else /* USE_IPV6 */
struct sockaddr_in sa_in;
#endif /* USE_IPV6 */
int sa_len, sock_family, sock_type, sock_protocol;
char* filename;
char* filedata;
int got_bytes;
long bytes;
int got_checksum;
long checksum;
} url;
static url* urls;
static int num_urls, max_urls, num_run_urls;
typedef struct {
char* str;
struct sockaddr_in sa_in;
} sip;
static sip* sips;
static int num_sips, max_sips;
/* Protocol symbols. */
#define PROTO_HTTP 0
#ifdef USE_SSL
#define PROTO_HTTPS 1
#endif
typedef struct {
int url_num;
struct sockaddr_in sa_in;
int sa_len;
int conn_fd;
#ifdef USE_SSL
SSL* ssl;
#endif
int conn_state, header_state;
int did_connect, did_response;
struct timeval started_at;
struct timeval connect_at;
struct timeval request_at;
struct timeval response_at;
Timer* idle_timer;
Timer* wakeup_timer;
long content_length;
long bytes;
long checksum;
int http_status;
} connection;
static connection* connections;
static int max_connections, num_connections, max_parallel;
static int http_status_counts[1000]; /* room for all three-digit statuses */
#define CNST_FREE 0
#define CNST_CONNECTING 1
#define CNST_HEADERS 2
#define CNST_READING 3
#define CNST_PAUSING 4
#define HDST_LINE1_PROTOCOL 0
#define HDST_LINE1_WHITESPACE 1
#define HDST_LINE1_STATUS 2
#define HDST_BOL 10
#define HDST_TEXT 11
#define HDST_LF 12
#define HDST_CR 13
#define HDST_CRLF 14
#define HDST_CRLFCR 15
#define HDST_C 20
#define HDST_CO 21
#define HDST_CON 22
#define HDST_CONT 23
#define HDST_CONTE 24
#define HDST_CONTEN 25
#define HDST_CONTENT 26
#define HDST_CONTENT_ 27
#define HDST_CONTENT_L 28
#define HDST_CONTENT_LE 29
#define HDST_CONTENT_LEN 30
#define HDST_CONTENT_LENG 31
#define HDST_CONTENT_LENGT 32
#define HDST_CONTENT_LENGTH 33
#define HDST_CONTENT_LENGTH_COLON 34
#define HDST_CONTENT_LENGTH_COLON_WHITESPACE 35
#define HDST_CONTENT_LENGTH_COLON_WHITESPACE_NUM 36
static char* argv0;
static int do_checksum, do_throttle, do_verbose, do_jitter, do_proxy;
static float throttle;
static int idle_secs;
static char* proxy_hostname;
static unsigned short proxy_port;
static struct timeval start_at;
static int fetches_started, connects_completed, responses_completed, fetches_completed;
static long long total_bytes;
static long long total_connect_usecs, max_connect_usecs, min_connect_usecs;
static long long total_response_usecs, max_response_usecs, min_response_usecs;
int total_timeouts, total_badbytes, total_badchecksums;
static long start_interval, low_interval, high_interval, range_interval;
#ifdef USE_SSL
static SSL_CTX* ssl_ctx = (SSL_CTX*) 0;
static char* cipher = (char*) 0;
#endif
/* Forwards. */
static void usage( void ) __attribute__ ((noreturn));
static void read_url_file( char* url_file );
static void lookup_address( int url_num );
static void read_sip_file( char* sip_file );
static void start_connection( struct timeval* nowP );
static void start_socket( int url_num, int cnum, struct timeval* nowP );
static void handle_connect( int cnum, struct timeval* nowP, int double_check );
static void handle_read( int cnum, struct timeval* nowP );
static void idle_connection( ClientData client_data, struct timeval* nowP );
static void wakeup_connection( ClientData client_data, struct timeval* nowP );
static void close_connection( int cnum );
static void progress_report( ClientData client_data, struct timeval* nowP );
static void start_timer( ClientData client_data, struct timeval* nowP );
static void end_timer( ClientData client_data, struct timeval* nowP );
static void finish( struct timeval* nowP ) __attribute__ ((noreturn));
static long long delta_timeval( struct timeval* start, struct timeval* end );
static void* malloc_check( size_t size );
static void* realloc_check( void* ptr, size_t size );
static char* strdup_check( char* str );
static void check( void* ptr );
int
main( int argc, char** argv )
{
int argn;
int start;
#define START_NONE 0
#define START_PARALLEL 1
#define START_RATE 2
int start_parallel = -1, start_rate = -1;
int end;
#define END_NONE 0
#define END_FETCHES 1
#define END_SECONDS 2
int end_fetches = -1, end_seconds = -1;
int cnum;
char* url_file;
char* sip_file;
#ifdef RLIMIT_NOFILE
struct rlimit limits;
#endif /* RLIMIT_NOFILE */
fd_set rfdset;
fd_set wfdset;
struct timeval now;
int i, r;
max_connections = 64 - RESERVED_FDS; /* a guess */
#ifdef RLIMIT_NOFILE
/* Try and increase the limit on # of files to the maximum. */
if ( getrlimit( RLIMIT_NOFILE, &limits ) == 0 )
{
if ( limits.rlim_cur != limits.rlim_max )
{
if ( limits.rlim_max == RLIM_INFINITY )
limits.rlim_cur = 8192; /* arbitrary */
else if ( limits.rlim_max > limits.rlim_cur )
limits.rlim_cur = limits.rlim_max;
(void) setrlimit( RLIMIT_NOFILE, &limits );
}
max_connections = limits.rlim_cur - RESERVED_FDS;
}
#endif /* RLIMIT_NOFILE */
/* Parse args. */
argv0 = argv[0];
argn = 1;
do_checksum = do_throttle = do_verbose = do_jitter = do_proxy = 0;
throttle = THROTTLE;
sip_file = (char*) 0;
idle_secs = IDLE_SECS;
start = START_NONE;
end = END_NONE;
while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
{
if ( strncmp( argv[argn], "-checksum", strlen( argv[argn] ) ) == 0 )
do_checksum = 1;
else if ( strncmp( argv[argn], "-throttle", strlen( argv[argn] ) ) == 0 )
评论2
最新资源