diff --git a/src/reqs.c b/src/reqs.c
index 2de43a8..56b9b17 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -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);
@@ -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) {
@@ -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.",
@@ -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;
@@ -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) "
diff --git a/src/sock.c b/src/sock.c
index d5d899b..70e8c51 100644
--- a/src/sock.c
+++ b/src/sock.c
@@ -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
diff --git a/src/sock.h b/src/sock.h
index 5eac10b..b140cf4 100644
--- a/src/sock.h
+++ b/src/sock.h
@@ -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);
diff --git a/src/stats.c b/src/stats.c
index c7b4423..3a6987f 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -33,6 +33,13 @@
#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;
@@ -40,9 +47,11 @@ struct stat_s {
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.
@@ -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,
- "\n"
- "\n"
- "\n"
- "
%s version %s run-time statistics\n"
- "\n"
- "%s version %s run-time statistics
\n"
- "\n"
- "Number of open connections: %lu
\n"
- "Number of requests: %lu
\n"
- "Number of bad connections: %lu
\n"
- "Number of denied connections: %lu
\n"
- "Number of refused connections due to high load: %lu\n"
- "
\n"
- "
\n"
- "Generated by %s version %s.
\n" "\n"
- "\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(; idxpeers)/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;
}
@@ -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(; idxpeers)/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(; idxpeers)/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;
+}
diff --git a/src/stats.h b/src/stats.h
index b1a43c3..5d058d2 100644
--- a/src/stats.h
+++ b/src/stats.h
@@ -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
diff --git a/src/utils.c b/src/utils.c
index ef2e673..acbab40 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -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.
*/
diff --git a/src/utils.h b/src/utils.h
index e6b0fc4..b68c5d0 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -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,