As talked about earlier in this mailing list, I've created a patch to
the 1.4.2 server which makes the server send blank packets to all
connected clients once per time period if no other client activity has
happened. This allows the server to notice bum connections much faster.
I've tested this patch with a number of clients, but certainly not them
all. Exodus 0.6.0.0 will stop working if you use this feature, but
there is a fix in CVS for this (so look out for the next release).
I'm still not 100% satisfied w/ this solution. In my testing it can
still take 10-20 minutes for the server to notice laptop users who pull
the network cable while connected. The problem is that the network
tries to deliver the packets for a long time before giving up. I'd like
to eventually add something to handle this, but that will be more work,
and probably a JEP because it'd require protocol changes. If anyone has
ideas or thoughts, I'd be happy to discuss this.
Nathan
--- ../tmp/jabber-1.4.2/jabber.xml Tue May 15 11:21:56 2001
+++ jabber.xml Tue May 28 12:48:52 2002
@@ -310,6 +310,17 @@
limit the amount of time allowed for authentication to be
completed, e.g., <authtime>10</authtime> for 10 seconds
+ * heartbeat - default is to not send out heartbeat packets
+ to the clients. This option allows you to specify that
+ you want heartbeats to happen every x seconds. This is
+ useful if you have a lot of dial-up or laptop users who
+ may drop their connection without logging off of jabber.
+ Otherwise the server won't notice that they are offline until
+ someone tries to send a packet to them (and the message is
+ lost). Example: <heartbeat>60</heartbeat>
+ NOTE: Exodus 0.6.0.0 will stop working if you turn this
+ feature on! There is a fix in Exodus's CVS for this.
+
* karma - this is an input/output rate limiting system that
the Jabber team came up with to prevent bandwidth hogging.
For details about karma, read the io section at the bottom
@@ -323,6 +334,7 @@
</load>
<pthcsock xmlns='jabber:config:pth-csock'>
<authtime/>
+ <heartbeat/>
<karma>
<init>10</init>
<max>10</max>
--- ../../tmp/jabber-1.4.2/pthsock/client.c Fri Feb 8 02:39:30 2002
+++ client.c Thu May 16 19:30:00 2002
@@ -57,12 +57,14 @@
#include <jabberd.h>
#define DEFAULT_AUTH_TIMEOUT 0
+#define DEFAULT_HEARTBEAT 0
/* socket manager instance */
typedef struct smi_st
{
instance i;
int auth_timeout;
+ int heartbeat;
HASHTABLE aliases;
HASHTABLE users;
xmlnode cfg;
@@ -79,6 +81,7 @@
user_state state;
char *client_id, *sid, *res, *auth_id;
time_t connect_time;
+ time_t last_activity;
mio m;
pth_msgport_t pre_auth_mp;
} _cdata,*cdata;
@@ -235,6 +238,7 @@
}*/
log_debug("c2s", "[%s] Writing packet to MIO: %s", ZONE,
xmlnode2str(xmlnode_get_firstchild(p->x)));
mio_write(m, xmlnode_get_firstchild(p->x), NULL, 0);
+ cdcur->last_activity = time(NULL);
}
return r_DONE;
@@ -249,6 +253,7 @@
cd->pre_auth_mp = pth_msgport_create("pre_auth_mp");
cd->state = state_UNKNOWN;
cd->connect_time = time(NULL);
+ cd->last_activity = cd->connect_time;
cd->m = m;
cd->si = s__i;
@@ -427,6 +432,7 @@
{ /* normal delivery of packets after authed */
x = pthsock_make_route(x, jid_full(cd->session_id), cd->client_id, NULL);
deliver(dpacket_new(x), cd->si->i);
+ cd->last_activity = time(NULL);
}
break;
}
@@ -479,6 +485,34 @@
return r_DONE;
}
+int _pthsock_client_heartbeat(void *arg, const void *key, void *data)
+{
+ time_t skipbeat;
+ cdata cd = (cdata)data;
+
+ skipbeat = time(NULL) - cd->si->heartbeat;
+ if ( (cd->state == state_AUTHD) &&
+ (cd->last_activity < skipbeat) )
+ {
+ log_debug("c2s", "[%s] heartbeat on fd %d", ZONE, cd->m->fd);
+ mio_write(cd->m, NULL, " \n", -1);
+ }
+ return 1;
+}
+
+/* auth timeout beat function */
+result pthsock_client_heartbeat(void *arg)
+{
+ smi s__i = (smi)arg;
+
+ if(s__i->users == NULL)
+ return r_UNREG;
+
+ ghash_walk(s__i->users, _pthsock_client_heartbeat, NULL);
+ return r_DONE;
+}
+
+
int _pthsock_client_shutdown(void *arg, const void *key, void *data)
{
cdata cd = (cdata)data;
@@ -513,6 +547,7 @@
s__i = pmalloco(i->p, sizeof(_smi));
s__i->auth_timeout = DEFAULT_AUTH_TIMEOUT;
+ s__i->heartbeat = DEFAULT_HEARTBEAT;
s__i->i = i;
s__i->aliases = ghash_create_pool(i->p, 7, (KEYHASHFUNC)str_hash_code,
(KEYCOMPAREFUNC)j_strcmp);
s__i->users = ghash_create_pool(i->p, 503, (KEYHASHFUNC)str_hash_code,
(KEYCOMPAREFUNC)j_strcmp);
@@ -548,6 +583,10 @@
{
s__i->auth_timeout = j_atoi(xmlnode_get_data(cur), 0);
}
+ else if(j_strcmp(xmlnode_get_name(cur), "heartbeat") == 0)
+ {
+ s__i->heartbeat = j_atoi(xmlnode_get_data(cur), 0);
+ }
else if(j_strcmp(xmlnode_get_name(cur), "rate") == 0)
{
rate_time = j_atoi(xmlnode_get_attrib(cur, "time"), 0);
@@ -630,5 +669,12 @@
pool_cleanup(i->p, pthsock_client_shutdown, (void*)s__i);
if(s__i->auth_timeout)
register_beat(5, pthsock_client_timeout, (void*)s__i);
+
+ if(s__i->heartbeat)
+ {
+ log_debug("c2s", "Registering heartbeat: %d", s__i->heartbeat);
+ //Register a heartbeat to catch dead sockets.
+ register_beat(s__i->heartbeat, pthsock_client_heartbeat, (void*)s__i);
+ }
}
--- ../../tmp/jabber-1.4.2/pthsock/README.pthsock_client Mon Jan 22 12:24:18
2001
+++ README.pthsock_client Tue May 28 12:50:03 2002
@@ -22,6 +22,20 @@
in the specified timeout seconds, then they will be dropped -->
<authtime>30</authtime>
+ <!--
+ heartbeat - default is to not send out heartbeat packets
+ to the clients. This option allows you to specify that
+ you want heartbeats to happen every x seconds. This is
+ useful if you have a lot of dial-up or laptop users who
+ may drop their connection without logging off of jabber.
+ Otherwise the server won't notice that they are offline until
+ someone tries to send a packet to them (and the message is
+ lost). Example: <heartbeat>60</heartbeat>
+ NOTE: Exodus 0.6.0.0 will stop working if you turn this
+ feature on! There is a fix in Exodus's CVS for this.
+ -->
+ <heartbeat>0</heartbeat>
+
<!-- you may override any defaults set in the <io/> section with values
here for rate and karma... any values not supplied will be set to
either the defaults set in the <io/> section, or the internal defaults
-->