diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 335c83d93..1d7407820 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -25,6 +25,7 @@ #include #include +#include #include "debug.h" @@ -103,6 +104,8 @@ struct mgcp_port_range { int last_port; }; +#define MGCP_KEEPALIVE_ONCE (-1) + struct mgcp_trunk_config { struct llist_head entry; @@ -118,6 +121,7 @@ struct mgcp_trunk_config { int audio_loop; int omit_rtcp; + int keepalive_interval; /* RTP patching */ int force_constant_ssrc; /* 0: don't, 1: once */ @@ -126,6 +130,9 @@ struct mgcp_trunk_config { /* spec handling */ int force_realloc; + /* timer */ + struct osmo_timer_list keepalive_timer; + unsigned int number_endpoints; struct mgcp_endpoint *endpoints; }; @@ -187,6 +194,8 @@ int mgcp_reset_transcoder(struct mgcp_config *cfg); void mgcp_format_stats(struct mgcp_endpoint *endp, char *stats, size_t size); int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter); +void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval); + /* * format helper functions */ diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index b55da37e9..9996ba7f6 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -877,6 +877,9 @@ mgcp_header_done: if (p->cfg->change_cb) p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX); + if (endp->bts_end.output_enabled && tcfg->keepalive_interval != 0) + mgcp_send_dummy(endp); + create_transcoder(endp); return create_response_with_sdp(endp, "CRCX", p->trans); error2: @@ -975,6 +978,10 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port)); if (p->cfg->change_cb) p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX); + + if (endp->bts_end.output_enabled && endp->tcfg->keepalive_interval != 0) + mgcp_send_dummy(endp); + if (silent) goto out_silent; @@ -1127,6 +1134,40 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p) create_err_response(p->endp, res, "RQNT", p->trans); } +static void mgcp_keepalive_timer_cb(void *_tcfg) +{ + struct mgcp_trunk_config *tcfg = _tcfg; + int i; + LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n", + tcfg->trunk_nr); + + if (tcfg->keepalive_interval <= 0) + return; + + for (i = 1; i < tcfg->number_endpoints; ++i) { + struct mgcp_endpoint *endp = &tcfg->endpoints[i]; + if (endp->conn_mode == MGCP_CONN_RECV_ONLY) + mgcp_send_dummy(endp); + } + + LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n", + tcfg->trunk_nr); + osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0); +} + +void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval) +{ + tcfg->keepalive_interval = interval; + tcfg->keepalive_timer.data = tcfg; + tcfg->keepalive_timer.cb = mgcp_keepalive_timer_cb; + + if (interval <= 0) + osmo_timer_del(&tcfg->keepalive_timer); + else + osmo_timer_schedule(&tcfg->keepalive_timer, + tcfg->keepalive_interval, 0); +} + struct mgcp_config *mgcp_config_alloc(void) { struct mgcp_config *cfg; @@ -1153,6 +1194,7 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->trunk.audio_payload = 126; cfg->trunk.audio_send_ptime = 1; cfg->trunk.omit_rtcp = 0; + mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE); INIT_LLIST_HEAD(&cfg->trunks); @@ -1177,6 +1219,7 @@ struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr) trunk->audio_send_ptime = 1; trunk->number_endpoints = 33; trunk->omit_rtcp = 0; + mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE); llist_add_tail(&trunk->entry, &cfg->trunks); return trunk; } diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 3f1ebeb2c..408a0596a 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -32,6 +32,7 @@ #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n" #define RTP_PATCH_STR "Modify RTP packet header in both directions\n" +#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n" static struct mgcp_config *g_cfg = NULL; @@ -85,6 +86,14 @@ static int config_write_mgcp(struct vty *vty) g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE); vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE); + if (g_cfg->trunk.keepalive_interval == MGCP_KEEPALIVE_ONCE) + vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE); + else if (g_cfg->trunk.keepalive_interval) + vty_out(vty, " rtp keep-alive %d%s", + g_cfg->trunk.keepalive_interval, VTY_NEWLINE); + else + vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE); + if (g_cfg->trunk.omit_rtcp) vty_out(vty, " rtcp-omit%s", VTY_NEWLINE); else @@ -511,6 +520,39 @@ DEFUN(cfg_mgcp_no_patch_rtp, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_rtp_keepalive, + cfg_mgcp_rtp_keepalive_cmd, + "rtp keep-alive <1-120>", + RTP_STR RTP_KEEPALIVE_STR + "Keep alive interval in secs\n" + ) +{ + mgcp_trunk_set_keepalive(&g_cfg->trunk, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_rtp_keepalive_once, + cfg_mgcp_rtp_keepalive_once_cmd, + "rtp keep-alive once", + RTP_STR RTP_KEEPALIVE_STR + "Send dummy packet only once after CRCX/MDCX\n" + ) +{ + mgcp_trunk_set_keepalive(&g_cfg->trunk, MGCP_KEEPALIVE_ONCE); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_rtp_keepalive, + cfg_mgcp_no_rtp_keepalive_cmd, + "no rtp keep-alive", + NO_STR RTP_STR RTP_KEEPALIVE_STR + ) +{ + mgcp_trunk_set_keepalive(&g_cfg->trunk, 0); + return CMD_SUCCESS; +} + + #define CALL_AGENT_STR "Callagent information\n" DEFUN(cfg_mgcp_agent_addr, @@ -598,6 +640,15 @@ static int config_write_trunk(struct vty *vty) trunk->audio_name, VTY_NEWLINE); vty_out(vty, " %ssdp audio-payload send-ptime%s", trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE); + + if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE) + vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE); + else if (trunk->keepalive_interval) + vty_out(vty, " rtp keep-alive %d%s", + trunk->keepalive_interval, VTY_NEWLINE); + else + vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE); + vty_out(vty, " loop %d%s", trunk->audio_loop, VTY_NEWLINE); if (trunk->omit_rtcp) @@ -780,6 +831,40 @@ DEFUN(cfg_trunk_no_patch_rtp, return CMD_SUCCESS; } +DEFUN(cfg_trunk_rtp_keepalive, + cfg_trunk_rtp_keepalive_cmd, + "rtp keep-alive <1-120>", + RTP_STR RTP_KEEPALIVE_STR + "Keep-alive interval in secs\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + mgcp_trunk_set_keepalive(trunk, atoi(argv[0])); + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_rtp_keepalive_once, + cfg_trunk_rtp_keepalive_once_cmd, + "rtp keep-alive once", + RTP_STR RTP_KEEPALIVE_STR + "Send dummy packet only once after CRCX/MDCX\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE); + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_rtp_keepalive, + cfg_trunk_no_rtp_keepalive_cmd, + "no rtp keep-alive", + NO_STR RTP_STR RTP_KEEPALIVE_STR + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + mgcp_trunk_set_keepalive(trunk, 0); + return CMD_SUCCESS; +} DEFUN(loop_endp, loop_endp_cmd, @@ -999,6 +1084,9 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd); install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd); install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd_old); install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd); @@ -1024,6 +1112,9 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd); install_node(&trunk_node, config_write_trunk); vty_install_default(TRUNK_NODE); + install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd); + install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd); install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd); install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd); install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd_old); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 596ea8a49..14ec22143 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -137,15 +137,6 @@ static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg) return 0; } -static int mgcp_change_cb(struct mgcp_trunk_config *cfg, int endpoint, int state) -{ - if (state != MGCP_ENDP_MDCX) - return 0; - - mgcp_send_dummy(&cfg->endpoints[endpoint]); - return 0; -} - static int read_call_agent(struct osmo_fd *fd, unsigned int what) { struct sockaddr_in addr; @@ -233,7 +224,6 @@ int main(int argc, char **argv) /* set some callbacks */ cfg->reset_cb = mgcp_rsip_cb; - cfg->change_cb = mgcp_change_cb; /* we need to bind a socket */ if (rc == 0) { diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 6db72262c..7e8aa5c3b 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -16,6 +16,7 @@ Testing AUEP2 Testing MDCX1 Testing MDCX2 Testing CRCX +Dummy packets: 1 Detected packet duration: 40 Requested packetetization period: 20-20 Connection mode: 1, BTS output enabled, NET output disabled @@ -24,18 +25,22 @@ Packet duration not set Requested packetization period not set Connection mode not set Testing MDCX4 +Dummy packets: 1 Detected packet duration: 40 Requested packetetization period: 20-20 Connection mode: 3, BTS output enabled, NET output enabled Testing MDCX4_PT1 +Dummy packets: 1 Detected packet duration: 40 Requested packetetization period: 20-40 Connection mode: 3, BTS output enabled, NET output enabled Testing MDCX4_PT2 +Dummy packets: 1 Detected packet duration: 40 Requested packetetization period: 20-20 Connection mode: 3, BTS output enabled, NET output enabled Testing MDCX4_PT3 +Dummy packets: 1 Detected packet duration: 40 Requested packetization period not set Connection mode: 3, BTS output enabled, NET output enabled @@ -48,6 +53,7 @@ Detected packet duration: 20 Requested packetization period not set Connection mode: 0, BTS output enabled, NET output enabled Testing CRCX_ZYN +Dummy packets: 1 Packet duration not set Requested packetization period not set Connection mode: 1, BTS output enabled, NET output disabled