From 246c148d0e7cedcd1f9c3cdef933a3b0a2e2e7af Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Sat, 16 May 2015 10:55:26 -0400 Subject: [PATCH] Track ping replies Set a limit on the number of pings without a reply and exit if the limit is reached. Useful for detecing broken network connections due to network changes. The default configuration will take about 4 minutes to detect failure (1 keepalive every 60 seconds, tolerate 3 failures). --- src/xmppipe.c | 26 +++++++++++++++++++++++--- src/xmppipe.h | 4 +++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/xmppipe.c b/src/xmppipe.c index bca1b82..ac0a652 100644 --- a/src/xmppipe.c +++ b/src/xmppipe.c @@ -68,7 +68,7 @@ main(int argc, char **argv) jid = xmppipe_getenv("XMPPIPE_USERNAME"); pass = xmppipe_getenv("XMPPIPE_PASSWORD"); - while ( (ch = getopt(argc, argv, "a:dDehk:m:o:P:p:r:sS:u:v")) != -1) { + while ( (ch = getopt(argc, argv, "a:dDehk:K:m:o:P:p:r:sS:u:v")) != -1) { switch (ch) { case 'u': /* username/jid */ @@ -106,6 +106,10 @@ main(int argc, char **argv) /* keepalives */ state->keepalive = (u_int32_t)atoi(optarg) * 1000; break; + case 'K': + /* number of keepalive without a reply */ + state->keepalive_limit = (u_int32_t)atoi(optarg); + break; case 'm': /* read buffer size */ state->bufsz = (size_t)atoi(optarg); @@ -141,7 +145,7 @@ main(int argc, char **argv) if (state->bufsz < 3 || state->bufsz >= 0xffff) usage(state); - if (state->keepalive == 0) + if (state->keepalive == 0 || state->keepalive_limit < 1) usage(state); state->server = xmppipe_servername(jid); @@ -325,6 +329,9 @@ XMPPIPE_POLL: state->interval = 0; } + if (state->keepalive_fail > state->keepalive_limit) + errx(EXIT_FAILURE, "no response to keepalives"); + xmpp_run_once(state->ctx, state->poll); state->interval += state->poll; @@ -715,6 +722,15 @@ handle_message(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } + int +handle_ping_reply(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + xmppipe_state_t *state = userdata; + state->keepalive_fail = 0; + return 0; +} + void xmppipe_muc_join(xmppipe_state_t *state) { @@ -828,7 +844,7 @@ xmppipe_ping(xmppipe_state_t *state) iq = xmpp_stanza_new(state->ctx); xmpp_stanza_set_name(iq, "iq"); xmpp_stanza_set_type(iq, "get"); - xmpp_stanza_set_id(iq, "c2s1"); /* XXX set unique id */ + xmpp_stanza_set_id(iq, "c2s1"); xmpp_stanza_set_attribute(iq, "from", xmpp_conn_get_bound_jid(state->conn)); ping = xmpp_stanza_new(state->ctx); @@ -839,6 +855,9 @@ xmppipe_ping(xmppipe_state_t *state) xmpp_send(state->conn, iq); xmpp_stanza_release(iq); + + state->keepalive_fail++; + xmpp_id_handler_add(state->conn, handle_ping_reply, "c2s1", state); } static void @@ -861,6 +880,7 @@ usage(xmppipe_state_t *state) " -s exit when MUC is empty\n" " -k periodically send a keepalive\n" + " -K number of keepalive failures before exiting\n" " -m size of read buffer\n" " -P poll delay\n" " -v verbose\n", diff --git a/src/xmppipe.h b/src/xmppipe.h index 2170be2..ea551b0 100644 --- a/src/xmppipe.h +++ b/src/xmppipe.h @@ -65,7 +65,9 @@ typedef struct { int occupants; u_int32_t poll; /* milliseconds */ u_int32_t keepalive; /* periodically send a keepalive (milliseconds) */ - u_int32_t interval; /* time since last keepalive (milliseconds) */ + u_int32_t keepalive_fail; /* number of consecutive keepalives without a reply */ + u_int32_t keepalive_limit; /* number of keepalives without a reply */ + u_int32_t interval; /* time since last keepalive (milliseconds) */ size_t bufsz; /* size of read buffer */ int opt;