Browse Source

Initial re-write of idleconn program to use libevent library

ahc_fix_select
tedbullock 17 years ago
parent
commit
c56788ae9e
1 changed files with 161 additions and 191 deletions
  1. +161
    -191
      httperf/src/idleconn.c

+ 161
- 191
httperf/src/idleconn.c View File

@@ -1,214 +1,184 @@
/*
httperf -- a tool for measuring web server performance
Copyright 2000-2007 Hewlett-Packard Company and Contributors listed in
AUTHORS file. Originally contributed by David Mosberger-Tang

This file is part of httperf, a web server performance measurment
tool.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
In addition, as a special exception, the copyright holders give
permission to link the code of this work with the OpenSSL project's
"OpenSSL" library (or with modified versions of it that use the same
license as the "OpenSSL" library), and distribute linked combinations
including the two. You must obey the GNU General Public License in
all respects for all of the code used other than "OpenSSL". If you
modify this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA
*/

#define _BSD_SOURCE

#include <errno.h>
#include <netdb.h>
#include <signal.h>
* Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
*
* This file is part of httperf, a web server performance measurment tool.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of this work with the OpenSSL project's "OpenSSL" library
* (or with modified versions of it that use the same license as the "OpenSSL"
* library), and distribute linked combinations including the two. You must
* obey the GNU General Public License in all respects for all of the code
* used other than "OpenSSL". If you modify this file, you may extend this
* exception to your version of the file, but you are not obligated to do so.
* If you do not wish to do so, delete this exception statement from your
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <string.h> /* For strrchr() */
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include <sys/time.h>
#include <sys/resource.h>
#include <event.h>
#include <evdns.h>

#include <generic_types.h>
#include <list.h>

/*
* Events allocated onto the heap
*/
static struct List *active_events = NULL;
static struct List *inactive_events = NULL;

static const char *prog_name = NULL;
static unsigned long num_conn = 0, num_closed = 0;
static struct timeval start_time;

const char *prog_name;
unsigned long num_conn, num_closed;
struct timeval start_time;
static char *server = NULL;
static int desired = 0;
static int port = 0;

static void
cleanup()
{
if (active_events != NULL) {
while (!is_list_empty(active_events)) {
Any_Type a = list_pop(active_events);
free(a.vp);
}
list_free(active_events);
}
}

void
sigint_handler (int signal)
sigint_exit(int fd, short event, void *arg)
{
struct timeval stop_time;
double delta_t;
struct event *signal_int = arg;
struct timeval stop_time;
double delta_t = 0;

gettimeofday (&stop_time, NULL);
gettimeofday(&stop_time, NULL);

delta_t = ((stop_time.tv_sec - start_time.tv_sec)
+ 1e-6*(stop_time.tv_usec - start_time.tv_usec));
delta_t = ((stop_time.tv_sec - start_time.tv_sec)
+ 1e-6 * (stop_time.tv_usec - start_time.tv_usec));

printf ("%s: total # conn. created = %lu, close() rate = %g conn/sec\n",
prog_name, num_conn, num_closed / delta_t);
exit (0);
printf("%s: total # conn. created = %lu, close() rate = %g conn/sec\n",
prog_name, num_conn, num_closed / delta_t);

printf("%s: caught SIGINT... Exiting.\n", __func__);

evdns_shutdown(0);
event_del(signal_int);

cleanup();
}

int
main (int argc, char **argv)
void
dns_lookup_callback(int result, char type, int count, int ttl, void *addresses,
void *arg)
{
int desired, current = 0, port, sd, max_sd = 0, n, i;
struct sockaddr_in sin, server_addr;
fd_set readable, rdfds;
struct rlimit rlimit;
struct hostent *he;
char *server;

signal (SIGINT, sigint_handler);

prog_name = strrchr (argv[0], '/');
if (prog_name)
++prog_name;
else
prog_name = argv[0];

memset (&rdfds, 0, sizeof (rdfds));

if (argc != 4)
{
fprintf (stderr, "Usage: %s server port numidle\n", prog_name);
exit (-1);
}

server = argv[1];
port = atoi (argv[2]);
desired = atoi (argv[3]);

/* boost open file limit to the max: */
if (getrlimit (RLIMIT_NOFILE, &rlimit) < 0)
{
fprintf (stderr, "%s: failed to get number of open file limit: %s",
prog_name, strerror (errno));
exit (1);
}

if (rlimit.rlim_max > FD_SETSIZE)
{
fprintf (stderr, "%s: warning: open file limit > FD_SETSIZE; "
"limiting max. # of open files to FD_SETSIZE\n", prog_name);
rlimit.rlim_max = FD_SETSIZE;
}

rlimit.rlim_cur = rlimit.rlim_max;
if (setrlimit (RLIMIT_NOFILE, &rlimit) < 0)
{
fprintf (stderr, "%s: failed to increase number of open file limit: %s",
prog_name, strerror (errno));
exit (1);
}

printf ("%s: creating and maintaining %d idle connections\n",
prog_name, desired);

memset (&server_addr, 0, sizeof (server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons (port);

he = gethostbyname (server);
if (he)
{
if (he->h_addrtype != AF_INET || he->h_length != sizeof (sin.sin_addr))
{
perror (server);
exit (-1);
uint8_t i;

if (result != DNS_ERR_NONE) {
printf("DNS Lookup: result(%d)\n",
evdns_err_to_string(result));
exit(EXIT_FAILURE);
}
memcpy (&server_addr.sin_addr, he->h_addr_list[0],
sizeof (server_addr.sin_addr));
}
else
if (!inet_aton (server, &server_addr.sin_addr))
{
fprintf (stderr, "%s: invalid server address %s\n", prog_name, server);
exit (-1);
}

gettimeofday (&start_time, NULL);

while (1)
{
while (current < desired)
{
/* create more idle connections */
sd = socket (AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
perror ("socket");
exit (-1);
}

sin = server_addr;
if (connect (sd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
printf("connect: %s\n", strerror (errno));
switch (errno)
{
case ECONNREFUSED:
/* wait for server to start up... */
sleep (1);
case ETIMEDOUT:
close (sd);
continue;

default:
perror ("connect");
exit (-1);
}
}

if (sd > max_sd)
max_sd = sd;
printf("Resolved %s\n", server);

#if DEBUG > 1
printf ("created %d\n", sd);
#endif
++num_conn;
++current;
FD_SET(sd, &rdfds);
for (i = 0; i < count; ++i) {
uint32_t *address_list = (uint32_t *) addresses;
uint8_t oct[4];
oct[0] = (uint8_t) (address_list[i] & 0x000000ff);
oct[1] = (uint8_t) ((address_list[i] & 0x0000ff00) >> 8);
oct[2] = (uint8_t) ((address_list[i] & 0x00ff0000) >> 16);
oct[3] = (uint8_t) ((address_list[i] & 0xff000000) >> 24);
printf("\t(%u.%u.%u.%u)\n", oct[0], oct[1], oct[2], oct[3]);
}

readable = rdfds;
n = select (max_sd + 1, &readable, NULL, NULL, NULL);
for (i = 0; i <= max_sd; ++i)
{
if (FD_ISSET (i, &readable))
{
#if DEBUG > 1
printf ("closed %d\n", i);
#endif
close (i);
--current;
--n;
++num_closed;
FD_CLR(i, &rdfds);
}
if (n <= 0)
break;

}

void
main(int argc, char *argv[])
{
struct event signal_int;

active_events = list_create();
if (active_events == NULL)
goto init_failure;

inactive_events = list_create();
if (inactive_events == NULL)
goto init_failure;

event_init();
evdns_init();

/*
* Initalize one event
*/
event_set(&signal_int, SIGINT, EV_SIGNAL, sigint_exit, &signal_int);

event_add(&signal_int, NULL);

prog_name = strrchr(argv[0], '/');
if (prog_name)
++prog_name;
else
prog_name = argv[0];

if (argc != 4) {
fprintf(stderr, "Usage: `%s server port numidle'\n",
prog_name);
goto init_failure;
}
}

server = argv[1];
port = atoi(argv[2]);
desired = atoi(argv[3]);

printf("%s: Using libevent-%s for %s event notification system.\n"
"Control-c to exit\n\n", prog_name, event_get_version(),
event_get_method());

gettimeofday(&start_time, NULL);

evdns_resolve_ipv4(server, 0, dns_lookup_callback, NULL);

event_dispatch();

/*
* Event loop will only exit upon receiving SIGINT. Make sure we pass
* this on to the parent process
*/
if (signal(SIGINT, SIG_DFL) < 0)
perror("signal");
else
kill(getpid(), SIGINT);

init_failure:
cleanup();
exit(EXIT_FAILURE);
}

Loading…
Cancel
Save