Browse Source

TT#72000 add different endpoint detection algorithms

Change-Id: I791dba23450cab31bc5744a6156965afbb8a3b5c
changes/99/35899/4
Richard Fuchs 6 years ago
parent
commit
61ac7e9656
5 changed files with 80 additions and 3 deletions
  1. +18
    -0
      daemon/main.c
  2. +36
    -3
      daemon/media_socket.c
  3. +16
    -0
      daemon/rtpengine.pod
  4. +1
    -0
      include/call.h
  5. +9
    -0
      include/main.h

+ 18
- 0
daemon/main.c View File

@ -308,6 +308,7 @@ static void options(int *argc, char ***argv) {
double max_load = 0; double max_load = 0;
double max_cpu = 0; double max_cpu = 0;
char *dtmf_udp_ep = NULL; char *dtmf_udp_ep = NULL;
char *endpoint_learning = NULL;
GOptionEntry e[] = { GOptionEntry e[] = {
{ "table", 't', 0, G_OPTION_ARG_INT, &rtpe_config.kernel_table, "Kernel table to use", "INT" }, { "table", 't', 0, G_OPTION_ARG_INT, &rtpe_config.kernel_table, "Kernel table to use", "INT" },
@ -374,6 +375,7 @@ static void options(int *argc, char ***argv) {
{ "mysql-user", 0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_user,"MySQL connection credentials", "USERNAME" }, { "mysql-user", 0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_user,"MySQL connection credentials", "USERNAME" },
{ "mysql-pass", 0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_pass,"MySQL connection credentials", "PASSWORD" }, { "mysql-pass", 0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_pass,"MySQL connection credentials", "PASSWORD" },
{ "mysql-query",0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_query,"MySQL select query", "STRING" }, { "mysql-query",0, 0, G_OPTION_ARG_STRING, &rtpe_config.mysql_query,"MySQL select query", "STRING" },
{ "endpoint-learning",0,0,G_OPTION_ARG_STRING, &endpoint_learning, "RTP endpoint learning algorithm", "delayed|immediate|off|heuristic" },
{ NULL, } { NULL, }
}; };
@ -547,6 +549,21 @@ static void options(int *argc, char ***argv) {
die("Too many '%%' placeholders (%u) present in --mysql-query='%s'", die("Too many '%%' placeholders (%u) present in --mysql-query='%s'",
count, rtpe_config.mysql_query); count, rtpe_config.mysql_query);
} }
enum endpoint_learning el_config = EL_DELAYED;
if (endpoint_learning) {
if (!strcasecmp(endpoint_learning, "delayed"))
el_config = EL_DELAYED;
else if (!strcasecmp(endpoint_learning, "immediate"))
el_config = EL_IMMEDIATE;
else if (!strcasecmp(endpoint_learning, "off"))
el_config = EL_OFF;
else if (!strcasecmp(endpoint_learning, "heuristic"))
el_config = EL_HEURISTIC;
else
die("Invalid --endpoint-learning option ('%s')", endpoint_learning);
}
rtpe_config.endpoint_learning = el_config;
} }
void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) {
@ -608,6 +625,7 @@ void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) {
ini_rtpe_cfg->redis_ep = rtpe_config.redis_ep; ini_rtpe_cfg->redis_ep = rtpe_config.redis_ep;
ini_rtpe_cfg->redis_write_ep = rtpe_config.redis_write_ep; ini_rtpe_cfg->redis_write_ep = rtpe_config.redis_write_ep;
ini_rtpe_cfg->homer_ep = rtpe_config.homer_ep; ini_rtpe_cfg->homer_ep = rtpe_config.homer_ep;
ini_rtpe_cfg->endpoint_learning = rtpe_config.endpoint_learning;
ini_rtpe_cfg->b2b_url = g_strdup(rtpe_config.b2b_url); ini_rtpe_cfg->b2b_url = g_strdup(rtpe_config.b2b_url);
ini_rtpe_cfg->redis_auth = g_strdup(rtpe_config.redis_auth); ini_rtpe_cfg->redis_auth = g_strdup(rtpe_config.redis_auth);


+ 36
- 3
daemon/media_socket.c View File

@ -1532,7 +1532,7 @@ static int media_packet_address_check(struct packet_handler_ctx *phc)
} }
/* do not pay attention to source addresses of incoming packets for asymmetric streams */ /* do not pay attention to source addresses of incoming packets for asymmetric streams */
if (MEDIA_ISSET(phc->mp.media, ASYMMETRIC))
if (MEDIA_ISSET(phc->mp.media, ASYMMETRIC) || rtpe_config.endpoint_learning == EL_OFF)
PS_SET(phc->mp.stream, CONFIRMED); PS_SET(phc->mp.stream, CONFIRMED);
/* confirm sink for unidirectional streams in order to kernelize */ /* confirm sink for unidirectional streams in order to kernelize */
@ -1574,22 +1574,55 @@ static int media_packet_address_check(struct packet_handler_ctx *phc)
goto out; goto out;
} }
const struct endpoint *use_endpoint_confirm = &phc->mp.fsin;
if (rtpe_config.endpoint_learning == EL_IMMEDIATE)
goto confirm_now;
if (rtpe_config.endpoint_learning == EL_HEURISTIC
&& phc->mp.stream->advertised_endpoint.address.family
&& phc->mp.stream->advertised_endpoint.port)
{
// possible endpoints that can be detected in order of preference:
// 0: endpoint that matches the address advertised in the SDP
// 1: endpoint with the same address but different port
// 2: endpoint with the same port but different address
// 3: endpoint with both different port and different address
unsigned int idx = 0;
if (phc->mp.fsin.port != phc->mp.stream->advertised_endpoint.port)
idx |= 1;
if (memcmp(&phc->mp.fsin.address, &phc->mp.stream->advertised_endpoint.address,
sizeof(sockaddr_t)))
idx |= 2;
// fill appropriate slot
phc->mp.stream->detected_endpoints[idx] = phc->mp.fsin;
// now grab the best matched endpoint
for (idx = 0; idx < 4; idx++) {
use_endpoint_confirm = &phc->mp.stream->detected_endpoints[idx];
if (use_endpoint_confirm->address.family)
break;
}
}
/* wait at least 3 seconds after last signal before committing to a particular /* wait at least 3 seconds after last signal before committing to a particular
* endpoint address */ * endpoint address */
if (!phc->mp.call->last_signal || rtpe_now.tv_sec <= phc->mp.call->last_signal + 3) if (!phc->mp.call->last_signal || rtpe_now.tv_sec <= phc->mp.call->last_signal + 3)
goto update_peerinfo; goto update_peerinfo;
confirm_now:
phc->kernelize = 1; phc->kernelize = 1;
phc->update = 1; phc->update = 1;
ilog(LOG_INFO, "Confirmed peer address as %s%s%s", FMT_M(endpoint_print_buf(&phc->mp.fsin)));
ilog(LOG_INFO, "Confirmed peer address as %s%s%s", FMT_M(endpoint_print_buf(use_endpoint_confirm)));
PS_SET(phc->mp.stream, CONFIRMED); PS_SET(phc->mp.stream, CONFIRMED);
update_peerinfo: update_peerinfo:
mutex_lock(&phc->mp.stream->out_lock); mutex_lock(&phc->mp.stream->out_lock);
endpoint = phc->mp.stream->endpoint; endpoint = phc->mp.stream->endpoint;
phc->mp.stream->endpoint = phc->mp.fsin;
phc->mp.stream->endpoint = *use_endpoint_confirm;
if (memcmp(&endpoint, &phc->mp.stream->endpoint, sizeof(endpoint))) { if (memcmp(&endpoint, &phc->mp.stream->endpoint, sizeof(endpoint))) {
phc->unkernelize = 1; phc->unkernelize = 1;
phc->update = 1; phc->update = 1;


+ 16
- 0
daemon/rtpengine.pod View File

@ -655,6 +655,22 @@ An example configuration might look like this:
mysql-query = select data from voip.files where id = %llu mysql-query = select data from voip.files where id = %llu
=item B<--endpoint-learning=>B<delayed>|B<immediate>|B<off>|B<heuristic>
Chooses one of the available algorithms to learn RTP endpoint addresses. The
legacy setting is B<delayed> which waits 3 seconds before committing to an
endpoint address, which is then learned from the first incoming RTP packet seen
after this delay. The setting B<immediate> learns the endpoint address from the
first incoming packet seen without the 3-second delay. Using B<off> disables
endpoint learning altogether, likely breaking clients behind NAT. The setting
B<heuristic> includes the 3-second delay, but source addresses seen from
incoming RTP packets are ranked according to preference: If a packet with a
source address and port matching the SDP address is seen, this address is used.
Otherwise, if a packet with a matching source address (but a different port) is
seen, that address is used. Otherwise, if a packet with a matching source port
(but different address) is seen, that address is used. Otherwise, the source
address of any incoming packet seen is used.
=back =back
=head1 INTERFACES =head1 INTERFACES


+ 1
- 0
include/call.h View File

@ -260,6 +260,7 @@ struct packet_stream {
struct packet_stream *rtcp_sibling; /* LOCK: call->master_lock */ struct packet_stream *rtcp_sibling; /* LOCK: call->master_lock */
const struct streamhandler *handler; /* LOCK: in_lock */ const struct streamhandler *handler; /* LOCK: in_lock */
struct endpoint endpoint; /* LOCK: out_lock */ struct endpoint endpoint; /* LOCK: out_lock */
struct endpoint detected_endpoints[4]; /* LOCK: out_lock */
struct endpoint advertised_endpoint; /* RO */ struct endpoint advertised_endpoint; /* RO */
struct crypto_context crypto; /* OUT direction, LOCK: out_lock */ struct crypto_context crypto; /* OUT direction, LOCK: out_lock */
struct ssrc_ctx *ssrc_in, /* LOCK: in_lock */ // XXX eliminate these struct ssrc_ctx *ssrc_in, /* LOCK: in_lock */ // XXX eliminate these


+ 9
- 0
include/main.h View File

@ -18,6 +18,14 @@ enum log_format {
__LF_LAST __LF_LAST
}; };
enum endpoint_learning {
EL_DELAYED = 0,
EL_IMMEDIATE = 1,
EL_OFF = 2,
EL_HEURISTIC = 3,
__EL_LAST
};
struct rtpengine_config { struct rtpengine_config {
/* everything below protected by config_lock */ /* everything below protected by config_lock */
@ -84,6 +92,7 @@ struct rtpengine_config {
char *mysql_pass; char *mysql_pass;
char *mysql_query; char *mysql_query;
endpoint_t dtmf_udp_ep; endpoint_t dtmf_udp_ep;
enum endpoint_learning endpoint_learning;
}; };


Loading…
Cancel
Save