Hi, Yury.
There is a problem in http.c with socket pool. Cached connection
to http resources never cleaned from this pool, even if it closed by other
side. So if you do not use proxy for your requests you will reach the limit of
open descriptor soon (depend on load).
I have patch againtst 1.3.2 which clean these connections. It doensn't accepted
by kannel because it creates one extra thread to clean descriptors.
But I use it in my kannel branch.
So either setup own proxy, either try my patch,
either do something else (restart kannel every hour ;))

Yury Mikhienko wrote:
Hi developers!

I was start kannel wapbox on Solaris 2.9 system.
But after some time I got error on opening new socket to bearerbox (Too many open 
files error)
lsof command show me 277 open descriptors on wapbox process, but 90% at all in 
CLOSE_WAIT station
Can I set timeout on unused WSP session and close the connect to bearerbox?
Or may be closing sessions (scavenging) must be automatically?
I can set up system parameters rlim_fd_max and rlim_fd_cur, but I do not sure of that 
method (system overflow may be caused)

Thanx for your answers.



--
Vjacheslav Chekushin                                mailto:[EMAIL PROTECTED]
Latvian Mobile Phone Company                        http://www.lmt.lv
--- ../gateway_base/gwlib/http.c        Tue Mar  2 11:16:35 2004
+++ gwlib/http.c        Tue Mar  2 13:56:59 2004
@@ -709,7 +709,7 @@
  */
 static Dict *conn_pool = NULL;
 static Mutex *conn_pool_lock = NULL;
-
+static long pool_control_thread_id = -1;
 
 static void conn_pool_item_destroy(void *item)
 {
@@ -726,17 +726,52 @@
     conn_pool_lock = mutex_create();
 }
 
-
-static void conn_pool_shutdown(void)
+static Octstr *conn_pool_key(Octstr *host, int port)
 {
-    dict_destroy(conn_pool);
-    mutex_destroy(conn_pool_lock);
+    return octstr_format("%S:%d", host, port);
 }
 
+#define KEEPALIVE_TIMEOUT 600
 
-static Octstr *conn_pool_key(Octstr *host, int port)
-{
-    return octstr_format("%S:%d", host, port);
+static void conn_pool_clean(void) {
+    List *all_keys, *list;
+    Octstr *key;
+    Connection *conn;
+    int i;
+
+    mutex_lock(conn_pool_lock);
+  
+    all_keys = dict_keys(conn_pool);
+    while ((key = list_extract_first(all_keys)) != NULL) {
+        list = dict_get(conn_pool,key);
+        i = 0;
+        while (i < list_len(list)) {
+            conn = list_get(list, i);
+
+            /* Check whether the server has closed the connection while
+             * it has been in the pool. */
+            conn_wait(conn, 0);
+            if (conn_eof(conn) || conn_error(conn)) {
+               debug("gwlib.http", 0, "Delete connection with fd 
%d.",conn_get_id(conn));
+                conn_destroy(conn);
+                list_delete(list, i, 1);
+            } else {
+               if (conn_is_expired(conn,KEEPALIVE_TIMEOUT) == 0) {
+                 debug("gwlib.http", 0, "Delete connection with fd %d. (timeout)",
+                       conn_get_id(conn));
+                 conn_destroy(conn);
+                 list_delete(list, i, 1);
+               } else {
+                    debug("gwlib.http", 0, "Fd %d is alive.",conn_get_id(conn));
+                    i++;
+               }
+            }
+        }
+        octstr_destroy(key);
+    }
+
+    list_destroy(all_keys, NULL);
+    mutex_unlock(conn_pool_lock);
 }
 
 
@@ -804,6 +839,22 @@
 }
 #endif
 
+static void pool_control_thread(void *arg) {
+  while (run_status == running) {
+    gwthread_sleep(60);
+    conn_pool_clean();
+  }
+  pool_control_thread_id = -1;
+}
+
+static void conn_pool_shutdown(void)
+{
+    if (pool_control_thread_id >= 0) 
+        gwthread_wakeup(pool_control_thread_id);
+    gwthread_join_every(pool_control_thread);
+    dict_destroy(conn_pool);
+    mutex_destroy(conn_pool_lock);
+}
 
 /*
  * Internal lists of completely unhandled requests and requests for which
@@ -1049,6 +1100,7 @@
 
 #ifdef USE_KEEPALIVE 
     if (trans->persistent) {
+        conn_update_usage(trans->conn);
         if (proxy_used_for_host(trans->host))
             conn_pool_put(trans->conn, proxy_hostname, proxy_port);
         else
@@ -1601,6 +1653,7 @@
        if (!client_threads_are_running) {
            client_fdset = fdset_create();
            gwthread_create(write_request_thread, NULL);
+           pool_control_thread_id = gwthread_create(pool_control_thread, NULL);
            client_threads_are_running = 1;
        }
        mutex_unlock(client_thread_lock);
--- ../gateway_base/gwlib/conn.c        Tue Mar  2 11:16:35 2004
+++ gwlib/conn.c        Tue Mar  2 13:58:46 2004
@@ -119,6 +119,9 @@
     /* socket state */
     enum {yes,no} connected;
 
+    /* time of last usage */
+    unsigned long last_ts;
+
     /* Protected by outlock */
     Octstr *outbuf;
     long outbufpos;   /* start of unwritten data in outbuf */
@@ -495,6 +498,17 @@
   return -1;
 }
 
+void conn_update_usage(Connection *conn) {
+  conn->last_ts = time(NULL);
+}
+ 
+int conn_is_expired(Connection *conn, unsigned long secs) {
+  if ((time(NULL) - (conn->last_ts + secs)) < 0) {
+    return -1;
+  }
+  return 0;
+}
+ 
 int conn_get_connect_result(Connection *conn)
 {
   int err,len;
--- ../gateway_base/gwlib/conn.h        Tue Mar  2 11:16:35 2004
+++ gwlib/conn.h        Tue Mar  2 13:56:59 2004
@@ -143,6 +143,13 @@
 /* Returns 0 if socket is connected, -1 overwise */
 int conn_is_connected(Connection *conn);
 
+/* Update the time of last usage for this connection */
+void conn_update_usage(Connection *conn);
+
+/* Check for expired connection. Returns 0 if connection has not been used 
+ * more than secs seconds, -1 overwise */
+int conn_is_expired(Connection *conn, unsigned long secs);
+
 /* If socket is in the 'connecting' state, it must be listen by poller.
  * After poller returns, connection must be checked for connection 
  * procedure's result. Return 0 if connection done successfully */

Reply via email to