From 03b463034885e7ebb09160f6d63c05ac120a8098 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 19 Dec 2014 19:18:54 +0100 Subject: [PATCH] gprs: Send PING and eventually reconnect Currently, the reconnect mechanism relies on gsup_client_updown_cb which in turn gets called based on the OS' view of connection state. This patch adds a timer based PING mechanism that regularly sends PING messages and forces a reconnect if a PONG message won't be received until the next PING message is scheduled. The current ping interval is 20s. Sponsored-by: On-Waves ehf Conflicts: openbsc/src/gprs/gprs_gsup_client.c [hfreyther: Conflicts due the potential memleak fix by me. Removed another TODO from the code as we stop the ping/pong timer] --- openbsc/include/openbsc/gprs_gsup_client.h | 3 ++ openbsc/src/gprs/gprs_gsup_client.c | 61 ++++++++++++++++++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gprs_gsup_client.h b/openbsc/include/openbsc/gprs_gsup_client.h index 1165c4a78..9537db4c7 100644 --- a/openbsc/include/openbsc/gprs_gsup_client.h +++ b/openbsc/include/openbsc/gprs_gsup_client.h @@ -24,6 +24,7 @@ #include #define GPRS_GSUP_RECONNECT_INTERVAL 10 +#define GPRS_GSUP_PING_INTERVAL 20 struct msgb; struct ipa_client_conn; @@ -37,8 +38,10 @@ struct gprs_gsup_client { gprs_gsup_read_cb_t read_cb; void *data; + struct osmo_timer_list ping_timer; struct osmo_timer_list connect_timer; int is_connected; + int got_ipa_pong; }; struct gprs_gsup_client *gprs_gsup_client_create(const char *ip_addr, diff --git a/openbsc/src/gprs/gprs_gsup_client.c b/openbsc/src/gprs/gprs_gsup_client.c index 986542953..523c541b7 100644 --- a/openbsc/src/gprs/gprs_gsup_client.c +++ b/openbsc/src/gprs/gprs_gsup_client.c @@ -33,6 +33,18 @@ extern void *tall_bsc_ctx; +static void start_test_procedure(struct gprs_gsup_client *gsupc); + +static void gsup_client_send_ping(struct gprs_gsup_client *gsupc) +{ + struct msgb *msg = gprs_gsup_msgb_alloc(); + + msg->l2h = msgb_put(msg, 1); + msg->l2h[0] = IPAC_MSGT_PING; + ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS); + ipa_client_conn_send(gsupc->link, msg); +} + static int gsup_client_connect(struct gprs_gsup_client *gsupc) { int rc; @@ -46,6 +58,12 @@ static int gsup_client_connect(struct gprs_gsup_client *gsupc) osmo_timer_del(&gsupc->connect_timer); } + if (osmo_timer_pending(&gsupc->ping_timer)) { + LOGP(DLINP, LOGL_DEBUG, + "GSUP connect: ping timer already running\n"); + osmo_timer_del(&gsupc->ping_timer); + } + if (ipa_client_conn_clear_queue(gsupc->link) > 0) LOGP(DLINP, LOGL_DEBUG, "GSUP connect: discarded stored messages\n"); @@ -83,17 +101,17 @@ static void gsup_client_updown_cb(struct ipa_client_conn *link, int up) { struct gprs_gsup_client *gsupc = link->data; - LOGP(DGPRS, LOGL_NOTICE, "GSUP link to %s:%d %s\n", + LOGP(DGPRS, LOGL_INFO, "GSUP link to %s:%d %s\n", link->addr, link->port, up ? "UP" : "DOWN"); gsupc->is_connected = up; if (up) { - /* TODO: Start ping procedure */ + start_test_procedure(gsupc); osmo_timer_del(&gsupc->connect_timer); } else { - /* TODO: Stop ping procedure */ + osmo_timer_del(&gsupc->ping_timer); osmo_timer_schedule(&gsupc->connect_timer, GPRS_GSUP_RECONNECT_INTERVAL, 0); @@ -125,7 +143,12 @@ static int gsup_client_read_cb(struct ipa_client_conn *link, struct msgb *msg) } if (rc == 1) { + uint8_t msg_type = *(msg->l2h); /* CCM message */ + if (msg_type == IPAC_MSGT_PONG) { + LOGP(DGPRS, LOGL_DEBUG, "GSUP receiving PONG\n"); + gsupc->got_ipa_pong = 1; + } msgb_free(msg); return 0; @@ -155,6 +178,37 @@ invalid: return -1; } +static void ping_timer_cb(void *gsupc_) +{ + struct gprs_gsup_client *gsupc = gsupc_; + + LOGP(DGPRS, LOGL_INFO, "GSUP ping callback (%s, %s PONG)\n", + gsupc->is_connected ? "connected" : "not connected", + gsupc->got_ipa_pong ? "got" : "didn't get"); + + if (gsupc->got_ipa_pong) { + start_test_procedure(gsupc); + return; + } + + LOGP(DGPRS, LOGL_NOTICE, "GSUP ping timed out, reconnecting\n"); + ipa_client_conn_close(gsupc->link); + gsupc->is_connected = 0; + + gsup_client_connect(gsupc); +} + +static void start_test_procedure(struct gprs_gsup_client *gsupc) +{ + gsupc->ping_timer.data = gsupc; + gsupc->ping_timer.cb = &ping_timer_cb; + + gsupc->got_ipa_pong = 0; + osmo_timer_schedule(&gsupc->ping_timer, GPRS_GSUP_PING_INTERVAL, 0); + LOGP(DGPRS, LOGL_DEBUG, "GSUP sending PING\n"); + gsup_client_send_ping(gsupc); +} + struct gprs_gsup_client *gprs_gsup_client_create(const char *ip_addr, unsigned int tcp_port, gprs_gsup_read_cb_t read_cb) @@ -196,6 +250,7 @@ failed: void gprs_gsup_client_destroy(struct gprs_gsup_client *gsupc) { osmo_timer_del(&gsupc->connect_timer); + osmo_timer_del(&gsupc->ping_timer); if (gsupc->link) { ipa_client_conn_close(gsupc->link);