aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Smith <osmith@sysmocom.de>2019-01-22 16:31:36 +0100
committerOliver Smith <osmith@sysmocom.de>2019-01-31 16:37:01 +0100
commitc9e298464304c297c0a296f1824bfbfb06721cea (patch)
tree53a45e46c68cc8da2485a07b8e5635ceea767f03
parent622dd61764a454bc19a54de5ee1097bc3d3fa5d7 (diff)
Inactive connection cleanup (disabled by default)osmith/kill-inactive-connections
Add a watchdog timer to connections, and close these connections when the watchdog timer expires. Kick the watchdog whenever RTP messages or the relevant MGCP messages arrive. This feature is disabled by default, as it is incompatible with LCLS (connections in LCLS state appear to be inactive). Enable it with the new "conn-timeout" VTY setting. In general, this feature can be used to work around interoperability problems causing connections to stay open forever, and slowly exhausting all available ports. This happened for various reasons already. MDCX is the only relevant MGCP message: - CRCX creates the conn and timer - DLCX deletes the conn and timer - MDCX is the only remaining supported MGCP message that indicates a CI - Can't easily generically parse a CI for all MGCP messages, parsing is done in handle_modify_con(). Related: OS#3429 Change-Id: I18886052e090466f73829133c24f011806cc1fe0
-rw-r--r--include/osmocom/mgcp/mgcp.h3
-rw-r--r--include/osmocom/mgcp/mgcp_internal.h4
-rw-r--r--src/libosmo-mgcp/mgcp_conn.c22
-rw-r--r--src/libosmo-mgcp/mgcp_network.c2
-rw-r--r--src/libosmo-mgcp/mgcp_protocol.c2
-rw-r--r--src/libosmo-mgcp/mgcp_vty.c17
-rw-r--r--tests/mgcp/mgcp_test.c4
7 files changed, 54 insertions, 0 deletions
diff --git a/include/osmocom/mgcp/mgcp.h b/include/osmocom/mgcp/mgcp.h
index 034a7809b..55f40751f 100644
--- a/include/osmocom/mgcp/mgcp.h
+++ b/include/osmocom/mgcp/mgcp.h
@@ -274,6 +274,9 @@ struct mgcp_config {
uint16_t osmux_dummy;
/* domain name of the media gateway */
char domain[255+1];
+
+ /* time after which inactive connections (CIs) get closed */
+ unsigned int conn_timeout;
};
/* config management */
diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h
index f75ae8b04..14c5f1128 100644
--- a/include/osmocom/mgcp/mgcp_internal.h
+++ b/include/osmocom/mgcp/mgcp_internal.h
@@ -231,6 +231,9 @@ struct mgcp_conn {
/*! human readable name (vty, logging) */
char name[256];
+ /*! activity tracker (for cleaning up inactive connections) */
+ struct osmo_timer_list watchdog;
+
/*! union with connection description */
union {
struct mgcp_conn_rtp rtp;
@@ -328,3 +331,4 @@ enum {
#define PTYPE_UNDEFINED (-1)
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
+void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index fce8a789b..ed027d144 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -29,6 +29,7 @@
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/timer.h>
#include <ctype.h>
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
@@ -125,6 +126,23 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
rate_ctr_group_free(conn_rtp->rate_ctr_group);
}
+void mgcp_conn_watchdog_cb(void *data)
+{
+ struct mgcp_conn *conn = data;
+ LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x CI:%s connection timed out!\n", ENDPOINT_NUMBER(conn->endp), conn->id);
+ mgcp_conn_free(conn->endp, conn->id);
+}
+
+void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
+{
+ unsigned long int timeout = conn->endp->cfg->conn_timeout;
+ if (!timeout)
+ return;
+
+ LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x CI:%s watchdog kicked\n", ENDPOINT_NUMBER(conn->endp), conn->id);
+ osmo_timer_schedule(&conn->watchdog, timeout, 0);
+}
+
/*! allocate a new connection list entry.
* \param[in] ctx talloc context
* \param[in] endp associated endpoint
@@ -167,6 +185,9 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
OSMO_ASSERT(false);
}
+ /* Initialize watchdog */
+ osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
+ mgcp_conn_watchdog_kick(conn);
llist_add(&conn->entry, &endp->conns);
return conn;
@@ -274,6 +295,7 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
OSMO_ASSERT(false);
}
+ osmo_timer_del(&conn->watchdog);
llist_del(&conn->entry);
talloc_free(conn);
}
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index 7af8e71f2..2c86f8fbd 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -1246,6 +1246,8 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
if (len < 0)
return -1;
+ mgcp_conn_watchdog_kick(conn_src->conn);
+
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index f1414858c..9f95ea49e 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -1141,6 +1141,8 @@ mgcp_header_done:
return create_err_response(endp, 400, "MDCX", p->trans);
}
+ mgcp_conn_watchdog_kick(conn->conn);
+
if (mode) {
if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_MODE]);
diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c
index 83f845a15..c68591309 100644
--- a/src/libosmo-mgcp/mgcp_vty.c
+++ b/src/libosmo-mgcp/mgcp_vty.c
@@ -154,6 +154,10 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " osmux dummy %s%s",
g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
}
+
+ if (g_cfg->conn_timeout)
+ vty_out(vty, " conn-timeout %u%s", g_cfg->conn_timeout, VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -1327,6 +1331,18 @@ DEFUN(cfg_mgcp_domain,
return CMD_SUCCESS;
}
+DEFUN(cfg_mgcp_conn_timeout,
+ cfg_mgcp_conn_timeout_cmd,
+ "conn-timeout <1-65534>",
+ "Set a time after which inactive connections (CIs) are closed. This can be used to work around interoperability"
+ " problems causing connections to stay open forever, and slowly exhausting all available ports. Do not enable"
+ " when LCLS is used (connections in LCLS state appear to be inactive)!\n"
+ "Timeout value (sec.)\n")
+{
+ g_cfg->conn_timeout = strtoul(argv[0], NULL, 16);
+ return CMD_SUCCESS;
+}
+
int mgcp_vty_init(void)
{
install_element_ve(&show_mgcp_cmd);
@@ -1391,6 +1407,7 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_conn_timeout_cmd);
install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
install_node(&trunk_node, config_write_trunk);
diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c
index a5400560e..78ddcdce3 100644
--- a/tests/mgcp/mgcp_test.c
+++ b/tests/mgcp/mgcp_test.c
@@ -970,6 +970,7 @@ static void test_packet_loss_calc(void)
{
int i;
struct mgcp_endpoint endp;
+ struct mgcp_config cfg = {0};
struct mgcp_trunk_config trunk;
printf("Testing packet loss calculation.\n");
@@ -977,6 +978,7 @@ static void test_packet_loss_calc(void)
memset(&endp, 0, sizeof(endp));
memset(&trunk, 0, sizeof(trunk));
+ endp.cfg = &cfg;
endp.type = &ep_typeset.rtp;
trunk.vty_number_endpoints = 1;
trunk.endpoints = &endp;
@@ -1197,6 +1199,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
struct mgcp_trunk_config trunk;
struct mgcp_endpoint endp;
+ struct mgcp_config cfg = {0};
struct mgcp_rtp_state state;
struct mgcp_rtp_end *rtp;
struct sockaddr_in addr = { 0 };
@@ -1224,6 +1227,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
state.in_stream.err_ts_ctr = &test_ctr_in;
state.out_stream.err_ts_ctr = &test_ctr_out;
+ endp.cfg = &cfg;
endp.type = &ep_typeset.rtp;
trunk.vty_number_endpoints = 1;