Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/reqs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,9 @@ void handle_connection (int fd)
close (fd);
return;
}

set_readtimeout(connptr->client_fd, config.idletimeout);
set_writetimeout(connptr->client_fd, config.idletimeout);

if (check_acl (peer_ipaddr, peer_string, config.access_list) <= 0) {
update_stats (STAT_DENIED);
Expand Down Expand Up @@ -1462,6 +1465,7 @@ void handle_connection (int fd)
}
goto fail;
}
update_reqpeer(request->host);

connptr->upstream_proxy = UPSTREAM_HOST (request->host);
if (connptr->upstream_proxy != NULL) {
Expand All @@ -1472,7 +1476,7 @@ void handle_connection (int fd)
connptr->server_fd = opensock (request->host, request->port,
connptr->server_ip_addr);
if (connptr->server_fd < 0) {
indicate_http_error (connptr, 500, "Unable to connect",
indicate_http_error (connptr, 601, "Unable to connect",
"detail",
PACKAGE_NAME " "
"was unable to connect to the remote web server.",
Expand All @@ -1485,10 +1489,14 @@ void handle_connection (int fd)
"file descriptor %d.", request->host,
connptr->server_fd);


if (!connptr->connect_method)
establish_http_connection (connptr, request);
}

set_readtimeout(connptr->server_fd, config.idletimeout);
set_writetimeout(connptr->server_fd, config.idletimeout);

if (process_client_headers (connptr, hashofheaders) < 0) {
update_stats (STAT_BADCONN);
goto fail;
Expand All @@ -1510,6 +1518,7 @@ void handle_connection (int fd)
}

relay_connection (connptr);
update_donepeer(request->host);

log_message (LOG_INFO,
"Closed connection between local client (fd:%d) "
Expand Down
28 changes: 28 additions & 0 deletions src/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,34 @@ int socket_blocking (int sock)
return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK);
}

/*
* set the socket 's read timeout -hanbaga
*/
int set_readtimeout(int sock, int timeout)
{
assert (sock >= 0);

struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;

return setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(struct timeval));
}

/*
* set the socket 's write timeout -hanbaga
*/
int set_writetimeout(int sock, int timeout)
{
assert (sock >= 0);

struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;

return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));
}

/*
* Start listening to a socket. Create a socket with the selected port.
* The size of the socket address will be returned to the caller through
Expand Down
3 changes: 3 additions & 0 deletions src/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
extern int opensock (const char *host, int port, const char *bind_to);
extern int listen_sock (uint16_t port, socklen_t * addrlen);

extern int set_readtimeout(int sock, int timeout);
extern int set_writetimeout(int sock, int timeout);

extern int socket_nonblocking (int sock);
extern int socket_blocking (int sock);

Expand Down
192 changes: 138 additions & 54 deletions src/stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,25 @@
#include "stats.h"
#include "utils.h"
#include "conf.h"
#include "hashmap.h"

struct peer_s {
char host[36];
int count;
int done;
};

struct stat_s {
unsigned long int num_reqs;
unsigned long int num_badcons;
unsigned long int num_open;
unsigned long int num_refused;
unsigned long int num_denied;
struct peer_s peers[100];
};

static struct stat_s *stats;
static int MAX_ITEM_LEN = 48;

/*
* Initialize the statistics information to zero.
Expand All @@ -63,65 +72,86 @@ int
showstats (struct conn_s *connptr)
{
char *message_buffer;
char opens[16], reqs[16], badconns[16], denied[16], refused[16];
FILE *statfile;

snprintf (opens, sizeof (opens), "%lu", stats->num_open);
snprintf (reqs, sizeof (reqs), "%lu", stats->num_reqs);
snprintf (badconns, sizeof (badconns), "%lu", stats->num_badcons);
snprintf (denied, sizeof (denied), "%lu", stats->num_denied);
snprintf (refused, sizeof (refused), "%lu", stats->num_refused);

if (!config.statpage || (!(statfile = fopen (config.statpage, "r")))) {
message_buffer = (char *) safemalloc (MAXBUFFSIZE);
if (!message_buffer)
return -1;

snprintf
(message_buffer, MAXBUFFSIZE,
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
"<html>\n"
"<head><title>%s version %s run-time statistics</title></head>\n"
"<body>\n"
"<h1>%s version %s run-time statistics</h1>\n"
"<p>\n"
"Number of open connections: %lu<br />\n"
"Number of requests: %lu<br />\n"
"Number of bad connections: %lu<br />\n"
"Number of denied connections: %lu<br />\n"
"Number of refused connections due to high load: %lu\n"
"</p>\n"
"<hr />\n"
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
"</html>\n",
PACKAGE, VERSION, PACKAGE, VERSION,
stats->num_open,
stats->num_reqs,
stats->num_badcons, stats->num_denied,
stats->num_refused, PACKAGE, VERSION);

if (send_http_message (connptr, 200, "OK",
message_buffer) < 0) {
safefree (message_buffer);
return -1;
}


message_buffer = (char *) safemalloc (MAXBUFFSIZE);
if (!message_buffer)
return -1;
memset(message_buffer, 0, MAXBUFFSIZE);

char item[MAX_ITEM_LEN];
int idx = 0;

for(; idx<sizeof(stats->peers)/sizeof(struct peer_s); ++idx)
{
if (strlen(stats->peers[idx].host) == 0){
continue;
}
if (idx >= MAXBUFFSIZE/MAX_ITEM_LEN){
break;
}
if (idx == 0){
strcat(message_buffer, "{\"domain\":{");
}
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":[%d, %d],", stats->peers[idx].host, stats->peers[idx].count, stats->peers[idx].done);
strcat(message_buffer, item);
}

if (strlen(message_buffer) > 0 && strlen(message_buffer) + 2 < MAXBUFFSIZE){
message_buffer[strlen(message_buffer)-1] = '}';
strcat(message_buffer, ",");
}else if (strlen(message_buffer) == 0){
message_buffer[0] = '{';
}

do {
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":%d,", "connreqs", stats->num_reqs);
if (strlen(message_buffer) + strlen(item) >= MAXBUFFSIZE){
break;
}
strcat(message_buffer, item);
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":%d,", "connbads", stats->num_badcons);
if (strlen(message_buffer) + strlen(item) >= MAXBUFFSIZE){
break;
}
strcat(message_buffer, item);
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":%d,", "connopens", stats->num_open);
if (strlen(message_buffer) + strlen(item) >= MAXBUFFSIZE){
break;
}
strcat(message_buffer, item);
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":%d,", "connrefused", stats->num_refused);
if (strlen(message_buffer) + strlen(item) >= MAXBUFFSIZE){
break;
}
strcat(message_buffer, item);
memset(item, 0, MAX_ITEM_LEN);
snprintf(item, MAX_ITEM_LEN, "\"%s\":%d", "conndenied", stats->num_denied);
if (strlen(message_buffer) + strlen(item) >= MAXBUFFSIZE){
break;
}
strcat(message_buffer, item);
} while(0);

int httpcode = 200;
if (strlen(message_buffer) + 1 < MAXBUFFSIZE){
strcat(message_buffer, "}");
}else{
httpcode = 500;
}

if (send_http_json_message (connptr, httpcode, "OK", message_buffer) < 0) {
safefree (message_buffer);
return 0;
}

add_error_variable (connptr, "opens", opens);
add_error_variable (connptr, "reqs", reqs);
add_error_variable (connptr, "badconns", badconns);
add_error_variable (connptr, "deniedconns", denied);
add_error_variable (connptr, "refusedconns", refused);
add_standard_vars (connptr);
send_http_headers (connptr, 200, "Statistic requested");
send_html_file (statfile, connptr);
fclose (statfile);

memset(stats, 0, sizeof(struct stat_s));
safefree (message_buffer);
return 0;
}

Expand Down Expand Up @@ -154,3 +184,57 @@ int update_stats (status_t update_level)

return 0;
}

int update_reqpeer(char* host)
{
struct peer_s* empty_peer = NULL;
int idx = 0;

for(; idx<sizeof(stats->peers)/sizeof(struct peer_s); ++idx)
{
if (strlen(stats->peers[idx].host) == 0 && stats->peers[idx].count == 0 && empty_peer == NULL){
empty_peer = &stats->peers[idx];
break;
}
if (0 == strncmp(host, stats->peers[idx].host, 35)){
stats->peers[idx].count += 1;
log_message(LOG_CONN, host);
return 0;
}
}

if (empty_peer == NULL){
return -1;
}

strncpy(empty_peer->host, host, 35);
empty_peer->count = 1;
return 1;
}

int update_donepeer(char* host)
{
struct peer_s* empty_peer = NULL;
int idx = 0;

for(; idx<sizeof(stats->peers)/sizeof(struct peer_s); ++idx)
{
if (strlen(stats->peers[idx].host) == 0 && stats->peers[idx].count == 0 && stats->peers[idx].done == 0 && empty_peer == NULL){
empty_peer = &stats->peers[idx];
break;
}
if (0 == strncmp(host, stats->peers[idx].host, 35)){
stats->peers[idx].done += 1;
log_message(LOG_CONN, host);
return 0;
}
}

if (empty_peer == NULL){
return -1;
}

strncpy(empty_peer->host, host, 35);
empty_peer->done = 1;
return 0;
}
2 changes: 2 additions & 0 deletions src/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ typedef enum {
extern void init_stats (void);
extern int showstats (struct conn_s *connptr);
extern int update_stats (status_t update_level);
extern int update_reqpeer(char* host);
extern int update_donepeer(char* host);

#endif
24 changes: 24 additions & 0 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,30 @@ send_http_message (struct conn_s *connptr, int http_code,
return 0;
}

int
send_http_json_message (struct conn_s *connptr, int http_code,
const char *error_title, const char *message)
{
static const char *headers[] = {
"Server: " PACKAGE "/" VERSION,
"Content-type: application/json",
"Connection: close"
};

http_message_t msg;

msg = http_message_create (http_code, error_title);
if (msg == NULL)
return -1;

http_message_add_headers (msg, headers, 3);
http_message_set_body (msg, message, strlen (message));
http_message_send (msg, connptr->client_fd);
http_message_destroy (msg);

return 0;
}

/*
* Safely creates filename and returns the low-level file descriptor.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct conn_s;

extern int send_http_message (struct conn_s *connptr, int http_code,
const char *error_title, const char *message);
extern int send_http_json_message (struct conn_s *connptr, int http_code,
const char *error_title, const char *message);

extern int pidfile_create (const char *path);
extern int create_file_safely (const char *filename,
Expand Down