[PATCH] http server fixes

Alexander Malysh <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
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
http-server-active-list.patch (text/x-diff, 7.8 KB)
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();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.