mirror of
https://gerrit.osmocom.org/osmo-gbproxy
synced 2024-08-21 10:26:25 +00:00
Merge branch 'jerlbeck/features/mgcp-rtp-keep-alive'
This commit is contained in:
commit
f50c5dfc64
9 changed files with 312 additions and 55 deletions
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
return mgcp_udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
|
||||
endp->net_end.rtp_port, buf, 1);
|
||||
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.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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue