|
|
|
@ -3301,233 +3301,6 @@ error: |
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* monologue - is other monologue (so the opposite site in offer/answer) |
|
|
|
* called with call->master_lock held in W |
|
|
|
*/ |
|
|
|
int sdp_replace(struct sdp_chopper *chop, sdp_sessions_q *sessions, |
|
|
|
struct call_monologue *monologue, sdp_ng_flags *flags) |
|
|
|
{ |
|
|
|
struct sdp_session *session; |
|
|
|
struct sdp_media *sdp_media; |
|
|
|
int sess_conn; |
|
|
|
struct call_media *call_media; |
|
|
|
struct packet_stream *ps; |
|
|
|
const char *err = NULL; |
|
|
|
unsigned int media_index = 0; |
|
|
|
|
|
|
|
/* for the usual SDP offer/answer there is only one SDP session though. */ |
|
|
|
for (__auto_type l = sessions->head; l; l = l->next) { |
|
|
|
session = l->data; |
|
|
|
|
|
|
|
// look for first usable (non-rejected, non-empty) packet stream |
|
|
|
// from any media to determine session-level attributes, if any |
|
|
|
ps = NULL; |
|
|
|
for (unsigned int ix = media_index; ix < monologue->medias->len; ix++) { |
|
|
|
call_media = monologue->medias->pdata[ix]; |
|
|
|
if (!call_media) |
|
|
|
continue; |
|
|
|
if (!call_media->streams.head) |
|
|
|
continue; |
|
|
|
ps = call_media->streams.head->data; |
|
|
|
if (ps->selected_sfd) |
|
|
|
break; |
|
|
|
ps = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
err = "no usable session media stream"; |
|
|
|
if (!ps) |
|
|
|
goto error; |
|
|
|
|
|
|
|
err = "error while processing o= line"; |
|
|
|
|
|
|
|
/* replace username */ |
|
|
|
if (monologue->session_last_sdp_orig && |
|
|
|
(flags->replace_username || flags->replace_origin_full)) |
|
|
|
{ |
|
|
|
/* make sure the username field in the o= line always remains the same |
|
|
|
* in all SDPs going to a particular endpoint */ |
|
|
|
if (copy_up_to(chop, &session->origin.username)) |
|
|
|
goto error; |
|
|
|
chopper_append_str(chop, &monologue->session_last_sdp_orig->username); |
|
|
|
if (skip_over(chop, &session->origin.username)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
/* replace session id */ |
|
|
|
if (monologue->session_last_sdp_orig && flags->replace_origin_full) { |
|
|
|
if (copy_up_to(chop, &session->origin.session_id)) |
|
|
|
goto error; |
|
|
|
chopper_append_str(chop, &monologue->session_last_sdp_orig->session_id); |
|
|
|
if (skip_over(chop, &session->origin.session_id)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
/* session version */ |
|
|
|
if (copy_up_to(chop, &session->origin.version_str)) |
|
|
|
goto error; |
|
|
|
/* record position of o= line and init SDP version */ |
|
|
|
session->origin.version_output_pos = chop->output->len; |
|
|
|
/* TODO: should we just go to 128bit length? */ |
|
|
|
if (monologue->session_last_sdp_orig && |
|
|
|
monologue->session_last_sdp_orig->version_num == ULLONG_MAX) |
|
|
|
{ |
|
|
|
monologue->session_last_sdp_orig->version_num = (unsigned int)ssl_random(); |
|
|
|
} |
|
|
|
|
|
|
|
/* replace origin's network addr */ |
|
|
|
if ((flags->replace_origin || flags->replace_origin_full) && |
|
|
|
flags->ice_option != ICE_FORCE_RELAY) |
|
|
|
{ |
|
|
|
err = "failed to replace network address"; |
|
|
|
if (replace_network_address(chop, &session->origin.address, ps, flags, false)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
err = "error while processing s= line"; |
|
|
|
if (!monologue->sdp_session_name) |
|
|
|
monologue->sdp_session_name = call_strdup_len(session->session_name.s, |
|
|
|
session->session_name.len); |
|
|
|
else if (flags->replace_sess_name) { |
|
|
|
if (copy_up_to(chop, &session->session_name)) |
|
|
|
goto error; |
|
|
|
chopper_append_c(chop, monologue->sdp_session_name); |
|
|
|
if (skip_over(chop, &session->session_name)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
sess_conn = 0; |
|
|
|
for (__auto_type k = session->media_streams.head; k; k = k->next) { |
|
|
|
sdp_media = k->data; |
|
|
|
if (!sdp_media->connection.parsed) { |
|
|
|
sess_conn = 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool keep_zero_address = !MEDIA_ISSET(call_media, ICE); |
|
|
|
|
|
|
|
if (session->connection.parsed && sess_conn && |
|
|
|
flags->ice_option != ICE_FORCE_RELAY) { |
|
|
|
err = "failed to replace network address"; |
|
|
|
if (replace_network_address(chop, &session->connection.address, ps, flags, |
|
|
|
keep_zero_address)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if (!MEDIA_ISSET(call_media, PASSTHRU)) { |
|
|
|
err = "failed to process session attributes"; |
|
|
|
if (process_session_attributes(chop, &session->attributes, flags)) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
copy_up_to_end_of(chop, &session->s); |
|
|
|
|
|
|
|
/* add a list of important attrs to the session section */ |
|
|
|
print_sdp_session_section(chop->output, flags, call_media); |
|
|
|
|
|
|
|
/* ADD arbitrary SDP manipulations for a session sessions */ |
|
|
|
struct sdp_manipulations *sdp_manipulations = sdp_manipulations_get_by_id(flags, MT_UNKNOWN); |
|
|
|
sdp_manipulations_add(chop->output, sdp_manipulations); |
|
|
|
|
|
|
|
for (__auto_type k = session->media_streams.head; k; k = k->next) { |
|
|
|
sdp_media = k->data; |
|
|
|
|
|
|
|
// skip over received dummy SDP sections |
|
|
|
if (sdp_media->legacy_osrtp) { |
|
|
|
if (skip_over(chop, &sdp_media->s)) |
|
|
|
goto error; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
err = "no matching media"; |
|
|
|
call_media = monologue->medias->pdata[media_index]; |
|
|
|
if (!call_media) |
|
|
|
goto error; |
|
|
|
err = "no matching media stream"; |
|
|
|
__auto_type rtp_ps_link = call_media->streams.head; |
|
|
|
if (!rtp_ps_link) |
|
|
|
goto error; |
|
|
|
|
|
|
|
const struct transport_protocol *prtp = NULL; |
|
|
|
if (call_media->protocol && call_media->protocol->srtp) |
|
|
|
prtp = &transport_protocols[call_media->protocol->rtp_proto]; |
|
|
|
|
|
|
|
if (prtp) { |
|
|
|
if (MEDIA_ISSET(call_media, LEGACY_OSRTP) |
|
|
|
&& !MEDIA_ISSET(call_media, LEGACY_OSRTP_REV)) |
|
|
|
{ |
|
|
|
// generate rejected m= line for accepted legacy OSRTP |
|
|
|
chopper_append_c(chop, "m="); |
|
|
|
chopper_append_str(chop, &call_media->type); |
|
|
|
chopper_append_c(chop, " 0 "); |
|
|
|
chopper_append_c(chop, prtp->name); |
|
|
|
chopper_append_c(chop, " "); |
|
|
|
chopper_append_str(chop, &call_media->format_str); |
|
|
|
chopper_append_c(chop, "\r\n"); |
|
|
|
} |
|
|
|
else if (flags->osrtp_offer_legacy && flags->opmode == OP_OFFER) { |
|
|
|
// generate duplicate plain RTP media section for OSRTP offer: |
|
|
|
// save current chopper state, save actual protocol, |
|
|
|
// print SDP section, restore chopper and protocl |
|
|
|
struct sdp_chopper chop_copy = *chop; |
|
|
|
const struct transport_protocol *proto = call_media->protocol; |
|
|
|
call_media->protocol = prtp; |
|
|
|
err = replace_sdp_media_section(chop, call_media, sdp_media, |
|
|
|
rtp_ps_link, flags, |
|
|
|
keep_zero_address); |
|
|
|
*chop = chop_copy; |
|
|
|
call_media->protocol = proto; |
|
|
|
if (err) |
|
|
|
goto error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
err = replace_sdp_media_section(chop, call_media, sdp_media, |
|
|
|
rtp_ps_link, flags, |
|
|
|
keep_zero_address); |
|
|
|
if (err) |
|
|
|
goto error; |
|
|
|
|
|
|
|
if (prtp && MEDIA_ISSET(call_media, LEGACY_OSRTP) |
|
|
|
&& MEDIA_ISSET(call_media, LEGACY_OSRTP_REV)) |
|
|
|
{ |
|
|
|
// generate rejected m= line for accepted legacy OSRTP |
|
|
|
chopper_append_c(chop, "m="); |
|
|
|
chopper_append_str(chop, &call_media->type); |
|
|
|
chopper_append_c(chop, " 0 "); |
|
|
|
chopper_append_c(chop, prtp->name); |
|
|
|
chopper_append_c(chop, " "); |
|
|
|
chopper_append_str(chop, &call_media->format_str); |
|
|
|
chopper_append_c(chop, "\r\n"); |
|
|
|
} |
|
|
|
|
|
|
|
/* ADD arbitrary SDP manipulations for audio/video media sessions */ |
|
|
|
sdp_manipulations = sdp_manipulations_get_by_id(flags, sdp_media->media_type_id); |
|
|
|
sdp_manipulations_add(chop->output, sdp_manipulations); |
|
|
|
|
|
|
|
media_index++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
copy_remainder(chop); |
|
|
|
|
|
|
|
/* 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(chop, NULL, sessions, monologue, !!flags->force_inc_sdp_ver); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
error: |
|
|
|
ilog(LOG_ERROR, "Error rewriting SDP: %s", err); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static void sdp_out_add_origin(GString *out, struct call_monologue *monologue, |
|
|
|
struct packet_stream *first_ps, sdp_ng_flags *flags) |
|
|
|
{ |
|
|
|
|