|
|
|
@ -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)
|
|
|
|
|
{
|
|
|
|
|