From 45403b1804d2318aec2858c28ac4c623bfdcde2f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 3 May 2010 11:51:07 +0800 Subject: nat/bsc: Send PONG on PING, send PING from the BSC too We do want to send PING/PONG in both ways to have a heartbeat on the TCP connection. When switching over to SCTP we can rely on the builtin heartbeat functionality. --- openbsc/src/bsc_msc_ip.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++- openbsc/src/nat/bsc_nat.c | 23 +++++++++++++++----- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/openbsc/src/bsc_msc_ip.c b/openbsc/src/bsc_msc_ip.c index 858a15c54..f760ad627 100644 --- a/openbsc/src/bsc_msc_ip.c +++ b/openbsc/src/bsc_msc_ip.c @@ -60,13 +60,17 @@ static struct log_target *stderr_target; struct gsm_network *bsc_gsmnet = 0; static const char *config_file = "openbsc.cfg"; static char *msc_address = NULL; -static struct bsc_msc_connection *msc_con; static struct in_addr local_addr; static LLIST_HEAD(active_connections); static struct write_queue mgcp_agent; static const char *rf_ctl = NULL; extern int ipacc_rtp_direct; +/* msc handling */ +static struct bsc_msc_connection *msc_con; +static struct timer_list msc_ping_timeout; +static struct timer_list msc_pong_timeout; + extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file); extern int bsc_shutdown_net(struct gsm_network *net); @@ -867,10 +871,51 @@ static void msc_connection_was_lost(struct bsc_msc_connection *msc) bss_force_close(bss); } + bsc_del_timer(&msc_ping_timeout); + bsc_del_timer(&msc_pong_timeout); + msc->is_authenticated = 0; bsc_msc_schedule_connect(msc); } +static void msc_pong_timeout_cb(void *data) +{ + LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n"); + bsc_msc_lost(msc_con); +} + +static void send_ping(void) +{ + struct msgb *msg; + + msg = msgb_alloc_headroom(4096, 128, "ping"); + if (!msg) { + LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n"); + return; + } + + msg->l2h = msgb_put(msg, 1); + msg->l2h[0] = IPAC_MSGT_PING; + + msc_queue_write(msg, IPAC_PROTO_IPACCESS); +} + +static void msc_ping_timeout_cb(void *data) +{ + send_ping(); + + /* send another ping in 20 seconds */ + bsc_schedule_timer(&msc_ping_timeout, 20, 0); + + /* also start a pong timer */ + bsc_schedule_timer(&msc_pong_timeout, 5, 0); +} + +static void msc_connection_connected(struct bsc_msc_connection *con) +{ + msc_ping_timeout_cb(con); +} + /* * callback with IP access data */ @@ -903,6 +948,8 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd) initialize_if_needed(); else if (msg->l2h[0] == IPAC_MSGT_ID_GET) { send_id_get_response(bfd->fd); + } else if (msg->l2h[0] == IPAC_MSGT_PONG) { + bsc_del_timer(&msc_pong_timeout); } } else if (hh->proto == IPAC_PROTO_SCCP) { sccp_system_incoming(msg); @@ -1131,7 +1178,11 @@ int main(int argc, char **argv) exit(1); } + msc_ping_timeout.cb = msc_ping_timeout_cb; + msc_pong_timeout.cb = msc_pong_timeout_cb; + msc_con->connection_loss = msc_connection_was_lost; + msc_con->connected = msc_connection_connected; msc_con->write_queue.read_cb = ipaccess_a_fd_cb; msc_con->write_queue.write_cb = msc_sccp_do_write; bsc_msc_connect(msc_con); diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index ca018e0c6..a60efd07c 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -117,6 +117,15 @@ static void send_ping(struct bsc_connection *bsc) bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS); } +static void send_pong(struct bsc_connection *bsc) +{ + static const u_int8_t id_pong[] = { + IPAC_MSGT_PONG, + }; + + bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS); +} + static void bsc_pong_timeout(void *_bsc) { struct bsc_connection *bsc = _bsc; @@ -646,6 +655,7 @@ static int ipaccess_bsc_read_cb(struct bsc_fd *bfd) int error; struct bsc_connection *bsc = bfd->data; struct msgb *msg = ipaccess_read_msg(bfd, &error); + struct ipaccess_head *hh; if (!msg) { if (error == 0) @@ -665,15 +675,18 @@ static int ipaccess_bsc_read_cb(struct bsc_fd *bfd) LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]); /* Handle messages from the BSC */ - if (bsc->authenticated) { - struct ipaccess_head *hh; - hh = (struct ipaccess_head *) msg->data; + hh = (struct ipaccess_head *) msg->data; - /* stop the pong timeout */ - if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_PONG) { + /* stop the pong timeout */ + if (hh->proto == IPAC_PROTO_IPACCESS) { + if (msg->l2h[0] == IPAC_MSGT_PONG) { bsc_del_timer(&bsc->pong_timeout); msgb_free(msg); return 0; + } else if (msg->l2h[0] == IPAC_MSGT_PING) { + send_pong(bsc); + msgb_free(msg); + return 0; } } -- cgit v1.2.3