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 */
