From 8f60c4c9ad63e705f9d85310e75b2a21d567aae8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 21 Dec 2012 16:31:40 +0100 Subject: [PATCH] Allow update of SRTP crypto keys without restarting the media streams. --- coreapi/callbacks.c | 53 ++++++++++++++++++++++++------------------ coreapi/linphonecall.c | 46 ++++++++++++++++++++++++++++++++++++ coreapi/private.h | 1 + coreapi/sal.c | 8 +++++++ coreapi/sal.h | 3 ++- 5 files changed, 88 insertions(+), 23 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 134c336a..f9399553 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -104,31 +104,40 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia /* we already started media: check if we really need to restart it*/ if (oldmd){ int md_changed = media_parameters_changed(call, oldmd, new_md); - if ((md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) && !call->playing_ringbacktone) { - /*as nothing has changed, keep the oldmd */ - call->resultdesc=oldmd; - sal_media_description_unref(new_md); - if (call->all_muted){ - ms_message("Early media finished, unmuting inputs..."); - /*we were in early media, now we want to enable real media */ - linphone_call_enable_camera (call,linphone_call_camera_enabled (call)); - if (call->audiostream) - linphone_core_mute_mic (lc, linphone_core_is_mic_muted(lc)); + if ((md_changed & SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) || call->playing_ringbacktone) { + ms_message("Media descriptions are different, need to restart the streams."); + } else { + if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) { + /*as nothing has changed, keep the oldmd */ + call->resultdesc=oldmd; + sal_media_description_unref(new_md); + if (call->all_muted){ + ms_message("Early media finished, unmuting inputs..."); + /*we were in early media, now we want to enable real media */ + linphone_call_enable_camera (call,linphone_call_camera_enabled (call)); + if (call->audiostream) + linphone_core_mute_mic (lc, linphone_core_is_mic_muted(lc)); #ifdef VIDEO_ENABLED - if (call->videostream && call->camera_active) - video_stream_change_camera(call->videostream,lc->video_conf.device ); + if (call->videostream && call->camera_active) + video_stream_change_camera(call->videostream,lc->video_conf.device ); #endif + } + ms_message("No need to restart streams, SDP is unchanged."); + return; + } + else { + if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) { + ms_message("Network parameters have changed, update them."); + linphone_core_update_streams_destinations(lc, call, oldmd, new_md); + } + if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) { + ms_message("Crypto parameters have changed, update them."); + linphone_call_update_crypto_parameters(call, oldmd, new_md); + } + call->resultdesc = oldmd; + sal_media_description_unref(new_md); + return; } - ms_message("No need to restart streams, SDP is unchanged."); - return; - } else if ((md_changed == SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) && !call->playing_ringbacktone) { - call->resultdesc = oldmd; - ms_message("Network parameters have changed, update them."); - linphone_core_update_streams_destinations(lc, call, oldmd, new_md); - sal_media_description_unref(new_md); - return; - }else{ - ms_message("Media descriptions are different, need to restart the streams."); } } linphone_call_stop_media_streams (call); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ffaf24b5..9ad1e177 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1658,6 +1658,52 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ #endif } +void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { + SalStreamDescription *old_stream; + SalStreamDescription *new_stream; + int i; + + old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); + new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); + if (old_stream && new_stream) { + const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); + if (crypto_idx >= 0) { + audio_stream_enable_strp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); + call->audiostream_encrypted = TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); + call->audiostream_encrypted = FALSE; + } + for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { + old_stream->crypto[i].tag = new_stream->crypto[i].tag; + old_stream->crypto[i].algo = new_stream->crypto[i].algo; + strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); + } + } + +#ifdef VIDEO_ENABLED + old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo); + new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo); + if (old_stream && new_stream) { + const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); + if (crypto_idx >= 0) { + video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); + call->videostream_encrypted = TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); + call->videostream_encrypted = FALSE; + } + for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { + old_stream->crypto[i].tag = new_stream->crypto[i].tag; + old_stream->crypto[i].algo = new_stream->crypto[i].algo; + strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); + } + } +#endif +} + void linphone_call_delete_ice_session(LinphoneCall *call){ if (call->ice_session != NULL) { ice_session_destroy(call->ice_session); diff --git a/coreapi/private.h b/coreapi/private.h index 43e4b222..c171fac8 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -285,6 +285,7 @@ void linphone_call_stop_video_stream(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); void linphone_call_delete_ice_session(LinphoneCall *call); void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call); +void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md); const char * linphone_core_get_identity(LinphoneCore *lc); const char * linphone_core_get_route(LinphoneCore *lc); diff --git a/coreapi/sal.c b/coreapi/sal.c index f46d9a55..7a3bbdf7 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -189,10 +189,18 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) { int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; + int i; /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */ if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { + if ((sd1->crypto[i].tag != sd2->crypto[i].tag) + || (sd1->crypto[i].algo != sd2->crypto[i].algo) + || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { + result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED; + } + } if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; diff --git a/coreapi/sal.h b/coreapi/sal.h index daa59217..77e43d6b 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -56,7 +56,8 @@ typedef enum { #define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 #define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 #define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 -#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) +#define SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED 0x04 +#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED | SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); -- 2.39.2