TT#107565 add option to track SDP version

Change-Id: Ifb3ca589742a4ad0cc83982d6e42bf692a2c98db
pull/1194/head
Richard Fuchs 4 years ago
parent 01112f27ca
commit 36273e1f5d

@ -852,6 +852,11 @@ Optionally included keys are:
Replace the address found in the *session-level connection* (c=) line of the SDP body.
Corresponds to *rtpproxy* `c` flag.
- `SDP version`
Take control of the version field in the SDP and make sure it's increased every
time the SDP changes, and left unchanged if the SDP is the same.
* `direction`
Contains a list of two strings and corresponds to the *rtpproxy* `e` and `i` flags. Each element must

@ -2626,6 +2626,8 @@ static void __call_free(void *p) {
g_hash_table_destroy(m->other_tags);
g_hash_table_destroy(m->branches);
g_hash_table_destroy(m->media_ids);
if (m->last_sdp)
g_string_free(m->last_sdp, TRUE);
g_slice_free1(sizeof(*m), m);
}

@ -706,13 +706,23 @@ static void call_ng_flags_rtcp_mux(struct sdp_ng_flags *out, str *s, void *dummy
}
static void call_ng_flags_replace(struct sdp_ng_flags *out, str *s, void *dummy) {
str_hyphenate(s);
if (!str_cmp(s, "origin"))
out->replace_origin = 1;
else if (!str_cmp(s, "session-connection"))
out->replace_sess_conn = 1;
else
ilog(LOG_WARN, "Unknown 'replace' flag encountered: '" STR_FORMAT "'",
STR_FMT(s));
switch (__csh_lookup(s)) {
case CSH_LOOKUP("origin"):
out->replace_origin = 1;
break;
case CSH_LOOKUP("session-connection"):
out->replace_sess_conn = 1;
break;
case CSH_LOOKUP("sdp-version"):
out->replace_sdp_version = 1;
break;
case CSH_LOOKUP("SDP-version"):
out->replace_sdp_version = 1;
break;
default:
ilog(LOG_WARN, "Unknown 'replace' flag encountered: '" STR_FORMAT "'",
STR_FMT(s));
}
}
static void call_ng_flags_supports(struct sdp_ng_flags *out, str *s, void *dummy) {
if (!str_cmp(s, "load limit"))

@ -29,8 +29,10 @@ struct network_address {
struct sdp_origin {
str username;
str session_id;
str version;
str version_str;
struct network_address address;
unsigned long long version_num;
size_t version_output_pos;
int parsed:1;
};
@ -347,9 +349,10 @@ static int parse_origin(str *value_str, struct sdp_origin *output) {
EXTRACT_TOKEN(username);
EXTRACT_TOKEN(session_id);
EXTRACT_TOKEN(version);
EXTRACT_TOKEN(version_str);
EXTRACT_NETWORK_ADDRESS_NF(address);
output->version_num = strtoull(output->version_str.s, NULL, 10);
output->parsed = 1;
return 0;
}
@ -1656,6 +1659,29 @@ INLINE void chopper_append_c(struct sdp_chopper *c, const char *s) {
INLINE void chopper_append_str(struct sdp_chopper *c, const str *s) {
chopper_append(c, s->s, s->len);
}
static void chopper_replace(struct sdp_chopper *c, str *old, size_t *old_pos,
const char *repl, size_t repl_len)
{
// adjust for offsets created within this run
*old_pos += c->offset;
// is our new value longer?
if (repl_len > old->len) {
// overwrite + insert
g_string_overwrite_len(c->output, *old_pos, repl, old->len);
g_string_insert(c->output, *old_pos + old->len, repl + old->len);
c->offset += repl_len - old->len;
old->len = repl_len;
}
else {
// overwrite + optional erase
g_string_overwrite(c->output, *old_pos, repl);
if (repl_len < old->len) {
g_string_erase(c->output, *old_pos + repl_len, old->len - repl_len);
c->offset -= old->len - repl_len;
old->len = repl_len;
}
}
}
#define chopper_append_printf(c, f...) g_string_append_printf((c)->output, f)
@ -2363,6 +2389,41 @@ static void insert_rtcp_attr(struct sdp_chopper *chop, struct packet_stream *ps,
}
static void sdp_version_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue) {
char version_str[64];
snprintf(version_str, sizeof(version_str), "%llu", monologue->sdp_version);
size_t version_len = strlen(version_str);
chop->offset = 0; // start from the top
for (GList *l = sessions->head; l; l = l->next) {
struct sdp_session *session = l->data;
struct sdp_origin *origin = &session->origin;
// update string unconditionally to keep position tracking intact
chopper_replace(chop, &origin->version_str, &origin->version_output_pos, version_str, version_len);
}
}
static void sdp_version_check(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue) {
// we really expect only a single session here, but we treat all the same regardless,
// and use the same version number on all of them
// first update all versions to match our single version
sdp_version_replace(chop, sessions, monologue);
// then check if we need to change
if (!monologue->last_sdp)
goto dup;
if (g_string_equal(monologue->last_sdp, chop->output))
return;
// mismatch detected. increment version, update again, and store copy
monologue->sdp_version++;
sdp_version_replace(chop, sessions, monologue);
g_string_free(monologue->last_sdp, TRUE);
dup:
monologue->last_sdp = g_string_new_len(chop->output->str, chop->output->len);
}
/* called with call->master_lock held in W */
int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue,
struct sdp_ng_flags *flags)
@ -2393,6 +2454,15 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
goto error;
ps = j->data;
// record position of o= line and init SDP version
copy_up_to(chop, &session->origin.version_str);
session->origin.version_output_pos = chop->output->len;
if (!monologue->sdp_version) {
monologue->sdp_version = session->origin.version_num;
if (monologue->sdp_version == 0 || monologue->sdp_version == ULLONG_MAX)
monologue->sdp_version = random();
}
sess_conn = 0;
if (flags->replace_sess_conn)
sess_conn = 1;
@ -2576,6 +2646,11 @@ next:
}
copy_remainder(chop);
if (flags->replace_sdp_version)
sdp_version_check(chop, sessions, monologue);
return 0;
error:

@ -371,6 +371,8 @@ struct call_monologue {
GQueue medias;
GHashTable *media_ids;
struct media_player *player;
unsigned long long sdp_version;
GString *last_sdp;
int block_dtmf:1;
int block_media:1;

@ -71,6 +71,7 @@ struct sdp_ng_flags {
port_latching:1,
replace_origin:1,
replace_sess_conn:1,
replace_sdp_version:1,
rtcp_mux_offer:1,
rtcp_mux_require:1,
rtcp_mux_demux:1,

@ -9,12 +9,9 @@
struct sdp_chopper {
str *input;
int position;
size_t position;
GString *output;
// GStringChunk *chunk;
// GArray *iov;
// int iov_num;
// int str_len;
ssize_t offset; // for post-processing using chopper_replace
};
extern const str rtpe_instance_id;

@ -12407,4 +12407,551 @@ rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5));
$resp = rtpe_req('statistics', 'statistics');
# SDP version tests
new_call;
offer('SDP version simple increments', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
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.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
offer('SDP version simple increments', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
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.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
offer('SDP version simple increments', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 2 IN IP4 198.51.100.1
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.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
offer('SDP version simple increments', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 3 IN IP4 198.51.100.1
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.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
offer('SDP version simple increments', { replace => ['SDP version'] }, <<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.1
----------------------------
v=0
o=- 1545997027 2 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
offer('SDP version simple increments', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 4 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 2 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_call;
offer('SDP version multi session', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 1000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 999 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
v=0
o=- 1545997027 999 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
offer('SDP version multi session', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 1000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 999 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
v=0
o=- 1545997027 999 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
offer('SDP version multi session', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2004 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 1000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 1000 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
v=0
o=- 1545997027 1000 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_call;
offer('SDP version string lengths', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 9999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2004 RTP/AVP 0
c=IN IP4 198.51.100.1
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.1
v=0
o=- 1545997027 10000000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 1000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
offer('SDP version string lengths', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 9999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2004 RTP/AVP 0
c=IN IP4 198.51.100.1
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.1
v=0
o=- 1545997027 10000000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 1000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
offer('SDP version string lengths', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2004 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 999999999999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 10000000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 10 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
v=0
o=- 1545997027 9999 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
offer('SDP version string lengths', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2006 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 999999999999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 10000000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 10 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
offer('SDP version string lengths', { replace => ['SDP version'] }, <<SDP);
v=0
o=- 1545997027 11111 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2006 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 99999999 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 10000 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
v=0
o=- 1545997027 000010 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2002 RTP/AVP 0
c=IN IP4 198.51.100.1
----------------------------
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
v=0
o=- 1545997027 10000 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
done_testing();

@ -28,6 +28,7 @@ GetOptions(
'unidirectional' => \$options{'unidirectional'},
'replace-origin' => \$options{'replace-origin'},
'replace-session-connection' => \$options{'replace-session connection'},
'replace-sdp-version' => \$options{'replace-sdp version'},
'client-address=s' => \$options{'client-address'},
'sdp=s' => \$options{'sdp'},
'sdp-file=s' => \$options{'sdp-file'},
@ -99,7 +100,7 @@ for my $x (split(/,/, 'TOS,delete-delay')) {
for my $x (split(/,/, 'trust address,symmetric,asymmetric,unidirectional,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,full rtcp attribute,loop protect,record call,always transcode,all,pad crypto,generate mid,fragment,original sendrecv,symmetric codecs,asymmetric codecs,inject DTMF,generate RTCP,single codec')) {
defined($options{$x}) and push(@{$packet{flags}}, $x);
}
for my $x (split(/,/, 'origin,session connection')) {
for my $x (split(/,/, 'origin,session connection,sdp version')) {
defined($options{'replace-' . $x}) and push(@{$packet{replace}}, $x);
}
for my $x (split(/,/, 'rtcp-mux,SDES,supports,T.38,OSRTP')) {

Loading…
Cancel
Save