MT#55283 support from-tag aliases

Change-Id: Iffd87cc821e35d3d775a5bde1986c2d7dd0192ee
pull/2079/head
Richard Fuchs 4 months ago
parent 2ab345ccd5
commit 76d5e6d439

@ -5082,6 +5082,8 @@ static void __call_free(call_t *c) {
t_hash_table_destroy(c->tags);
t_hash_table_destroy(c->viabranches);
t_hash_table_destroy(c->labels);
t_hash_table_destroy(c->sdps);
t_hash_table_destroy(c->endpoints);
t_queue_clear(&c->callid_aliases);
while (c->streams.head) {
@ -5111,6 +5113,8 @@ static call_t *call_create(const str *callid) {
c->tags = str_ml_ht_new();
c->viabranches = str_ml_ht_new();
c->labels = str_ml_ht_new();
c->sdps = str_ml_ht_new();
c->endpoints = endpoint_ml_ht_new();
call_memory_arena_set(c);
c->callid = call_str_cpy(callid);
c->created = rtpe_now;
@ -5654,6 +5658,25 @@ struct call_monologue *call_get_monologue(call_t *call, const str *fromtag) {
return t_hash_table_lookup(call->tags, fromtag);
}
static struct call_monologue *call_get_monologue_alias(call_t *call, const str *fromtag,
sdp_ng_flags *flags, const str *sdp, const endpoint_t *ep)
{
__auto_type ret = t_hash_table_lookup(call->tags, fromtag);
if (ret)
return ret;
if (flags->alias_key == AK_SDP && sdp->len)
ret = t_hash_table_lookup(call->sdps, sdp);
else if (flags->alias_key == AK_ADDRESS && ep && ep->port)
ret = t_hash_table_lookup(call->endpoints, ep);
if (!ret)
return NULL;
__monologue_tag(ret, fromtag);
return ret;
}
/**
* Based on the monologue tag, try to lookup the monologue in the 'tags' GHashTable.
* If not found create a new one (call_monologue) and associate with a given tag.
@ -5715,14 +5738,14 @@ static int call_get_monologue_new(struct call_monologue *monologues[2], call_t *
const str *fromtag,
const str *totag,
const str *viabranch,
sdp_ng_flags *flags)
sdp_ng_flags *flags, const endpoint_t *ep)
{
struct call_monologue *ret, *os = NULL; /* ret - initial offer, os - other side */
__C_DBG("getting monologue for tag '"STR_FORMAT"' in call '"STR_FORMAT"'",
STR_FMT(fromtag), STR_FMT(&call->callid));
ret = call_get_monologue(call, fromtag);
ret = call_get_monologue_alias(call, fromtag, flags, &flags->sdp, ep);
if (!ret) {
/* this is a brand new offer */
ret = __monologue_create(call);
@ -5738,7 +5761,7 @@ static int call_get_monologue_new(struct call_monologue *monologues[2], call_t *
* Create a new monologue for the other side, if the monologue with such to-tag not found.
*/
if (totag && totag->s) {
struct call_monologue * monologue = call_get_monologue(call, totag);
struct call_monologue *monologue = call_get_monologue(call, totag);
if (!monologue)
goto new_branch;
}
@ -5807,7 +5830,7 @@ static int call_get_dialogue(struct call_monologue *monologues[2], call_t *call,
const str *fromtag,
const str *totag,
const str *viabranch,
sdp_ng_flags *flags)
sdp_ng_flags *flags, const endpoint_t *ep)
{
struct call_monologue *ft, *tt;
@ -5821,10 +5844,10 @@ static int call_get_dialogue(struct call_monologue *monologues[2], call_t *call,
/* we start with the to-tag. if it's not known, we treat it as a branched offer */
tt = call_get_monologue(call, totag);
if (!tt)
return call_get_monologue_new(monologues, call, fromtag, totag, viabranch, flags);
return call_get_monologue_new(monologues, call, fromtag, totag, viabranch, flags, ep);
/* if the from-tag is known already, return that */
ft = call_get_monologue(call, fromtag);
ft = call_get_monologue_alias(call, fromtag, flags, &flags->sdp, ep);
if (ft) {
__C_DBG("found existing dialogue");
@ -5915,13 +5938,13 @@ int call_get_mono_dialogue(struct call_monologue *monologues[2], call_t *call,
const str *fromtag,
const str *totag,
const str *viabranch,
sdp_ng_flags *flags)
sdp_ng_flags *flags, const endpoint_t *ep)
{
/* initial offer */
if (!totag || !totag->s)
return call_get_monologue_new(monologues, call, fromtag, NULL, viabranch, flags);
return call_get_monologue_new(monologues, call, fromtag, NULL, viabranch, flags, ep);
return call_get_dialogue(monologues, call, fromtag, totag, viabranch, flags);
return call_get_dialogue(monologues, call, fromtag, totag, viabranch, flags, ep);
}
static void media_stop(struct call_media *m) {

@ -192,7 +192,7 @@ static str call_update_lookup_udp(char **out, enum ng_opmode opmode, const char*
updated_created_from(c, addr);
if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL, NULL))
if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL, NULL, NULL))
goto ml_fail;
struct call_monologue *from_ml = monologues[0];
@ -355,7 +355,7 @@ static str call_request_lookup_tcp(char **out, enum ng_opmode opmode) {
str_swap(&fromtag, &totag);
}
if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL, NULL)) {
if (call_get_mono_dialogue(monologues, c, &fromtag, &totag, NULL, NULL, NULL)) {
ilog(LOG_WARNING, "Invalid dialogue association");
goto out2;
}
@ -1799,6 +1799,26 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
STR_FMT(&s));
}
break;
case CSH_LOOKUP("alias-key"):
switch (__csh_lookup_n(1, &s)) {
case CSH_LOOKUP_N(1, "none"):
case CSH_LOOKUP_N(1, "off"):
case CSH_LOOKUP_N(1, "no"):
out->alias_key = AK_NONE;
break;
case CSH_LOOKUP_N(1, "sdp"):
case CSH_LOOKUP_N(1, "SDP"):
out->alias_key = AK_SDP;
break;
case CSH_LOOKUP_N(1, "address"):
case CSH_LOOKUP_N(1, "endpoint"):
out->alias_key = AK_ADDRESS;
break;
default:
ilog(LOG_WARN, "Unknown 'alias-key' flag encountered: '" STR_FORMAT "'",
STR_FMT(&s));
}
break;
case CSH_LOOKUP("audio-player"):
case CSH_LOOKUP("player"):
switch (__csh_lookup_n(1, &s)) {
@ -2588,7 +2608,7 @@ static const char *call_offer_answer_ng(ng_command_ctx_t *ctx, const char* addr)
g_auto(sdp_sessions_q) parsed = TYPED_GQUEUE_INIT;
g_auto(sdp_streams_q) streams = TYPED_GQUEUE_INIT;
g_autoptr(call_t) call = NULL;
struct call_monologue * monologues[2];
struct call_monologue *monologues[2];
int ret;
g_auto(sdp_ng_flags) flags;
parser_arg output = ctx->resp;
@ -2659,7 +2679,8 @@ static const char *call_offer_answer_ng(ng_command_ctx_t *ctx, const char* addr)
errstr = "Invalid dialogue association";
if (call_get_mono_dialogue(monologues, call, &flags.from_tag, &flags.to_tag,
flags.via_branch.s ? &flags.via_branch : NULL, &flags)) {
flags.via_branch.s ? &flags.via_branch : NULL, &flags,
streams.length ? &streams.head->data->rtp_endpoint : NULL)) {
goto out;
}
@ -2680,7 +2701,13 @@ static const char *call_offer_answer_ng(ng_command_ctx_t *ctx, const char* addr)
}
if (flags.block_dtmf)
call_set_dtmf_block(call, monologues[0], &flags);
call_set_dtmf_block(call, from_ml, &flags);
if (flags.alias_key == AK_SDP)
t_hash_table_insert(call->sdps, call_str_dup(&sdp), from_ml);
else if (flags.alias_key == AK_ADDRESS && streams.length && streams.head->data->rtp_endpoint.port)
t_hash_table_insert(call->endpoints, memory_arena_objdup(streams.head->data->rtp_endpoint),
from_ml);
struct recording *recording = NULL;

@ -168,6 +168,28 @@ Optionally included keys are:
body. The default is to auto-detect the address family if possible (if the receiving end is known
already) or otherwise to leave it unchanged.
* `alias key`
Contains a string value to control the creation of from-tag aliases. The
default is to disable from-tag aliases, which corresponds to the string
value `off`. Any other value enables the creation of from-tag aliases.
A from-tag alias is created when an offer from an unknown from-tag is
received, and the criteria selected through the `alias key` value is
matched against an existing, known from-tag. If a match is found, the newly
appeared from-tag will be remembered as an alias for the existing from-tag
going forward. Note that the same `alias key` value must have been used
when the offer for the existing from-tag was received for this to work.
With the value `SDP`, matching is performed on the entire SDP body as
received in the offer. In other words, if an offer from an unknown from-tag
is received and the identical SDP was previously used in another offer with
a different from-tag, then these two from-tags will be considered aliases.
With the value `address` or `endpoint`, matching is performed on the
address/port pair used as connection address in the SDP, specifically the
address and port used by the first media section.
* `audio player`
Contains a string value of either `default`, `transcoding`, `off`, or `always`.

@ -23,6 +23,14 @@ INLINE void *__memory_arena_alloc0(size_t len) {
return ret;
}
#define memory_arena_alloc0(type) ((type *) __memory_arena_alloc0(sizeof(type)))
INLINE char *__memory_arena_memdup(const void *b, size_t len) {
char *ret = __memory_arena_alloc(len);
memcpy(ret, b, len);
return ret;
}
#define memory_arena_objdup(o) ((__typeof(&(o))) __memory_arena_memdup(&(o), sizeof(o)))
INLINE char *memory_arena_dup(const char *b, size_t len) {
char *ret = __memory_arena_alloc(len + 1);
memcpy(ret, b, len);

@ -676,6 +676,8 @@ struct sdp_fragment;
TYPED_GQUEUE(fragment, struct sdp_fragment)
TYPED_GHASHTABLE(fragments_ht, str, fragment_q, str_hash, str_equal, NULL, NULL)
TYPED_GHASHTABLE(endpoint_ml_ht, endpoint_t, struct call_monologue, endpoint_hash, endpoint_eq, NULL, NULL)
struct call_iterator_list {
call_list *first;
@ -779,6 +781,8 @@ struct call {
str_ml_ht tags;
str_ml_ht viabranches;
str_ml_ht labels;
str_ml_ht sdps;
endpoint_ml_ht endpoints;
fragments_ht sdp_fragments;
packet_stream_q streams;
stream_fd_q stream_fds; /* stream_fd */
@ -869,7 +873,7 @@ int call_get_mono_dialogue(struct call_monologue *monologues[2], call_t *call,
const str *fromtag,
const str *totag,
const str *viabranch,
sdp_ng_flags *);
sdp_ng_flags *, const endpoint_t *);
struct call_monologue *call_get_monologue(call_t *call, const str *fromtag);
struct call_monologue *call_get_or_create_monologue(call_t *call, const str *fromtag);
__attribute__((nonnull(1, 2, 4, 5, 6)))

@ -142,6 +142,11 @@ struct sdp_ng_flags {
AP_TRANSCODING,
AP_FORCE,
} audio_player:2;
enum {
AK_NONE = 0,
AK_SDP,
AK_ADDRESS,
} alias_key:2;
enum endpoint_learning el_option;
enum block_dtmf_mode block_dtmf_mode;
int delay_buffer;

@ -89,6 +89,458 @@ sub stun_succ {
new_call;
($port_a) = offer('from-tag alias control', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag alias control', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
($port_c) = offer('from-tag alias control', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
isnt($port_a, $port_c, "new port");
new_call;
($port_a) = offer('from-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
($port_c) = offer('from-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
is($port_a, $port_c, "same port");
new_call;
($port_a) = offer('from-tag alias control 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag alias control 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
($port_c) = offer('from-tag alias control 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
isnt($port_a, $port_c, "different port");
new_call;
($port_a) = offer('from-tag alias 2', { 'alias-key' => 'address' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag alias 2', { 'alias-key' => 'address' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
($port_c) = offer('from-tag alias 2', { 'alias-key' => 'address' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
is($port_a, $port_c, "same port");
new_call;
($port_a) = offer('from-tag & to-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag & to-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
new_tt();
($port_c) = offer('from-tag & to-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
is($port_a, $port_c, "same port");
($port_d) = answer('from-tag & to-tag alias', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
is($port_b, $port_d, "same port");
new_call;
($port_a) = offer('from-tag & to-tag alias 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('from-tag & to-tag alias 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
new_ft();
new_tt();
($port_c) = offer('from-tag & to-tag alias 2', { 'alias-key' => 'SDP', 'to-tag' => tt() }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 2000 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
isnt($port_a, $port_c, "different port");
# XXX unexpected? should we support to-tag alias here?
($port_d) = answer('from-tag & to-tag alias 2', { 'alias-key' => 'SDP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.3
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
is($port_b, $port_d, "same port");
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7354)], [qw(198.51.100.3 7356)]);
($port_a) = offer('reuse + transcoding', {

@ -102,6 +102,7 @@ my @string_opts = qw(
vsc-start-pause-resume-rec
rtpp-flags
body
alias-key
);
my @int_opts = qw(

Loading…
Cancel
Save