ApacheBench
view release on metacpan or search on metacpan
src/apachebench/socket_io.c view on Meta::CPAN
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include "types.h"
#include "socket_io.h"
#include "http_util.h"
#include "xs_util.h"
#include "regression_data.h"
/* --------------------------------------------------------- */
/* make an fd non blocking */
static void
nonblock(int fd) {
int i = 1;
#ifdef BEOS
setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, &i, sizeof(i));
#else
ioctl(fd, FIONBIO, &i);
#endif
}
/* --------------------------------------------------------- */
/* start asnchronous non-blocking connection */
static void
start_connect(struct global * registry, struct connection * c) {
c->read = 0;
c->bread = 0;
c->keepalive = 0;
c->cbx = 0;
c->gotheader = 0;
c->fd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef AB_DEBUG
printf("AB_DEBUG: start of start_connect()\n");
#endif
if (c->fd < 0) {
myerr(registry->warn_and_error, "socket error");
registry->failed[c->url]++;
close_connection(registry, c);
return;
}
nonblock(c->fd);
#ifdef AB_DEBUG
printf("AB_DEBUG: start_connect() - stage 1\n");
#endif
c->connect_time.tv_sec = 0;
c->connect_time.tv_usec = 0;
c->sent_request_time.tv_sec = 0;
c->sent_request_time.tv_usec = 0;
gettimeofday(&c->start_time, 0);
{
/* get server information */
struct hostent *he;
#ifdef AB_DEBUG
printf("AB_DEBUG: start_connect() - stage 2, c->url: '%d'\n", c->url);
#endif
he = gethostbyname(registry->hostname[c->url]);
#ifdef AB_DEBUG
printf("AB_DEBUG: start_connect() - stage 3\n");
#endif
if (!he) {
char * warn = malloc(256 * sizeof(char));
sprintf(warn, "Bad hostname: %s, the information stored for it could be wrong!", registry->hostname[c->url]);
myerr(registry->warn_and_error, warn);
free(warn);
/* bad hostname, yields the resource */
registry->failed[c->url]++;
close_connection(registry, c);
return;
}
#ifdef AB_DEBUG
printf("AB_DEBUG: start_connect() - stage 4\n");
#endif
registry->server.sin_family = he->h_addrtype;
registry->server.sin_port = htons(registry->port[c->url]);
registry->server.sin_addr.s_addr = ((unsigned long *) (he->h_addr_list[0]))[0];
}
#ifdef AB_DEBUG
printf("AB_DEBUG: start_connect() - stage 5\n");
#endif
if (connect(c->fd, (struct sockaddr *) & registry->server, sizeof(registry->server)) < 0) {
if (errno == EINPROGRESS) {
src/apachebench/socket_io.c view on Meta::CPAN
registry->memory[c->run] >= 3)
strncat(c->response, registry->buffer, r);
#ifdef AB_DEBUG
printf("AB_DEBUG: read_connection() - stage 2\n");
#endif
if (!c->gotheader) {
char *s;
int wslen = 4;
int space = CBUFFSIZE - c->cbx - 1; /* -1 to allow for 0
* terminator */
int tocopy = (space < r) ? space : r;
#ifndef CHARSET_EBCDIC
memcpy(c->cbuff + c->cbx, registry->buffer, tocopy);
#else /* CHARSET_EBCDIC */
ascii2ebcdic(c->cbuff + c->cbx, registry->buffer, tocopy);
#endif /* CHARSET_EBCDIC */
c->cbx += tocopy;
space -= tocopy;
c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */
s = strstr(c->cbuff, "\r\n\r\n");
/*
* this next line is so that we talk to NCSA 1.5 which blatantly
* breaks the http specification
*/
if (!s) {
s = strstr(c->cbuff, "\n\n");
wslen = 2;
}
if (!s) {
/* read rest next time */
if (registry->memory[c->run] >= 2)
c->response_headers = "";
if (space)
return;
else {
/*
* header is in invalid or too big - close connection
*/
ab_close(c->fd);
FD_CLR(c->fd, ®istry->writebits);
start_connect(registry, c);
}
} else {
/* have full header */
/*
* XXX: this parsing isn't even remotely HTTP compliant... but in
* the interest of speed it doesn't totally have to be, it just
* needs to be extended to handle whatever servers folks want to
* test against. -djg
*/
c->gotheader = 1;
*s = 0; /* terminate at end of header */
if (registry->memory[c->run] >= 2) {
c->response_headers = malloc(CBUFFSIZE * sizeof(char));
strcpy(c->response_headers, c->cbuff);
}
if (registry->keepalive[c->url] &&
(strstr(c->cbuff, "Keep-Alive") ||
strstr(c->cbuff, "keep-alive"))) { /* for benefit of MSIIS */
char *cl;
cl = strstr(c->cbuff, "Content-Length:");
/* handle NCSA, which sends Content-length: */
if (!cl)
cl = strstr(c->cbuff, "Content-length:");
if (cl) {
c->keepalive = 1;
c->length = atoi(cl + 16);
}
}
c->bread += c->cbx - (s + wslen - c->cbuff) + r - tocopy;
}
} else {
/* outside header, everything we have read is entity body */
c->bread += r;
}
/*
* cater for the case where we're using keepalives and doing HEAD
* requests
*/
if (c->keepalive &&
((c->bread >= c->length) || (registry->posting[c->url] < 0))) {
/* save current url for checking for hostname/port changes */
int prev = c->url;
/* finished a keep-alive connection */
registry->good[c->url]++;
registry->finished[c->url]++;
store_regression_data(registry, c);
if (++registry->done >= registry->need_to_be_done)
return;
if (!schedule_next_request(registry, c))
return;
c->length = 0;
c->gotheader = 0;
c->cbx = 0;
c->read = c->bread = 0;
c->keepalive = 0;
/* if new hostname/port is different from last hostname/port, or new
url is *not* keepalive, then we need to close connection and start
a new connection */
if (registry->keepalive[c->url] &&
strcmp(registry->hostname[c->url], registry->hostname[prev]) == 0
&& registry->port[c->url] == registry->port[prev]) {
write_request(registry, c);
registry->started[c->url]++;
c->start_time = c->connect_time; /* zero connect time with keep-alive */
} else {
ab_close(c->fd);
FD_CLR(c->fd, ®istry->readbits);
FD_CLR(c->fd, ®istry->writebits);
start_connect(registry, c);
}
}
}
/* --------------------------------------------------------- */
/* close down connection and save stats */
static void
close_connection(struct global * registry, struct connection * c) {
#ifdef AB_DEBUG
printf("AB_DEBUG: start of close_connection(), postdata[%d] = %s\n", c->url, registry->postdata[c->url]);
#endif
if (registry->use_auto_cookies[c->run])
extract_cookies_from_response(registry, c);
store_regression_data(registry, c);
registry->finished[c->url]++;
#ifdef AB_DEBUG
printf("AB_DEBUG: close_connection() - stage 1\n");
#endif
ab_close(c->fd);
FD_CLR(c->fd, ®istry->readbits);
FD_CLR(c->fd, ®istry->writebits);
#ifdef AB_DEBUG
printf("AB_DEBUG: close_connection() - stage 2\n");
#endif
/* finish if last response has been received */
if (++registry->done >= registry->need_to_be_done)
return;
#ifdef AB_DEBUG
printf("AB_DEBUG: close_connection() - stage 3\n");
#endif
/* else continue with requests in run queues */
if (schedule_next_request(registry, c))
start_connect(registry, c);
}
/* --------------------------------------------------------- */
/* write out request to a connection - assumes we can write
(small) request out in one go into our new socket buffer */
static void
write_request(struct global * registry, struct connection * c) {
#ifndef NO_WRITEV
struct iovec out[2];
src/apachebench/socket_io.c view on Meta::CPAN
int i = c->url;
char * ctype = calloc(40, sizeof(char));
strcpy(ctype, "application/x-www-form-urlencoded");
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 0.1\n");
#endif
if (registry->ctypes[i]) {
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 0.1.1\n");
#endif
free(ctype);
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 0.1.2\n");
#endif
ctype = registry->ctypes[i];
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 1\n");
#endif
c->request = calloc(registry->buffersize[c->run], sizeof(char));
c->request_headers = calloc(registry->buffersize[c->run], sizeof(char));
if (registry->posting[i] <= 0) {
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 1.1 (GET)\n");
#endif
sprintf(c->request_headers, "%s %s HTTP/1.0\r\n"
"User-Agent: ApacheBench-Perl/%s\r\n"
"Host: %s\r\n"
"Accept: */*\r\n",
(registry->posting[i] == 0) ? "GET" : "HEAD",
registry->path[i],
registry->version,
registry->hostname[i]);
} else {
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 1.1 (POST)\n");
#endif
sprintf(c->request_headers, "POST %s HTTP/1.0\r\n"
"User-Agent: ApacheBench-Perl/%s\r\n"
"Host: %s\r\n"
"Accept: */*\r\n"
"Content-length: %d\r\n"
"Content-type: %s\r\n",
registry->path[i],
registry->version,
registry->hostname[i],
registry->postlen[i],
ctype);
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2\n");
#endif
if (registry->keepalive[i])
strcat(c->request_headers, "Connection: Keep-Alive\r\n");
if (registry->cookie[c->run]) {
strcat(c->request_headers, "Cookie: ");
strcat(c->request_headers, registry->cookie[c->run]);
strcat(c->request_headers, "\r\n");
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2.1: c->run %d; c->thread %d\n", c->run, c->thread);
#endif
allocate_auto_cookie_memory(registry, c);
if (registry->use_auto_cookies[c->run] && registry->auto_cookies[c->run] != NULL && registry->auto_cookies[c->run][c->thread] != NULL) {
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2.2a: request_headers %s\n", c->request_headers);
printf("AB_DEBUG: reset_request() - stage 2.2b: auto_cookies %s\n", registry->auto_cookies[c->run][c->thread]);
#endif
strcat(c->request_headers, registry->auto_cookies[c->run][c->thread]);
}
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2.3: c->run %d; c->thread %d\n", c->run, c->thread);
#endif
if (registry->req_headers[i]) {
strcat(c->request_headers, registry->req_headers[i]);
strcat(c->request_headers, "\r\n");
}
strcat(c->request_headers, "\r\n");
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 2.4: c->run %d; c->thread %d\n", c->run, c->thread);
#endif
strcpy(c->request, c->request_headers);
c->reqlen = strlen(c->request);
#ifdef AB_DEBUG
printf("AB_DEBUG: reset_request() - stage 3\n");
#endif
#ifdef CHARSET_EBCDIC
ebcdic2ascii(c->request, c->request, c->reqlen);
#endif /* CHARSET_EBCDIC */
return 0;
}
/* --------------------------------------------------------- */
/* setup the next request in the sequence / repetition / run to be sent
returns 1 if the next request is ready to be sent,
returns 0 if this connection is done,
sets the connection values: c->run, c->url, c->thread, and c->state,
as well as helper structures: registry->which_thread[][],
registry->ready_to_run_queue[], and registry->arranged[]
( run in 0.575 second using v1.01-cache-2.11-cpan-df04353d9ac )