diff options
-rw-r--r-- | openbsc/include/openbsc/mgcp.h | 9 | ||||
-rw-r--r-- | openbsc/include/openbsc/mgcp_internal.h | 2 | ||||
-rw-r--r-- | openbsc/src/libmgcp/mgcp_network.c | 71 | ||||
-rw-r--r-- | openbsc/src/libmgcp/mgcp_protocol.c | 82 | ||||
-rw-r--r-- | openbsc/src/libmgcp/mgcp_vty.c | 99 | ||||
-rw-r--r-- | openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 10 | ||||
-rw-r--r-- | openbsc/tests/mgcp/Makefile.am | 3 | ||||
-rw-r--r-- | openbsc/tests/mgcp/mgcp_test.c | 72 | ||||
-rw-r--r-- | openbsc/tests/mgcp/mgcp_test.ok | 19 |
9 files changed, 312 insertions, 55 deletions
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 <osmocom/core/msgb.h> #include <osmocom/core/write_queue.h> +#include <osmocom/core/timer.h> #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/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index a9ae33c73..b4899e408 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -71,6 +71,7 @@ struct mgcp_rtp_end { /* statistics */ unsigned int packets; unsigned int octets; + unsigned int dropped_packets; struct in_addr addr; /* in network byte order */ @@ -84,6 +85,7 @@ struct mgcp_rtp_end { int frames_per_packet; uint32_t packet_duration_ms; char *fmtp_extra; + int output_enabled; /* RTP patching */ int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 657019e15..0cc20416b 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -129,9 +129,16 @@ static int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int mgcp_send_dummy(struct mgcp_endpoint *endp) { static char buf[] = { MGCP_DUMMY_LOAD }; + int rc; + + rc = mgcp_udp_send(endp->net_end.rtp.fd, &endp->net_end.addr, + endp->net_end.rtp_port, buf, 1); + + if (rc == -1 || endp->tcfg->omit_rtcp) + return rc; - return mgcp_udp_send(endp->net_end.rtp.fd, &endp->net_end.addr, - endp->net_end.rtp_port, buf, 1); + return mgcp_udp_send(endp->net_end.rtcp.fd, &endp->net_end.addr, + endp->net_end.rtcp_port, buf, 1); } static int32_t compute_timestamp_aligment_error(struct mgcp_rtp_stream_state *sstate, @@ -241,10 +248,11 @@ static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state, struct mgcp_rtp_end *rtp_end, struct sockaddr_in *addr, - int16_t delta_seq, uint32_t timestamp) + int16_t delta_seq, uint32_t in_timestamp) { int32_t tsdelta = state->packet_duration; int timestamp_offset; + uint32_t out_timestamp; if (tsdelta == 0) { tsdelta = state->out_stream.last_tsdelta; @@ -269,9 +277,8 @@ static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp, } } - timestamp_offset = - state->out_stream.last_timestamp - timestamp + - delta_seq * tsdelta; + out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta; + timestamp_offset = out_timestamp - in_timestamp; if (state->timestamp_offset != timestamp_offset) { state->timestamp_offset = timestamp_offset; @@ -537,6 +544,10 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct sockaddr_in *addr, char *buf, int rc) { struct mgcp_trunk_config *tcfg = endp->tcfg; + struct mgcp_rtp_end *rtp_end; + struct mgcp_rtp_state *rtp_state; + int tap_idx; + /* For loop toggle the destination and then dispatch. */ if (tcfg->audio_loop) dest = !dest; @@ -546,35 +557,27 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, dest = !dest; if (dest == MGCP_DEST_NET) { - if (is_rtp) { - mgcp_patch_and_count(endp, &endp->bts_state, - &endp->net_end, - addr, buf, rc); - forward_data(endp->net_end.rtp.fd, - &endp->taps[MGCP_TAP_NET_OUT], buf, rc); - return mgcp_udp_send(endp->net_end.rtp.fd, - &endp->net_end.addr, - endp->net_end.rtp_port, buf, rc); - } else if (!tcfg->omit_rtcp) { - return mgcp_udp_send(endp->net_end.rtcp.fd, - &endp->net_end.addr, - endp->net_end.rtcp_port, buf, rc); - } + rtp_end = &endp->net_end; + rtp_state = &endp->bts_state; + tap_idx = MGCP_TAP_NET_OUT; } else { - if (is_rtp) { - mgcp_patch_and_count(endp, &endp->net_state, - &endp->bts_end, - addr, buf, rc); - forward_data(endp->bts_end.rtp.fd, - &endp->taps[MGCP_TAP_BTS_OUT], buf, rc); - return mgcp_udp_send(endp->bts_end.rtp.fd, - &endp->bts_end.addr, - endp->bts_end.rtp_port, buf, rc); - } else if (!tcfg->omit_rtcp) { - return mgcp_udp_send(endp->bts_end.rtcp.fd, - &endp->bts_end.addr, - endp->bts_end.rtcp_port, buf, rc); - } + rtp_end = &endp->bts_end; + rtp_state = &endp->net_state; + tap_idx = MGCP_TAP_BTS_OUT; + } + + if (!rtp_end->output_enabled) + rtp_end->dropped_packets += 1; + else if (is_rtp) { + mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc); + forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc); + return mgcp_udp_send(rtp_end->rtp.fd, + &rtp_end->addr, + rtp_end->rtp_port, buf, rc); + } else if (!tcfg->omit_rtcp) { + return mgcp_udp_send(rtp_end->rtcp.fd, + &rtp_end->addr, + rtp_end->rtcp_port, buf, rc); } return 0; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index ddec44d92..9996ba7f6 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -488,22 +488,45 @@ static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p) return create_ok_response(p->endp, 200, "AUEP", p->trans); } -static int parse_conn_mode(const char *msg, int *conn_mode) +static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp) { int ret = 0; if (strcmp(msg, "recvonly") == 0) - *conn_mode = MGCP_CONN_RECV_ONLY; + endp->conn_mode = MGCP_CONN_RECV_ONLY; else if (strcmp(msg, "sendrecv") == 0) - *conn_mode = MGCP_CONN_RECV_SEND; + endp->conn_mode = MGCP_CONN_RECV_SEND; else if (strcmp(msg, "sendonly") == 0) - *conn_mode = MGCP_CONN_SEND_ONLY; + endp->conn_mode = MGCP_CONN_SEND_ONLY; else if (strcmp(msg, "loopback") == 0) - *conn_mode = MGCP_CONN_LOOPBACK; + endp->conn_mode = MGCP_CONN_LOOPBACK; else { LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg); ret = -1; } + switch (endp->conn_mode) { + case MGCP_CONN_NONE: + endp->net_end.output_enabled = 0; + endp->bts_end.output_enabled = 0; + break; + + case MGCP_CONN_RECV_ONLY: + endp->net_end.output_enabled = 0; + endp->bts_end.output_enabled = 1; + break; + + case MGCP_CONN_SEND_ONLY: + endp->net_end.output_enabled = 1; + endp->bts_end.output_enabled = 0; + break; + + default: + endp->net_end.output_enabled = 1; + endp->bts_end.output_enabled = 1; + break; + } + + return ret; } @@ -794,7 +817,7 @@ mgcp_header_done: set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); - if (parse_conn_mode(mode, &endp->conn_mode) != 0) { + if (parse_conn_mode(mode, endp) != 0) { error_code = 517; goto error2; } @@ -854,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: @@ -895,7 +921,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) local_options = (const char *) line + 3; break; case 'M': - if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) { + if (parse_conn_mode(line + 3, endp) != 0) { error_code = 517; goto error3; } @@ -952,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; @@ -1104,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; @@ -1130,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); @@ -1154,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; } @@ -1178,6 +1244,7 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->packets = 0; end->octets = 0; + end->dropped_packets = 0; memset(&end->addr, 0, sizeof(end->addr)); end->rtp_port = end->rtcp_port = 0; end->payload_type = -1; @@ -1191,6 +1258,7 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->frames_per_packet = 0; /* unknown */ end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + end->output_enabled = 1; } static void mgcp_rtp_end_init(struct mgcp_rtp_end *end) diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 8411b4aa4..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 @@ -150,7 +159,7 @@ static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int verbo endp->trans_net.packets, endp->trans_bts.packets, VTY_NEWLINE); - if (verbose) + if (verbose) { vty_out(vty, " Timestamp Errs: BTS %d->%d, Net %d->%d%s", endp->bts_state.in_stream.err_ts_counter, @@ -158,6 +167,12 @@ static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int verbo endp->net_state.in_stream.err_ts_counter, endp->net_state.out_stream.err_ts_counter, VTY_NEWLINE); + vty_out(vty, + " Dropped Packets: Net->BTS %d, BTS->Net %d%s", + endp->bts_end.dropped_packets, + endp->net_end.dropped_packets, + VTY_NEWLINE); + } } } @@ -505,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, @@ -592,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) @@ -774,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, @@ -993,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); @@ -1018,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/Makefile.am b/openbsc/tests/mgcp/Makefile.am index 8c365b416..470cdd80e 100644 --- a/openbsc/tests/mgcp/Makefile.am +++ b/openbsc/tests/mgcp/Makefile.am @@ -11,4 +11,5 @@ mgcp_test_SOURCES = mgcp_test.c mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libmgcp/libmgcp.a \ $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) -lrt $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) + $(LIBOSMOCORE_LIBS) -lrt $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ + $(LIBRARY_DL) diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 3cfc183e7..7eeef99af 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#undef _GNU_SOURCE +#define _GNU_SOURCE #include <openbsc/mgcp.h> #include <openbsc/mgcp_internal.h> @@ -24,6 +26,7 @@ #include <osmocom/core/talloc.h> #include <string.h> #include <limits.h> +#include <dlfcn.h> char *strline_r(char *str, char **saveptr); @@ -84,6 +87,7 @@ static void test_strline(void) "a=rtpmap:126 AMR/8000\r\n" \ "a=ptime:20\r\n" #define MDCX4 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \ + "M: sendrecv\r" \ "C: 2\r\n" \ "I: 1\r\n" \ "L: p:20, a:AMR, nt:IN\r\n" \ @@ -107,6 +111,7 @@ static void test_strline(void) "a=ptime:20\r\n" #define MDCX4_PT1 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \ + "M: sendrecv\r" \ "C: 2\r\n" \ "I: 1\r\n" \ "L: p:20-40, a:AMR, nt:IN\r\n" \ @@ -120,6 +125,7 @@ static void test_strline(void) "a=ptime:40\r\n" #define MDCX4_PT2 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \ + "M: sendrecv\r" \ "C: 2\r\n" \ "I: 1\r\n" \ "L: p:20-20, a:AMR, nt:IN\r\n" \ @@ -133,6 +139,7 @@ static void test_strline(void) "a=ptime:40\r\n" #define MDCX4_PT3 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \ + "M: sendrecv\r" \ "C: 2\r\n" \ "I: 1\r\n" \ "L: a:AMR, nt:IN\r\n" \ @@ -145,6 +152,20 @@ static void test_strline(void) "a=rtpmap:99 AMR/8000\r\n" \ "a=ptime:40\r\n" +#define MDCX4_SO "MDCX 18983220 1@mgw MGCP 1.0\r\n" \ + "M: sendonly\r" \ + "C: 2\r\n" \ + "I: 1\r\n" \ + "L: p:20, a:AMR, nt:IN\r\n" \ + "\n" \ + "v=0\r\n" \ + "o=- 1 23 IN IP4 0.0.0.0\r\n" \ + "c=IN IP4 0.0.0.0\r\n" \ + "t=0 0\r\n" \ + "m=audio 4441 RTP/AVP 99\r\n" \ + "a=rtpmap:99 AMR/8000\r\n" \ + "a=ptime:40\r\n" + #define SHORT2 "CRCX 1" #define SHORT2_RET "510 000000 FAIL\r\n" #define SHORT3 "CRCX 1 1@mgw" @@ -152,7 +173,7 @@ static void test_strline(void) #define SHORT5 "CRCX 1 1@mgw MGCP 1.0" #define CRCX "CRCX 2 1@mgw MGCP 1.0\r\n" \ - "M: sendrecv\r\n" \ + "M: recvonly\r\n" \ "C: 2\r\n" \ "L: p:20\r\n" \ "\r\n" \ @@ -174,7 +195,7 @@ static void test_strline(void) "a=ptime:20\r\n" #define CRCX_ZYN "CRCX 2 1@mgw MGCP 1.0\r" \ - "M: sendrecv\r" \ + "M: recvonly\r" \ "C: 2\r\r" \ "v=0\r" \ "c=IN IP4 123.12.12.123\r" \ @@ -233,6 +254,7 @@ static const struct mgcp_test tests[] = { { "MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99, 126 }, { "MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99, 126 }, { "MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99, 126 }, + { "MDCX4_SO", MDCX4_SO, MDCX4_RET("18983220"), 99, 126 }, { "DLCX", DLCX, DLCX_RET, -1, -1 }, { "CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97, 126 }, { "EMPTY", EMPTY, EMPTY_RET }, @@ -274,6 +296,31 @@ static int mgcp_test_policy_cb(struct mgcp_trunk_config *cfg, int endpoint, return MGCP_POLICY_CONT; } +#define MGCP_DUMMY_LOAD 0x23 +static int dummy_packets = 0; +/* override and forward */ +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + typedef ssize_t (*sendto_t)(int, const void *, size_t, int, + const struct sockaddr *, socklen_t); + static sendto_t real_sendto = NULL; + uint32_t dest_host = htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr); + int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port); + + if (!real_sendto) + real_sendto = dlsym(RTLD_NEXT, "sendto"); + + if (len == 1 && ((const char *)buf)[0] == MGCP_DUMMY_LOAD ) { + fprintf(stderr, "Dummy packet to 0x%08x:%d, msg length %d\n%s\n\n", + dest_host, dest_port, + len, osmo_hexdump(buf, len)); + dummy_packets += 1; + } + + return real_sendto(sockfd, buf, len, flags, dest_addr, addrlen); +} + static void test_messages(void) { struct mgcp_config *cfg; @@ -294,6 +341,9 @@ static void test_messages(void) endp = &cfg->trunk.endpoints[i]; endp->net_end.payload_type = PTYPE_NONE; endp->net_end.packet_duration_ms = -1; + endp->bts_end.output_enabled = 0; + endp->net_end.output_enabled = 0; + endp->conn_mode = -1; } for (i = 0; i < ARRAY_SIZE(tests); i++) { @@ -304,6 +354,7 @@ static void test_messages(void) printf("Testing %s\n", t->name); last_endpoint = -1; + dummy_packets = 0; inp = create_msg(t->req); msg = mgcp_handle_message(cfg, inp); @@ -315,6 +366,9 @@ static void test_messages(void) printf("%s failed '%s'\n", t->name, (char *) msg->data); msgb_free(msg); + if (dummy_packets) + printf("Dummy packets: %d\n", dummy_packets); + if (last_endpoint != -1) { endp = &cfg->trunk.endpoints[last_endpoint]; @@ -332,7 +386,21 @@ static void test_messages(void) else printf("Requested packetization period not set\n"); + if (endp->conn_mode != -1) + printf("Connection mode: %d, " + "BTS output %sabled, NET output %sabled\n", + endp->conn_mode, + endp->bts_end.output_enabled ? "en" : "dis", + endp->net_end.output_enabled ? "en" : "dis"); + else + printf("Connection mode not set\n"); + endp->net_end.packet_duration_ms = -1; + endp->bts_end.output_enabled = 0; + endp->net_end.output_enabled = 0; + endp->local_options.pkt_period_min = 0; + endp->local_options.pkt_period_max = 0; + endp->conn_mode = -1; } diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 638ac9215..7e8aa5c3b 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -16,29 +16,47 @@ 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 Testing MDCX3 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 +Testing MDCX4_SO +Detected packet duration: 40 +Requested packetetization period: 20-20 +Connection mode: 2, BTS output disabled, NET output enabled Testing DLCX 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 Testing EMPTY Testing SHORT1 Testing SHORT2 @@ -49,6 +67,7 @@ Testing RQNT2 Testing DLCX Detected packet duration: 20 Requested packetization period not set +Connection mode: 0, BTS output enabled, NET output enabled Testing CRCX Re-transmitting CRCX Testing RQNT1 |