fix integer overflows with commandline parameters resulting in wrong amount of requests performed

fix client state machine
This commit is contained in:
Thomas Porzelt 2009-09-11 12:09:54 +02:00
parent 20738ad079
commit 9df7f495cc
3 changed files with 37 additions and 16 deletions

1
TODO
View File

@ -4,3 +4,4 @@
- ssl support - ssl support
- better error reporting - better error reporting
- ipv6 support - ipv6 support
- progress output

View File

@ -83,19 +83,18 @@ void client_free(Client *client) {
static void client_reset(Client *client) { static void client_reset(Client *client) {
//printf("keep alive: %d\n", client->keepalive); //printf("keep alive: %d\n", client->keepalive);
if (!client->keepalive) { if (!client->keepalive) {
ev_io_stop(client->worker->loop, &client->sock_watcher);
if (client->sock_watcher.fd != -1) { if (client->sock_watcher.fd != -1) {
ev_io_stop(client->worker->loop, &client->sock_watcher);
shutdown(client->sock_watcher.fd, SHUT_WR); shutdown(client->sock_watcher.fd, SHUT_WR);
close(client->sock_watcher.fd); close(client->sock_watcher.fd);
client->sock_watcher.fd = -1;
} }
client->sock_watcher.fd = -1;
client->state = CLIENT_START; client->state = CLIENT_START;
} else { } else {
client_set_events(client, EV_WRITE); client_set_events(client, EV_WRITE);
client->worker->stats.req_started++;
client->state = CLIENT_WRITING; client->state = CLIENT_WRITING;
client->worker->stats.req_started++;
} }
client->parser_state = PARSER_START; client->parser_state = PARSER_START;
@ -158,12 +157,16 @@ void client_state_machine(Client *client) {
//printf("state: %d\n", client->state); //printf("state: %d\n", client->state);
switch (client->state) { switch (client->state) {
case CLIENT_START: case CLIENT_START:
client->worker->stats.req_started++;
do { do {
r = socket(config->saddr->ai_family, config->saddr->ai_socktype, config->saddr->ai_protocol); r = socket(config->saddr->ai_family, config->saddr->ai_socktype, config->saddr->ai_protocol);
} while (-1 == r && errno == EINTR); } while (-1 == r && errno == EINTR);
if (-1 == r) { if (-1 == r) {
client->state = CLIENT_ERROR; client->state = CLIENT_ERROR;
strerror_r(errno, client->buffer, sizeof(client->buffer));
W_ERROR("socket() failed: %s (%d)", client->buffer, errno);
goto start; goto start;
} }
@ -174,8 +177,6 @@ void client_state_machine(Client *client) {
ev_io_set(&client->sock_watcher, r, EV_WRITE); ev_io_set(&client->sock_watcher, r, EV_WRITE);
ev_io_start(client->worker->loop, &client->sock_watcher); ev_io_start(client->worker->loop, &client->sock_watcher);
client->worker->stats.req_started++;
if (!client_connect(client)) { if (!client_connect(client)) {
client->state = CLIENT_ERROR; client->state = CLIENT_ERROR;
goto start; goto start;
@ -257,7 +258,6 @@ void client_state_machine(Client *client) {
} }
} }
break;
case CLIENT_ERROR: case CLIENT_ERROR:
//printf("client error\n"); //printf("client error\n");
client->worker->stats.req_error++; client->worker->stats.req_error++;
@ -275,9 +275,15 @@ void client_state_machine(Client *client) {
client->worker->stats.req_failed++; client->worker->stats.req_failed++;
} }
/*if (client->worker->id == 1 && (client->worker->stats.req_started % 10) == 0)
printf("thread: %d, requests done: %"PRIu64", %"PRIu64" todo, %"PRIu64" started\n",
client->worker->id, client->worker->stats.req_done, client->worker->stats.req_todo,
client->worker->stats.req_started);*/
if (client->worker->stats.req_started == client->worker->stats.req_todo) { if (client->worker->stats.req_started == client->worker->stats.req_todo) {
/* this worker has started all requests */ /* this worker has started all requests */
ev_io_stop(client->worker->loop, &client->sock_watcher); client->keepalive = 0;
client_reset(client);
if (client->worker->stats.req_done == client->worker->stats.req_todo) { if (client->worker->stats.req_done == client->worker->stats.req_todo) {
/* this worker has finished all requests */ /* this worker has finished all requests */

View File

@ -139,6 +139,20 @@ static char *forge_request(char *url, char keep_alive, char **host, uint16_t *po
return req; return req;
} }
static uint64_t str_to_uint64(char *str) {
uint64_t i;
for (i = 0; *str; str++) {
if (*str < '0' || *str > '9')
return UINT64_MAX;
i *= 10;
i += *str - '0';
}
return i;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
Worker **workers; Worker **workers;
pthread_t *threads; pthread_t *threads;
@ -179,7 +193,7 @@ int main(int argc, char *argv[]) {
config.keep_alive = 1; config.keep_alive = 1;
break; break;
case 'n': case 'n':
config.req_count = atoi(optarg); config.req_count = str_to_uint64(optarg);
break; break;
case 't': case 't':
config.thread_count = atoi(optarg); config.thread_count = atoi(optarg);
@ -220,7 +234,7 @@ int main(int argc, char *argv[]) {
show_help(); show_help();
return 1; return 1;
} }
if (config.thread_count > config.req_count || config.thread_count > config.concur_count || config.concur_count > config.req_count) { if (config.req_count == UINT64_MAX || config.thread_count > config.req_count || config.thread_count > config.concur_count || config.concur_count > config.req_count) {
W_ERROR("%s", "insane arguments\n"); W_ERROR("%s", "insane arguments\n");
show_help(); show_help();
return 1; return 1;
@ -259,9 +273,9 @@ int main(int argc, char *argv[]) {
stats.ts_start = ev_time(); stats.ts_start = ev_time();
for (i = 0; i < config.thread_count; i++) { for (i = 0; i < config.thread_count; i++) {
uint16_t reqs = config.req_count / config.thread_count; uint64_t reqs = config.req_count / config.thread_count;
uint16_t concur = config.concur_count / config.thread_count; uint16_t concur = config.concur_count / config.thread_count;
uint16_t diff; uint64_t diff;
if (rest_concur) { if (rest_concur) {
diff = (i == config.thread_count) ? rest_concur : (rest_concur / config.thread_count); diff = (i == config.thread_count) ? rest_concur : (rest_concur / config.thread_count);
@ -276,15 +290,15 @@ int main(int argc, char *argv[]) {
reqs += diff; reqs += diff;
rest_req -= diff; rest_req -= diff;
} }
printf("spawning thread #%d: %"PRIu16" concurrent requests, %"PRIu64" total requests\n", i+1, concur, reqs);
workers[i] = worker_new(i+1, &config, concur, reqs);
workers[i] = worker = worker_new(i+1, &config, concur, reqs); if (!(workers[i])) {
if (!worker) {
W_ERROR("%s", "failed to allocate worker or client"); W_ERROR("%s", "failed to allocate worker or client");
return 1; return 1;
} }
err = pthread_create(&threads[i], NULL, worker_thread, (void*)worker); err = pthread_create(&threads[i], NULL, worker_thread, (void*)workers[i]);
if (err != 0) { if (err != 0) {
W_ERROR("failed spawning thread (%d)", err); W_ERROR("failed spawning thread (%d)", err);