Compare commits

..

6 Commits

Author SHA1 Message Date
Adrian Chadd
6510cdb4db Merge branch 'master' of github.com:/httperf/httperf into ahc_fix_select 2018-07-11 15:57:27 -07:00
Adrian Chadd
84f4376c6c Don't allow the fd count to exceed FD_SETSIZE. 2016-03-31 16:17:42 -07:00
Adrian Chadd
18db423b1d oops - just use 'sd' for the loop. 2016-03-31 11:08:59 -07:00
Adrian Chadd
1e5e8d1bc2 remove these; not used. 2016-03-31 10:54:36 -07:00
Adrian Chadd
c62cdb51b9 oops - remove double decl. 2016-03-31 10:43:22 -07:00
Adrian Chadd
f62f1c0bda Totally untested fix for select() logic going out of bounds. 2016-03-31 10:41:04 -07:00
7 changed files with 76 additions and 240 deletions

View File

@ -122,7 +122,7 @@ A list of all available options can be obtained by specifying the
--help option (all option names can be abbreviated as long as they
remain unambiguous).
A more realistic test case might be to issue 100 HTTP requests at a
A more realistic test case might be to issue 1000 HTTP requests at a
rate of 10 requests per second. This can be achieved by additionally
specifying the --num-conns and --rate options. When specifying the
--rate option, it's generally a good idea to also specify a timeout

View File

@ -93,9 +93,4 @@ if test "$enable_debug" = yes; then
CFLAGS="${CFLAGS} -DDEBUG"
fi
AC_ARG_WITH(epoll, AS_HELP_STRING([--with-epoll], [use epoll if available]))
AS_IF([test "$with_epoll" != "no"],
AC_CHECK_FUNC(epoll_create,
AC_DEFINE([HAVE_EPOLL], 1, [#undef HAVE_EPOLL])))
AC_OUTPUT(Makefile man/Makefile src/stat/Makefile src/lib/Makefile src/gen/Makefile src/Makefile)

View File

@ -122,11 +122,6 @@ conn_init(Conn *conn)
exit(-1);
}
if (param.tls_server_name)
{
SSL_set_tlsext_host_name(conn->ssl, param.tls_server_name);
}
if (param.ssl_cipher_list) {
/* set order of ciphers */
int ssl_err = SSL_set_cipher_list(conn->ssl, param.ssl_cipher_list);

View File

@ -108,9 +108,6 @@ typedef struct Conn
#ifdef HAVE_SSL
SSL *ssl; /* SSL connection info */
#endif
#ifdef HAVE_EPOLL
int epoll_added; /* is fd added into epoll? */
#endif
}
Conn;

View File

@ -49,12 +49,12 @@
#include <sys/socket.h>
#include <sys/time.h>
#ifdef HAVE_SYS_SELECT_H
// You may need to override this!
// #define FD_SETSIZE 2048
#include <sys/select.h>
#endif
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
#endif
#ifdef HAVE_KEVENT
#include <sys/event.h>
@ -111,17 +111,10 @@ static u_long max_burst_len;
#ifdef HAVE_KEVENT
static int kq, max_sd = 0;
#else
#ifdef HAVE_EPOLL
#define EPOLL_N_MAX 8192
static int epoll_fd, max_sd = 0;
static struct epoll_event *epoll_events;
static int epoll_timeout;
#else
static fd_set rdfds, wrfds;
static int min_sd = 0x7fffffff, max_sd = 0, alloced_sd_to_conn = 0;
static struct timeval select_timeout;
#endif
#endif
static struct sockaddr_in myaddr;
static struct address_pool myaddrs;
#ifndef HAVE_KEVENT
@ -162,14 +155,12 @@ static char http11req_nohost[] =
enum Syscalls {
SC_BIND, SC_CONNECT, SC_READ, SC_SELECT, SC_SOCKET, SC_WRITEV,
SC_SSL_READ, SC_SSL_WRITEV, SC_KEVENT,
SC_EPOLL_CREATE, SC_EPOLL_CTL, SC_EPOLL_WAIT,
SC_NUM_SYSCALLS
};
static const char *const syscall_name[SC_NUM_SYSCALLS] = {
"bind", "connct", "read", "select", "socket", "writev",
"ssl_read", "ssl_writev", "kevent",
"epoll_create", "epoll_ctl", "epoll_wait"
"ssl_read", "ssl_writev", "kevent"
};
static Time syscall_time[SC_NUM_SYSCALLS];
static u_int syscall_count[SC_NUM_SYSCALLS];
@ -386,23 +377,6 @@ clear_active(Conn * s, enum IO_DIR dir)
"write" : "read");
exit(1);
}
#else
#ifdef HAVE_EPOLL
struct epoll_event ev;
int error;
if (dir == WRITE)
ev.events = EPOLLIN;
else
ev.events = EPOLLOUT;
ev.data.ptr = s;
error = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, sd, &ev);
if (error < 0) {
error = errno;
fprintf(stderr, "failed to EPOLL_CTL_DEL\n");
exit(1);
}
#else
fd_set * fdset;
@ -411,7 +385,6 @@ clear_active(Conn * s, enum IO_DIR dir)
else
fdset = &rdfds;
FD_CLR(sd, fdset);
#endif
#endif
if (dir == WRITE)
s->writing = 0;
@ -435,28 +408,6 @@ set_active(Conn * s, enum IO_DIR dir)
"write" : "read");
exit(1);
}
#else
#ifdef HAVE_EPOLL
struct epoll_event ev;
int error;
if (dir == WRITE)
ev.events = EPOLLOUT;
else
ev.events = EPOLLIN;
ev.data.ptr = s;
if (s->epoll_added)
error = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, sd, &ev);
else {
error = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sd, &ev);
s->epoll_added = 1;
}
if (error < 0) {
error = errno;
fprintf(stderr, "failed to EPOLL_CTL_MOD\n");
exit(1);
}
#else
fd_set * fdset;
@ -467,7 +418,6 @@ set_active(Conn * s, enum IO_DIR dir)
FD_SET(sd, fdset);
if (sd < min_sd)
min_sd = sd;
#endif
#endif
if (sd >= max_sd)
max_sd = sd;
@ -936,7 +886,7 @@ core_init(void)
Any_Type arg;
memset(&hash_table, 0, sizeof(hash_table));
#if !defined(HAVE_KEVENT) && !defined(HAVE_EPOLL)
#ifndef HAVE_KEVENT
memset(&rdfds, 0, sizeof(rdfds));
memset(&wrfds, 0, sizeof(wrfds));
#endif
@ -976,23 +926,6 @@ core_init(void)
strerror(errno));
}
#else
#ifdef HAVE_EPOLL
epoll_fd = epoll_create(EPOLL_N_MAX);
if (epoll_fd < 0) {
fprintf(stderr,
"%s: failed to create epoll: %s", prog_name,
strerror(errno));
exit(1);
}
epoll_events = calloc(EPOLL_N_MAX, sizeof(struct epoll_event));
if (epoll_events == NULL) {
fprintf(stderr,
"%s: failed to create epoll_events: %s", prog_name,
strerror(errno));
exit(1);
}
epoll_timeout = 0;
#else
#ifdef DONT_POLL
/*
* This causes select() to take several milliseconds on both Linux/x86
@ -1010,7 +943,6 @@ core_init(void)
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 0;
#endif
#endif
#endif
/*
@ -1148,6 +1080,15 @@ core_connect(Conn * s)
goto failure;
}
if (sd > FD_SETSIZE) {
fprintf(stderr,
"%s.core_connect.socket: sd > FD_SETSIZE (%d)\n",
prog_name,
FD_SETSIZE);
close(sd);
goto failure;
}
if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) {
fprintf(stderr, "%s.core_connect.fcntl: %s\n",
prog_name, strerror(errno));
@ -1192,7 +1133,7 @@ core_connect(Conn * s)
}
s->sd = sd;
#if !defined(HAVE_KEVENT) && !defined(HAVE_EPOLL)
#ifndef HAVE_KEVENT
if (sd >= alloced_sd_to_conn) {
size_t size, old_size;
@ -1440,19 +1381,8 @@ core_close(Conn * conn)
#endif
if (sd >= 0) {
#ifdef HAVE_EPOLL
struct epoll_event ev = { 0, { 0 } };
int error;
error = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sd, &ev);
if (error < 0) {
error = errno;
printf("EPOLL_CTL_DEL: %d %d %d\n", epoll_fd, sd, error);
assert(error == 0);
}
#endif
close(sd);
#if !defined(HAVE_KEVENT) && !defined(HAVE_EPOLL)
#ifndef HAVE_KEVENT
sd_to_conn[sd] = 0;
FD_CLR(sd, &wrfds);
FD_CLR(sd, &rdfds);
@ -1528,111 +1458,18 @@ core_loop(void)
}
}
#else
#ifdef HAVE_EPOLL
void
core_loop(void)
static void
check_conn(int sd, int is_readable, int is_writable)
{
struct epoll_event *ep;
int i, n;
Any_Type arg;
Conn *conn;
while (running) {
++iteration;
timer_tick();
n = epoll_wait(epoll_fd, epoll_events, EPOLL_N_MAX, epoll_timeout);
if (n < 0 && errno == EINTR) {
fprintf(stderr, "failed to fetch event: %s",
strerror(errno));
continue;
}
ep = epoll_events;
for (i = 0; i < n; i++, ep++) {
conn = ep->data.ptr;
conn_inc_ref(conn);
if (conn->watchdog) {
timer_cancel(conn->watchdog);
conn->watchdog = 0;
}
if (conn->state == S_CONNECTING) {
#ifdef HAVE_SSL
if (param.use_ssl)
core_ssl_connect(conn);
else
#endif
if (ep->events & EPOLLOUT) {
clear_active(conn, WRITE);
conn->state = S_CONNECTED;
arg.l = 0;
event_signal(EV_CONN_CONNECTED, (Object*)conn, arg);
}
} else {
if (ep->events & (EPOLLIN | EPOLLHUP) && conn->recvq)
do_recv(conn);
if (ep->events & EPOLLOUT && conn->sendq)
do_send(conn);
}
conn_dec_ref(conn);
}
}
close(epoll_fd);
}
#else
void
core_loop(void)
{
int is_readable, is_writable, n, sd, bit, min_i, max_i, i = 0;
fd_set readable, writable;
fd_mask mask;
Any_Type arg;
Conn *conn;
while (running) {
struct timeval tv = select_timeout;
timer_tick();
readable = rdfds;
writable = wrfds;
min_i = min_sd / NFDBITS;
max_i = max_sd / NFDBITS;
SYSCALL(SELECT, n = select(max_sd + 1, &readable, &writable, 0, &tv));
++iteration;
if (n <= 0) {
if (n < 0) {
fprintf(stderr, "%s.core_loop: select failed: %s\n", prog_name, strerror(errno));
exit(1);
}
continue;
/* Don't bother doing anything if we're not ready */
if ((is_readable || is_writable) == 0) {
return;
}
while (n > 0) {
/*
* find the index of the fdmask that has something
* going on:
*/
do {
++i;
if (i > max_i)
i = min_i;
assert(i <= max_i);
mask = readable.fds_bits[i] | writable.fds_bits[i];
} while (!mask);
bit = 0;
sd = i * NFDBITS + bit;
do {
if (mask & 1) {
--n;
is_readable = (FD_ISSET(sd, &readable) && FD_ISSET(sd, &rdfds));
is_writable = (FD_ISSET(sd, &writable) && FD_ISSET(sd, &wrfds));
if (is_readable || is_writable) {
/*
* only handle sockets that
* haven't timed out yet
@ -1644,6 +1481,7 @@ core_loop(void)
timer_cancel(conn->watchdog);
conn->watchdog = 0;
}
if (conn->state == S_CONNECTING) {
#ifdef HAVE_SSL
if (param.use_ssl)
@ -1662,20 +1500,51 @@ core_loop(void)
if (is_readable && conn->recvq)
do_recv(conn);
}
conn_dec_ref(conn);
}
if (n > 0)
void
core_loop(void)
{
int is_readable, is_writable, n, sd;
fd_set readable, writable;
fd_mask mask;
while (running) {
struct timeval tv = select_timeout;
timer_tick();
readable = rdfds;
writable = wrfds;
SYSCALL(SELECT, n = select(max_sd + 1, &readable, &writable, 0, &tv));
++iteration;
if (n <= 0) {
if (n < 0) {
fprintf(stderr, "%s.core_loop: select failed: %s\n", prog_name, strerror(errno));
exit(1);
}
continue;
}
/* XXX totally suboptimal loop, but less potentially problematic */
for (sd = 0; sd <= max_sd; sd++) {
is_readable = (FD_ISSET(sd, &readable) && FD_ISSET(sd, &rdfds));
is_writable = (FD_ISSET(sd, &writable) && FD_ISSET(sd, &wrfds));
if (is_readable || is_writable)
check_conn(sd, is_readable, is_writable);
/* XXX TODO: totally can bail out if we've seen 'n' FDs */
}
/* Do timer tick at the end of the connection check */
timer_tick();
}
}
mask = ((u_long) mask) >> 1;
++sd;
} while (mask);
}
}
}
#endif
#endif
void

View File

@ -144,7 +144,6 @@ static struct option longopts[] = {
#ifdef HAVE_SSL
{"ssl", no_argument, &param.use_ssl, 1},
{"ssl-ciphers", required_argument, (int *) &param.ssl_cipher_list, 0},
{"tls-server-name", required_argument, (int *) &param.tls_server_name, 0},
{"ssl-no-reuse", no_argument, &param.ssl_reuse, 0},
{"ssl-certificate", required_argument, (int *) &param.ssl_cert, 0},
{"ssl-key", required_argument, (int *) &param.ssl_key, 0},
@ -669,8 +668,6 @@ main(int argc, char **argv)
param.ssl_ca_path = optarg;
else if (flag == &param.ssl_protocol)
{
param.use_ssl = 1;
if (strcasecmp (optarg, "auto") == 0)
param.ssl_protocol = 0;
#ifndef OPENSSL_NO_SSL2
@ -687,7 +684,7 @@ main(int argc, char **argv)
param.ssl_protocol = 5;
else if (strcasecmp (optarg, "TLSv1.2") == 0 || strcasecmp (optarg, "TLSv1_2") == 0)
param.ssl_protocol = 6;
#ifdef TLS1_3_VERSION
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
else if (strcasecmp (optarg, "TLSv1.3") == 0 || strcasecmp (optarg, "TLSv1_3") == 0)
param.ssl_protocol = 7;
#endif
@ -698,19 +695,6 @@ main(int argc, char **argv)
exit (1);
}
}
else if (flag == &param.tls_server_name)
{
if (param.ssl_protocol >= 4)
{
param.tls_server_name = optarg;
}
else
{
fprintf (stderr, "%s: Error setting the SNI (Server Name Indication) server name to %s. The --tls-server-name option can only be used if --ssl-protocol-version is set to TLSv1.0 and above.\n",
prog_name, optarg);
exit (1);
}
}
#endif
else if (flag == &param.uri)
param.uri = optarg;
@ -1076,7 +1060,7 @@ main(int argc, char **argv)
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_VERSION);
break;
#else
ssl_ctx = SSL_CTX_new (TLSv1_client_method ());
ssl_ctx = SSL_CTX_new (TLSv1_client_method ()); break;
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2); break;
#endif
@ -1088,7 +1072,7 @@ main(int argc, char **argv)
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_1_VERSION);
break;
#else
ssl_ctx = SSL_CTX_new (TLSv1_client_method ());
ssl_ctx = SSL_CTX_new (TLSv1_client_method ()); break;
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2); break;
#endif
@ -1100,13 +1084,12 @@ main(int argc, char **argv)
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_2_VERSION);
break;
#else
ssl_ctx = SSL_CTX_new (TLSv1_client_method ());
ssl_ctx = SSL_CTX_new (TLSv1_client_method ()); break;
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); break;
#endif
#ifdef TLS1_3_VERSION
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
/* 7/TLSv1.3 */
case 7:
ssl_ctx = SSL_CTX_new (TLS_client_method ());
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
@ -1308,8 +1291,6 @@ main(int argc, char **argv)
printf(" --ssl");
if (param.ssl_cipher_list)
printf(" --ssl-ciphers=%s", param.ssl_cipher_list);
if (param.tls_server_name)
printf(" --tls-server-name=%s", param.tls_server_name);
if (!param.ssl_reuse)
printf(" --ssl-no-reuse");
if (param.ssl_cert) printf (" --ssl-cert=%s", param.ssl_cert);
@ -1329,7 +1310,7 @@ main(int argc, char **argv)
case 4: printf (" --ssl-protocol=TLSv1.0"); break;
case 5: printf (" --ssl-protocol=TLSv1.1"); break;
case 6: printf (" --ssl-protocol=TLSv1.2"); break;
#ifdef TLS1_3_VERSION
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
case 7: printf (" --ssl-protocol=TLSv1.3"); break;
#endif
}

View File

@ -121,7 +121,6 @@ typedef struct Cmdline_Params
int ssl_reuse; /* reuse SSL Session ID */
int ssl_verify; /* whether to verify the server certificate */
int ssl_protocol; /* which SSL protocol to use */
const char *tls_server_name; /* TLS SNI (server name indication) */
const char *ssl_cipher_list; /* client's list of SSL cipher suites */
const char *ssl_cert; /* client certificate file name */
const char *ssl_key; /* client key file name */