Hi together,
hopefully all of us have overcome those long new year holidays and are back
to normal live & development ;)
attached you can find a patch that includes some http server fixes:
- don't close listen filedescriptor when accept failed (that can be caused
bei client just now disconnected or network error)
- added 'active_list' that saves all active http clients and so while
shutdown all active clients can be disconnected gracefully (w/o fdset
warning about active entries) and when listen port removed all active
clients for this port could be disconnected
This active_list could be used later in order to implement keep alive
timeout.
Comments and votes please!
--
Thanks,
Alex
Index: gwlib/http.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/http.c,v
retrieving revision 1.221
diff -a -u -p -r1.221 http.c
--- gwlib/http.c 23 Dec 2004 11:26:31 -0000 1.221
+++ gwlib/http.c 19 Jan 2005 15:25:34 -0000
@@ -381,7 +381,7 @@ static void deduce_body_state(HTTPEntity
h = http_header_find_first(ent->headers, "Content-Length");
if (h != NULL) {
if (octstr_parse_long(&ent->expected_body_len, h, 0, 10) == -1 ||
- ent->expected_body_len < 0) {
+ ent->expected_body_len < 0) {
error(0, "HTTP: Content-Length header wrong: <%s>",
octstr_get_cstr(h));
ent->state = body_error;
@@ -802,8 +802,8 @@ static Connection *conn_pool_get(Octstr
else
#endif /* HAVE_LIBSSL */
conn = conn_open_tcp_nb(host, port, our_host);
- debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",
- octstr_get_cstr(host), port, conn_get_id(conn));
+ debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",
+ octstr_get_cstr(host), port, conn_get_id(conn));
} else {
debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).",
octstr_get_cstr(host), port, conn_get_id(conn));
@@ -1764,6 +1764,10 @@ struct HTTPClient {
};
+/* List with all active HTTPClient's */
+static List *active_connections;
+
+
static HTTPClient *client_create(int port, Connection *conn, Octstr *ip)
{
HTTPClient *p;
@@ -1786,6 +1790,11 @@ static HTTPClient *client_create(int por
p->persistent_conn = 1;
p->conn_time = time(NULL);
p->request = NULL;
+ debug("gwlib.http", 0, "HTTP: Created HTTPClient area %p.", p);
+
+ /* add this client to active_connections */
+ list_produce(active_connections, p);
+
return p;
}
@@ -1795,13 +1804,17 @@ static void client_destroy(void *client)
HTTPClient *p;
if (client == NULL)
- return;
+ return;
p = client;
debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p);
gw_assert_allocated(p, __FILE__, __LINE__, __func__);
debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.",
- octstr_get_cstr(p->ip));
+ octstr_get_cstr(p->ip));
+
+ /* drop this client from active_connections list */
+ list_delete_equal(active_connections, p);
+
conn_destroy(p->conn);
octstr_destroy(p->ip);
octstr_destroy(p->url);
@@ -1854,8 +1867,6 @@ static int client_is_persistent(List *he
/*
* Port specific lists of clients with requests.
*/
-
-
struct port {
List *clients_with_requests;
Counter *active_consumers;
@@ -1866,16 +1877,26 @@ static Mutex *port_mutex = NULL;
static Dict *port_collection = NULL;
+static int port_match(void *client, void *port)
+{
+ return ((HTTPClient*)client)->port == *((int*)port);
+}
+
+
static void port_init(void)
{
port_mutex = mutex_create();
port_collection = dict_create(1024, NULL);
+ /* create list with all active_connections */
+ active_connections = list_create();
}
static void port_shutdown(void)
{
mutex_destroy(port_mutex);
dict_destroy(port_collection);
+ /* destroy active_connections list */
+ list_destroy(active_connections, client_destroy);
}
@@ -1890,14 +1911,17 @@ static void port_add(int port)
Octstr *key;
struct port *p;
- p = gw_malloc(sizeof(*p));
- p->clients_with_requests = list_create();
- list_add_producer(p->clients_with_requests);
- p->active_consumers = counter_create();
-
key = port_key(port);
mutex_lock(port_mutex);
- dict_put(port_collection, key, p);
+ if ((p = dict_get(port_collection, key)) == NULL) {
+ p = gw_malloc(sizeof(*p));
+ p->clients_with_requests = list_create();
+ list_add_producer(p->clients_with_requests);
+ p->active_consumers = counter_create();
+ dict_put(port_collection, key, p);
+ } else {
+ warning(0, "HTTP: port_add called for existing port (%d)", port);
+ }
mutex_unlock(port_mutex);
octstr_destroy(key);
}
@@ -1907,12 +1931,18 @@ static void port_remove(int port)
{
Octstr *key;
struct port *p;
+ List *l;
key = port_key(port);
mutex_lock(port_mutex);
p = dict_remove(port_collection, key);
mutex_unlock(port_mutex);
octstr_destroy(key);
+
+ if (p == NULL) {
+ error(0, "HTTP: Could not find port (%d) in port_collection.", port);
+ return;
+ }
list_remove_producer(p->clients_with_requests);
while (counter_value(p->active_consumers) > 0)
@@ -1920,6 +1950,10 @@ static void port_remove(int port)
list_destroy(p->clients_with_requests, client_destroy);
counter_destroy(p->active_consumers);
gw_free(p);
+
+ /* drop all active_connections for this port */
+ l = list_extract_matching(active_connections, &port, port_match);
+ list_destroy(l, client_destroy);
}
@@ -2073,16 +2107,16 @@ static void receive_request(Connection *
return;
case sending_reply:
- /* Implicite conn_unregister() and _destroy */
- if (conn_error(conn))
- goto error;
+ /* Implicite conn_unregister() and _destroy */
+ if (conn_error(conn))
+ goto error;
if (conn_outbuf_len(conn) > 0)
- return;
+ return;
/* Reply has been sent completely */
if (!client->persistent_conn) {
- conn_unregister(conn);
- client_destroy(client);
- return;
+ conn_unregister(conn);
+ client_destroy(client);
+ return;
}
/* Start reading another request */
client_reset(client);
@@ -2138,7 +2172,7 @@ static void server_thread(void *dummy)
if ((ret = gwthread_poll(tab, n, -1.0)) == -1) {
if (errno != EINTR) /* a signal was caught during poll() function */
- warning(0, "HTTP: gwthread_poll failed.");
+ warning(errno, "HTTP: gwthread_poll failed.");
continue;
}
@@ -2148,11 +2182,6 @@ static void server_thread(void *dummy)
fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen);
if (fd == -1) {
error(errno, "HTTP: Error accepting a client.");
- (void) close(tab[i].fd);
- port_remove(ports[i]);
- tab[i].fd = -1;
- ports[i] = -1;
- ssl[i] = 0;
} else {
Octstr *client_ip = host_ip(addr);
/*
@@ -2171,7 +2200,7 @@ static void server_thread(void *dummy)
}
}
}
-
+
while ((portno = list_extract_first(closed_server_sockets)) != NULL) {
for (i = 0; i < n; ++i) {
if (ports[i] == *portno) {
@@ -2184,7 +2213,7 @@ static void server_thread(void *dummy)
}
gw_free(portno);
}
-
+
j = 0;
for (i = 0; i < n; ++i) {
if (tab[i].fd != -1) {
@@ -3142,6 +3171,7 @@ void http_header_dump(List *headers)
debug("gwlib.http", 0, "End of dump.");
}
+
void http_cgivar_dump(List *cgiargs)
{
HTTPCGIVar *v;
@@ -3290,11 +3320,11 @@ void http_init(void)
proxy_init();
client_init();
conn_pool_init();
+ port_init();
server_init();
#ifdef HAVE_LIBSSL
server_ssl_init();
#endif /* HAVE_LIBSSL */
- port_init();
run_status = running;
}
@@ -3307,10 +3337,10 @@ void http_shutdown(void)
run_status = terminating;
- port_shutdown();
conn_pool_shutdown();
client_shutdown();
server_shutdown();
+ port_shutdown();
proxy_shutdown();
#ifdef HAVE_LIBSSL
openssl_shutdown_locks();