diff --git a/daemon/sdp.c b/daemon/sdp.c index abf0ecd21..194998ca9 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -2040,6 +2040,9 @@ 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); } +/** + * TODO: deprecate as soon as sdp_replace is discontinued. + */ static void chopper_replace(struct sdp_chopper *c, str *old, size_t *old_pos, const char *repl, size_t repl_len) { @@ -2900,36 +2903,84 @@ static void insert_rtcp_attr(GString *s, struct packet_stream *ps, const sdp_ng_ append_attr_to_gstring(s, "rtcp", &STR_GS(s_dst), flags, (sdp_media ? sdp_media->media_type_id : MT_UNKNOWN)); } - -static void sdp_version_replace(struct sdp_chopper *chop, sdp_sessions_q *sessions, - sdp_origin *orig) +/** + * chop - used by sdp_replace + * s - used by sdp_create + * + * TODO: deprecate chop-based handling, as soon as sdp_replace is gone. + */ +static void sdp_version_replace(struct sdp_chopper *chop, GString *s, + sdp_sessions_q *sessions, + sdp_origin *src_orig, + sdp_origin *other_orig) { char version_str[64]; - snprintf(version_str, sizeof(version_str), "%llu", orig->version_num); + snprintf(version_str, sizeof(version_str), "%llu", src_orig->version_num); size_t version_len = strlen(version_str); - chop->offset = 0; // start from the top - for (__auto_type l = sessions->head; l; l = l->next) { - struct sdp_session *session = l->data; - 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); + /* for sdp_replace */ + if (chop) { + /* start from the top */ + chop->offset = 0; + + for (__auto_type l = sessions->head; l; l = l->next) + { + struct sdp_session *session = l->data; + 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); + } + } + /* for sdp_create */ + else { + if (!other_orig || !src_orig) + return; + + other_orig->version_num = src_orig->version_num; + /* is our new value longer? */ + if (version_len > other_orig->version_str.len) { + /* overwrite + insert */ + g_string_overwrite_len(s, other_orig->version_output_pos, version_str, other_orig->version_str.len); + g_string_insert(s, other_orig->version_output_pos + other_orig->version_str.len, version_str + other_orig->version_str.len); + other_orig->version_str.len = version_len; + } + else { + /* overwrite + optional erase */ + g_string_overwrite(s, other_orig->version_output_pos, version_str); + if (version_len < other_orig->version_str.len) { + g_string_erase(s, other_orig->version_output_pos + version_len, other_orig->version_str.len - version_len); + other_orig->version_str.len = version_len; + } + } } } -static void sdp_version_check(struct sdp_chopper *chop, sdp_sessions_q *sessions, +/** + * `chop` - used by sdp_replace (in this case `s` is NULL) + * `s` - used by sdp_create (in this case `chop` is NULL) + * + * TODO: deprecate chop-based handling, as soon as sdp_replace is gone. + */ +static void sdp_version_check(struct sdp_chopper *chop, GString *s, + sdp_sessions_q *sessions, struct call_monologue *monologue, bool force_increase) { - /* 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 */ - if (!monologue->session_last_sdp_orig) return; + sdp_origin *origin = monologue->session_last_sdp_orig; + sdp_origin *other_origin = NULL; + + struct media_subscription *ms = call_get_top_media_subscription(monologue); + if (ms && ms->monologue && ms->monologue->session_sdp_orig) + other_origin = ms->monologue->session_sdp_orig; + + /* 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, origin); + sdp_version_replace(chop, s, sessions, origin, other_origin); /* Now check if we need to change the version actually. * The version change will be forced with the 'force_increase', @@ -2939,17 +2990,17 @@ static void sdp_version_check(struct sdp_chopper *chop, sdp_sessions_q *sessions if (!force_increase) { if (!monologue->last_out_sdp) goto dup; - if (g_string_equal(monologue->last_out_sdp, chop->output)) + if (g_string_equal(monologue->last_out_sdp, (chop ? chop->output : s))) return; } /* mismatch detected. increment version, update again, and store copy */ origin->version_num++; - sdp_version_replace(chop, sessions, origin); + sdp_version_replace(chop, s, sessions, origin, other_origin); if (monologue->last_out_sdp) g_string_free(monologue->last_out_sdp, TRUE); dup: - monologue->last_out_sdp = g_string_new_len(chop->output->str, chop->output->len); + monologue->last_out_sdp = g_string_new_len((chop ? chop->output->str : s->str), (chop ? chop->output->len : s->len)); } const char *sdp_get_sendrecv(struct call_media *media) { @@ -3442,7 +3493,7 @@ int sdp_replace(struct sdp_chopper *chop, sdp_sessions_q *sessions, * which forces version increase regardless changes in the SDP information. */ if (flags->force_inc_sdp_ver || flags->replace_sdp_version || flags->replace_origin_full) - sdp_version_check(chop, sessions, monologue, !!flags->force_inc_sdp_ver); + sdp_version_check(chop, NULL, sessions, monologue, !!flags->force_inc_sdp_ver); return 0; @@ -3472,10 +3523,12 @@ static void sdp_out_add_origin(GString *out, struct call_monologue *monologue, str * orig_session_id = (ml->session_last_sdp_orig && flags->replace_origin_full) ? &ml->session_last_sdp_orig->session_id : &ml->session_sdp_orig->session_id; - /* orig session ver */ - /* TODO: add support of `sdp_version_check()` */ - unsigned long long orig_session_version = (ml->session_last_sdp_orig && flags->replace_origin_full) ? - ml->session_last_sdp_orig->version_num : ml->session_sdp_orig->version_num; + /* orig session ver + * replacement is handled later in sdp_create() based on SDP changes */ + unsigned long long orig_session_version = ml->session_sdp_orig->version_num; + /* record origin version position for replacements + * + 4 - means: `o=` + 2 spaces between username and version / version and id */ + ml->session_sdp_orig->version_output_pos = out->len + orig_username->len + orig_session_id->len + 4; /* orig IP family and address */ str orig_address_type; @@ -3489,6 +3542,7 @@ static void sdp_out_add_origin(GString *out, struct call_monologue *monologue, orig_address = ml->session_sdp_orig->address.address; } + /* print it to the output sdp */ g_string_append_printf(out, "o="STR_FORMAT" "STR_FORMAT" %llu IN "STR_FORMAT" "STR_FORMAT"\r\n", STR_FMT(orig_username), @@ -3680,6 +3734,14 @@ int sdp_create(str *out, struct call_monologue *monologue, sdp_ng_flags *flags) print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, true, false); } + /* The SDP version gets increased in case: + * - if replace_sdp_version (sdp-version) or replace_origin_full flag is set and SDP information has been updated, or + * - if the force_inc_sdp_ver (force-increment-sdp-ver) flag is set additionally to replace_sdp_version, + * which forces version increase regardless changes in the SDP information. + */ + if (flags->force_inc_sdp_ver || flags->replace_sdp_version || flags->replace_origin_full) + sdp_version_check(NULL, s, NULL, monologue, !!flags->force_inc_sdp_ver); + out->len = s->len; out->s = g_string_free(s, FALSE); return 0;