From b986af37339679319d4c912b91d8dfaf28051fe1 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Wed, 10 Dec 2014 15:11:36 +0100 Subject: [PATCH 01/20] Add dtls srtp --- configure.ac | 12 ++++ coreapi/bellesip_sal/sal_impl.c | 36 ++++++++++ coreapi/bellesip_sal/sal_sdp.c | 98 +++++++++++++++++++++++++ coreapi/call_params.c | 2 + coreapi/linphonecall.c | 124 ++++++++++++++++++++++++++++---- coreapi/linphonecore.c | 33 +++++++++ coreapi/linphonecore.h | 19 ++++- coreapi/offeranswer.c | 46 ++++++++++++ coreapi/private.h | 2 + coreapi/sal.c | 18 ++++- gtk/incall_view.c | 6 ++ gtk/main.c | 5 ++ gtk/propertybox.c | 32 +++++++-- include/sal/sal.h | 27 +++++++ mediastreamer2 | 2 +- oRTP | 2 +- 16 files changed, 440 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 067a13b62..02b034f8d 100644 --- a/configure.ac +++ b/configure.ac @@ -585,6 +585,16 @@ AC_ARG_ENABLE(zrtp, [zrtp=false] ) +AC_ARG_ENABLE(dtls, + [AS_HELP_STRING([--enable-dtls], [Turn on dtls support - requires polarssl > 1.4])], + [case "${enableval}" in + yes) dtls=true ;; + no) dtls=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-dtls) ;; + esac], + [dtls=false] +) + dnl build console if required AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) @@ -595,6 +605,7 @@ dnl compilation of gtk user interface AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] ) AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes ) AM_CONDITIONAL(BUILD_ZRTP, test x$zrtp = xtrue) +AM_CONDITIONAL(BUILD_DTLS, test x$dtls = xtrue) dnl check getenv AH_TEMPLATE([HAVE_GETENV]) @@ -943,6 +954,7 @@ printf "* %-30s %s\n" "Console interface" $console_ui printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "Message storage" $enable_msg_storage printf "* %-30s %s\n" "zRTP encryption" $zrtp +printf "* %-30s %s\n" "DTLS encryption" $dtls printf "* %-30s %s\n" "uPnP support" $build_upnp printf "* %-30s %s\n" "LDAP support" $enable_ldap diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 052c83971..0dfc10aa7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -1060,6 +1060,42 @@ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); } +/** + * Parse a directory to get a certificate with the given subject common name + * + */ +void sal_certificates_chain_parse_directory(unsigned char **certificate_pem, unsigned char **key_pem, unsigned char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) { + belle_sip_certificates_chain_t *certificate = NULL; + belle_sip_signing_key_t *key = NULL; + *certificate_pem = NULL; + *key_pem = NULL; + if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) { + *certificate_pem = belle_sip_get_certificates_pem(certificate); + *key_pem = belle_sip_get_key_pem(key); + ms_message("Retrieve certificate with CN=%s successful\n", subject); + } else { + if (generate_certificate == TRUE) { + if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) { + *certificate_pem = belle_sip_get_certificates_pem(certificate); + *key_pem = belle_sip_get_key_pem(key); + ms_message("Generate self-signed certificate with CN=%s successful\n", subject); + } + } + } + /* generate the fingerprint as described in RFC4572 if needed */ + if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) { + *fingerprint = belle_sip_generate_certificate_fingerprint(certificate); + } + + /* free key and certificate */ + if ( certificate != NULL ) { + belle_sip_object_unref(certificate); + } + if ( key != NULL ) { + belle_sip_object_unref(key); + } +} + unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index fe952bb56..cc6db442f 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -233,6 +233,26 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session }else break; } } + + /* insert DTLS session attribute if needed */ + if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) { + if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) { + switch(stream->dtls_role) { + case SalDtlsRoleIsClient: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","active")); + break; + case SalDtlsRoleIsServer: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","passive")); + break; + case SalDtlsRoleUnset: + default: + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","actpass")); + break; + } + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint)); + } + } + switch ( stream->dir ) { case SalStreamSendRecv: /*dir="sendrecv";*/ @@ -351,6 +371,23 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd)); if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag)); + /* insert DTLS session attribute if needed */ + if ((desc->dtls_role != SalDtlsRoleInvalid) && (strlen(desc->dtls_fingerprint)>0)) { + switch(desc->dtls_role) { + case SalDtlsRoleIsClient: + belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","active")); + break; + case SalDtlsRoleIsServer: + belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","passive")); + break; + case SalDtlsRoleUnset: + default: + belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","actpass")); + break; + } + belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("fingerprint",desc->dtls_fingerprint)); + } + if (desc->rtcp_xr.enabled == TRUE) { belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr)); } @@ -646,6 +683,10 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, stream->proto = SalProtoRtpAvpf; } else if (strcasecmp(proto, "RTP/SAVPF") == 0) { stream->proto = SalProtoRtpSavpf; + } else if (strcasecmp(proto, "UDP/TLS/RTP/SAVP") == 0) { + stream->proto = SalProtoUdpTlsRtpSavp; + } else if (strcasecmp(proto, "UDP/TLS/RTP/SAVPF") == 0) { + stream->proto = SalProtoUdpTlsRtpSavpf; } else { strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1); } @@ -701,6 +742,36 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, } } + /* Read DTLS specific attributes : check is some are found in the stream description otherwise copy the session description one(which are at least set to Invalid) */ + stream->dtls_role = SalDtlsRoleInvalid; + stream->dtls_fingerprint[0] = '\0'; + if (((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp))) { + attribute=belle_sdp_media_description_get_attribute(media_desc,"setup"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + if (strncmp(value, "actpass", 7) == 0) { + stream->dtls_role = SalDtlsRoleUnset; + } else if (strncmp(value, "active", 6) == 0) { + stream->dtls_role = SalDtlsRoleIsClient; + } else if (strncmp(value, "passive", 7) == 0) { + stream->dtls_role = SalDtlsRoleIsServer; + } + + if (stream->dtls_role != SalDtlsRoleInvalid) { + attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + strncpy(stream->dtls_fingerprint, value, strlen(value)+1); + } else { + /* no valid stream attributes, get them from session */ + stream->dtls_role = md->dtls_role; + strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1); + } + } + } else { /* no setup attribute found in the stream, get the one from the session */ + stream->dtls_role = md->dtls_role; + strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1); + } + } + /* Read crypto lines if any */ if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { sdp_parse_media_crypto_parameters(media_desc, stream); @@ -756,6 +827,33 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S desc->dir=SalStreamInactive; } + /* Read dtls specific session attributes if any (setup and fingerprint - rfc5763) */ + /* Presence of a valid dtls offer(setup and fingerprint attribute) is set in media Description by a dtls_fingerprint string longer than 0 + * and a dtls_role != SalDtlsRoleInvalid */ + desc->dtls_role = SalDtlsRoleInvalid; + desc->dtls_fingerprint[0] = '\0'; + value=belle_sdp_session_description_get_attribute_value(session_desc,"setup"); + if (value){ + if (strncmp(value, "actpass", 7) == 0) { + desc->dtls_role = SalDtlsRoleUnset; + } else if (strncmp(value, "active", 6) == 0) { + desc->dtls_role = SalDtlsRoleIsClient; + } else if (strncmp(value, "passive", 7) == 0) { + desc->dtls_role = SalDtlsRoleIsServer; + } + } + + if (desc->dtls_role != SalDtlsRoleInvalid) { + value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint"); + if (value){ + strncpy(desc->dtls_fingerprint, value, strlen(value)+1); + } else { + desc->dtls_role = SalDtlsRoleInvalid; + } + } + + + /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); diff --git a/coreapi/call_params.c b/coreapi/call_params.c index a48066169..255103fb8 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf; if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; + if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf; + if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp; if (params->avpf_enabled) return SalProtoRtpAvpf; return SalProtoRtpAvp; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dc991c616..2990406aa 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -158,8 +158,12 @@ static void propagate_encryption_changed(LinphoneCall *call){ call->current_params->media_encryption=LinphoneMediaEncryptionNone; linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token); } else { - ms_message("All streams are encrypted"); - call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); + if (call->auth_token) {/* ZRTP only is using auth_token */ + call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + } else { /* otherwise it must be DTLS as SDES doesn't go through this function */ + call->current_params->media_encryption=LinphoneMediaEncryptionDTLS; + } linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token); } } @@ -171,8 +175,10 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr call = (LinphoneCall *)data; if (encrypted) { - snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); - linphone_core_notify_display_status(call->core, status); + if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */ + snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); + linphone_core_notify_display_status(call->core, status); + } } propagate_encryption_changed(call); @@ -472,6 +478,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * } setup_encryption_keys(call,md); + /* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */ + if ((call->params->media_encryption==LinphoneMediaEncryptionDTLS) && (call->dtls_certificate_fingerprint!= NULL)) { + memcpy(md->dtls_fingerprint, call->dtls_certificate_fingerprint, strlen((const char *)(call->dtls_certificate_fingerprint))); /* get the self fingerprint from call(it's computed at stream init) */ + md->dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */ + } else { + md->dtls_fingerprint[0] = '\0'; + md->dtls_role = SalDtlsRoleInvalid; + } setup_rtcp_fb(call, md); setup_rtcp_xr(call, md); @@ -572,6 +586,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->camera_enabled=TRUE; call->current_params = linphone_call_params_new(); call->current_params->media_encryption=LinphoneMediaEncryptionNone; + call->dtls_certificate_fingerprint = NULL; linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); @@ -735,7 +750,7 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) { call->params->has_video &= linphone_core_media_description_contains_video_stream(md); - /* Handle AVPF and SRTP. */ + /* Handle AVPF, SRTP and DTLS. */ call->params->avpf_enabled = sal_media_description_has_avpf(md); if (call->params->avpf_enabled == TRUE) { if (call->dest_proxy != NULL) { @@ -744,6 +759,9 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000; } } + if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) { + call->params->media_encryption = LinphoneMediaEncryptionDTLS; + } if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { call->params->media_encryption = LinphoneMediaEncryptionSRTP; } @@ -917,8 +935,19 @@ static void linphone_call_set_terminated(LinphoneCall *call){ void linphone_call_fix_call_parameters(LinphoneCall *call){ call->params->has_video=call->current_params->has_video; - if (call->params->media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/ - call->params->media_encryption=call->current_params->media_encryption; + switch(call->params->media_encryption) { + case LinphoneMediaEncryptionZRTP: + case LinphoneMediaEncryptionDTLS: + case LinphoneMediaEncryptionNone: + /* do nothing */ + break; + case LinphoneMediaEncryptionSRTP: + call->params->media_encryption=call->current_params->media_encryption; + break; + default: + ms_fatal("Unknown media encryption type on call [%p]", call); + break; + } } const char *linphone_call_state_to_string(LinphoneCallState cs){ @@ -1066,6 +1095,10 @@ static void linphone_call_destroy(LinphoneCall *obj){ ms_free(obj->auth_token); obj->auth_token=NULL; } + if (obj->dtls_certificate_fingerprint) { + ms_free(obj->dtls_certificate_fingerprint); + obj->dtls_certificate_fingerprint=NULL; + } if (obj->dtmfs_timer) { linphone_call_cancel_dtmfs(obj); } @@ -1118,11 +1151,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ #endif if (linphone_call_all_streams_encrypted(call)) { - if (linphone_call_get_authentication_token(call)) { - call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; - } else { - call->current_params->media_encryption=LinphoneMediaEncryptionSRTP; - } + if (linphone_call_get_authentication_token(call)) { + call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; + } else { + /* TODO : check this or presence of dtls_fingerprint in the call? */ + if (call->params->media_encryption == LinphoneMediaEncryptionDTLS) { + call->current_params->media_encryption=LinphoneMediaEncryptionDTLS; + } else { + call->current_params->media_encryption=LinphoneMediaEncryptionSRTP; + } + } } else { call->current_params->media_encryption=LinphoneMediaEncryptionNone; } @@ -1553,6 +1591,34 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ if (call->sessions[0].rtp_session==NULL){ call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6); rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); + if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + MSDtlsSrtpParams params; + unsigned char *certificate, *key; + memset(¶ms,0,sizeof(MSDtlsSrtpParams)); + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or defautl celui par default linphone-dtls-default-identity */ + /* This will parse the directory to find a matching fingerprint or generate it if not found */ + /* returned string must be freed */ + sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); + + if (key!= NULL && certificate!=NULL) { + params.pem_certificate = (char *)certificate; + params.pem_pkey = (char *)key; + params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ + audio_stream_enable_dtls(call->audiostream,¶ms); + ms_free(certificate); + ms_free(key); + } else { + ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); + /* TODO : check if encryption forced, if yes, stop call */ + } + #if TODO_DTLS_VIDEO_ENCRYPTION //VIDEO_ENABLED + if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + /*audio stream is already encrypted and video stream is active*/ + memset(¶ms,0,sizeof(MSDtlsSrtpParams)); + video_stream_enable_dtls(call->videostream,call->audiostream,¶ms); + } + #endif + } }else{ call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); } @@ -2241,9 +2307,32 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); } #endif - }else{ + } else if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + /* DTLS engine was already initialised during stream init. Before starting it we must be sure that the role(client or server) is set. + * Role may have already been set to server if we initiate the call and already received a packet from peer, in that case do nothing */ + SalDtlsRole salRole = call->resultdesc->streams[0].dtls_role; /* TODO: is streams[0] necessary the audiostream in the media description ? */ + if (salRole==SalDtlsRoleInvalid) { /* it's invalid in streams[0] but check also at session level */ + salRole = call->resultdesc->dtls_role; + } + + if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ + /* give the peer certificate fingerprint to dtls context */ + SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); + ms_dtls_srtp_set_peer_fingerprint(call->audiostream->ms.sessions.dtls_context, remote_desc->streams[0].dtls_fingerprint); + } else { + ms_warning("unable to start DTLS engine, Dtls role in resulting media description is invalid\n"); + } + if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */ + ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */ + ms_dtls_srtp_start(call->audiostream->ms.sessions.dtls_context); /* then start the engine, it will send the DTLS client Hello */ + } else if (salRole == SalDtlsRoleIsServer) { /* local endpoint is server */ + ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */ + /* no need to start engine, we are waiting for DTLS Client Hello */ + } + + } else { call->current_params->media_encryption=linphone_call_all_streams_encrypted(call) ? - LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; + LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { @@ -2968,7 +3057,12 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { if (ms->type==AudioStreamType) linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); - } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) + } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) { + if (ms->type==AudioStreamType) + linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted); + else if (ms->type==VideoStreamType) + propagate_encryption_changed(call); + }else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) { handle_ice_events(call, ev); } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3ead49966..a3fbb21c7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#include #include "mediastreamer2/mediastream.h" #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/msvolume.h" @@ -1487,6 +1488,11 @@ static void misc_config_read(LinphoneCore *lc) { lp_config_set_string(config,"misc","uuid",tmp); }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/ sal_set_uuid(lc->sal, uuid); + + /* DTLS: if media_encryption is DTLS, get or create the certificate directory */ + if (linphone_core_get_media_encryption(lc) == LinphoneMediaEncryptionDTLS) { + /* TODO*/ + } } static void linphone_core_start(LinphoneCore * lc) { @@ -6253,6 +6259,9 @@ static void linphone_core_uninit(LinphoneCore *lc) if(lc->zrtp_secrets_cache != NULL) { ms_free(lc->zrtp_secrets_cache); } + if(lc->user_certificates_path != NULL) { + ms_free(lc->user_certificates_path); + } if(lc->play_file!=NULL){ ms_free(lc->play_file); } @@ -6685,6 +6694,17 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ return lc->zrtp_secrets_cache; } +void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){ + if (lc->user_certificates_path != NULL) { + ms_free(lc->user_certificates_path); + } + lc->user_certificates_path = path ? ms_strdup(path) : NULL; +} + +const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){ + return lc->user_certificates_path; +} + LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) { MSList *calls; LinphoneCall *c; @@ -6745,6 +6765,8 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){ switch(menc){ case LinphoneMediaEncryptionSRTP: return "LinphoneMediaEncryptionSRTP"; + case LinphoneMediaEncryptionDTLS: + return "LinphoneMediaEncryptionDTLS"; case LinphoneMediaEncryptionZRTP: return "LinphoneMediaEncryptionZRTP"; case LinphoneMediaEncryptionNone: @@ -6761,6 +6783,8 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone switch(menc){ case LinphoneMediaEncryptionSRTP: return media_stream_srtp_supported(); + case LinphoneMediaEncryptionDTLS: + return ms_dtls_available(); case LinphoneMediaEncryptionZRTP: return ms_zrtp_available(); case LinphoneMediaEncryptionNone: @@ -6784,7 +6808,14 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption type="none"; ret=-1; }else type="zrtp"; + }else if (menc == LinphoneMediaEncryptionDTLS){ + if (!ms_dtls_available()){ + ms_warning("DTLS not supported by library."); + type="none"; + ret=-1; + }else type="dtls"; } + lp_config_set_string(lc->config,"sip","media_encryption",type); return ret; } @@ -6796,6 +6827,8 @@ LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) { return LinphoneMediaEncryptionNone; else if (strcmp(menc, "srtp")==0) return LinphoneMediaEncryptionSRTP; + else if (strcmp(menc, "dtls")==0) + return LinphoneMediaEncryptionDTLS; else if (strcmp(menc, "zrtp")==0) return LinphoneMediaEncryptionZRTP; else diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index add43e4a0..37c09e7b2 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -287,7 +287,8 @@ typedef enum _LinphoneAVPFMode LinphoneAVPFMode; enum _LinphoneMediaEncryption { LinphoneMediaEncryptionNone, /**< No media encryption is used */ LinphoneMediaEncryptionSRTP, /**< Use SRTP media encryption */ - LinphoneMediaEncryptionZRTP /**< Use ZRTP media encryption */ + LinphoneMediaEncryptionZRTP, /**< Use ZRTP media encryption */ + LinphoneMediaEncryptionDTLS /**< Use DTLS media encryption */ }; /** @@ -2908,6 +2909,22 @@ LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const */ LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); +/** + * Set the path to the directory storing the user's x509 certificates (used by dtls) + * @param[in] lc #LinphoneCore object + * @param[in] path The path to the directory to use to store the user's certificates. + * @ingroup initializing + */ +LINPHONE_PUBLIC void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path); + +/** + * Get the path to the directory storing the user's certificates. + * @param[in] lc #LinphoneCore object. + * @returns The path to the directory storing the user's certificates. + * @ingroup initializing + */ +LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCore *lc); + /** * Search from the list of current calls if a remote address match uri * @ingroup call_control diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index d7d2e6e84..9f2ce5f6b 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -315,6 +315,21 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, result->rtcp_xr.enabled = FALSE; } + // Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, get the remote fingerprint into the result + if ((local_offer->dtls_role!=SalDtlsRoleInvalid) && (remote_answer->dtls_role!=SalDtlsRoleInvalid) + &&(strlen(local_offer->dtls_fingerprint)>0) && (strlen(remote_answer->dtls_fingerprint)>0)) { + strcpy(result->dtls_fingerprint, remote_answer->dtls_fingerprint); + if (remote_answer->dtls_role==SalDtlsRoleIsClient) { + result->dtls_role = SalDtlsRoleIsServer; + } else { + result->dtls_role = SalDtlsRoleIsClient; + } + } else { + result->dtls_fingerprint[0] = '\0'; + result->dtls_role = SalDtlsRoleInvalid; + } + + return 0; } @@ -334,7 +349,9 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { if (local == remote) return TRUE; if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoUdpTlsRtpSavp) || (local == SalProtoUdpTlsRtpSavpf))) return TRUE; if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoUdpTlsRtpSavpf)) return TRUE; return FALSE; } @@ -368,6 +385,23 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); + // Handle dtls stream attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer + // Note: local description usually stores dtls config at session level which means it apply to all streams, check this too + if (((ls->dtls_role!=SalDtlsRoleInvalid) || (local_capabilities->dtls_role!=SalDtlsRoleInvalid)) && (rs->dtls_role!=SalDtlsRoleInvalid) + && ((strlen(ls->dtls_fingerprint)>0) || (strlen(local_capabilities->dtls_fingerprint)>0)) && (strlen(rs->dtls_fingerprint)>0)) { + if (strlen(ls->dtls_fingerprint)>0) { /* get the fingerprint in stream description */ + strcpy(result->streams[i].dtls_fingerprint, ls->dtls_fingerprint); + } else { /* get the fingerprint in session description */ + strcpy(result->streams[i].dtls_fingerprint, local_capabilities->dtls_fingerprint); + } + if (rs->dtls_role==SalDtlsRoleUnset) { + result->streams[i].dtls_role = SalDtlsRoleIsClient; + } + } else { + result->streams[i].dtls_fingerprint[0] = '\0'; + result->streams[i].dtls_role = SalDtlsRoleInvalid; + } + // Handle media RTCP XR attribute memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr)); if (rs->rtcp_xr.enabled == TRUE) { @@ -408,6 +442,18 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities strcpy(result->name,local_capabilities->name); + // Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer + if ((local_capabilities->dtls_role!=SalDtlsRoleInvalid) && (remote_offer->dtls_role!=SalDtlsRoleInvalid) + &&(strlen(local_capabilities->dtls_fingerprint)>0) && (strlen(remote_offer->dtls_fingerprint)>0)) { + strcpy(result->dtls_fingerprint, local_capabilities->dtls_fingerprint); + if (remote_offer->dtls_role==SalDtlsRoleUnset) { + result->dtls_role = SalDtlsRoleIsClient; + } + } else { + result->dtls_fingerprint[0] = '\0'; + result->dtls_role = SalDtlsRoleInvalid; + } + // Handle session RTCP XR attribute memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr)); if (remote_offer->rtcp_xr.enabled == TRUE) { diff --git a/coreapi/private.h b/coreapi/private.h index 8e1bfaf8a..8198e08af 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -241,6 +241,7 @@ struct _LinphoneCall{ char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/ belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/ + unsigned char *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */ bool_t refer_pending; bool_t expect_media_in_ack; bool_t audio_muted; @@ -734,6 +735,7 @@ struct _LinphoneCore MSList *hooks; LinphoneConference conf_ctx; char* zrtp_secrets_cache; + char* user_certificates_path; LinphoneVideoPolicy video_policy; bool_t use_files; bool_t apply_nat_settings; diff --git a/coreapi/sal.c b/coreapi/sal.c index b8395c897..5d43546be 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -194,13 +194,17 @@ bool_t sal_stream_description_active(const SalStreamDescription *sd) { } bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) { - return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf)); + return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoUdpTlsRtpSavpf)); } bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) { return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf)); } +bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoUdpTlsRtpSavp) || (sd->proto == SalProtoUdpTlsRtpSavpf)); +} + bool_t sal_media_description_has_avpf(const SalMediaDescription *md) { int i; if (md->nb_streams == 0) return FALSE; @@ -221,6 +225,16 @@ bool_t sal_media_description_has_srtp(const SalMediaDescription *md) { return TRUE; } +bool_t sal_media_description_has_dtls(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + /* static bool_t fmtp_equals(const char *p1, const char *p2){ if (p1 && p2 && strcmp(p1,p2)==0) return TRUE; @@ -607,8 +621,10 @@ const char* sal_media_proto_to_string(SalMediaProto type) { switch (type) { case SalProtoRtpAvp:return "RTP/AVP"; case SalProtoRtpSavp:return "RTP/SAVP"; + case SalProtoUdpTlsRtpSavp:return "UDP/TLS/RTP/SAVP"; case SalProtoRtpAvpf:return "RTP/AVPF"; case SalProtoRtpSavpf:return "RTP/SAVPF"; + case SalProtoUdpTlsRtpSavpf:return "UDP/TLS/RTP/SAVPF"; default: return "unknown"; } } diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 4fa0bd66b..0d6606aee 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -680,6 +680,12 @@ void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){ gtk_widget_hide(status_icon); gtk_widget_hide(verify_button); break; + case LinphoneMediaEncryptionDTLS: + gtk_widget_show_all(encryption_box); + gtk_label_set_markup(GTK_LABEL(label),_("Secured by DTLS")); + gtk_widget_hide(status_icon); + gtk_widget_hide(verify_button); + break; case LinphoneMediaEncryptionZRTP: { gchar *text=g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"),linphone_call_get_authentication_token(call)); diff --git a/gtk/main.c b/gtk/main.c index ea3078c9a..13e622969 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -172,9 +172,11 @@ static GOptionEntry linphone_options[]={ #ifndef WIN32 #define CONFIG_FILE ".linphonerc" #define SECRETS_FILE ".linphone-zidcache" +#define CERTIFICATES_PATH ".linphone-usr-crt" #else #define CONFIG_FILE "linphonerc" #define SECRETS_FILE "linphone-zidcache" +#define CERTIFICATES_PATH "linphone-usr-crt" #endif char *linphone_gtk_get_config_file(const char *filename){ @@ -279,6 +281,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); + gchar *user_certificates_dir=linphone_gtk_get_config_file(CERTIFICATES_PATH); vtable.global_state_changed=linphone_gtk_global_state_changed; vtable.call_state_changed=linphone_gtk_call_state_changed; @@ -316,6 +319,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); linphone_core_set_zrtp_secrets_file(the_core,secrets_file); g_free(secrets_file); + linphone_core_set_user_certificates_path(the_core,user_certificates_dir); + g_free(user_certificates_dir); linphone_core_enable_video_capture(the_core, TRUE); linphone_core_enable_video_display(the_core, TRUE); linphone_core_set_native_video_window_id(the_core,-1);/*don't create the window*/ diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 677fe5f06..c075fe91c 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1199,11 +1199,13 @@ static void linphone_gtk_media_encryption_changed(GtkWidget *combo){ if (strcasecmp(selected,"SRTP")==0){ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,TRUE); + }else if (strcasecmp(selected,"DTLS")==0){ + linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionDTLS); + linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); }else if (strcasecmp(selected,"ZRTP")==0){ linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); - } - else { + } else { linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone); linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE); } @@ -1219,7 +1221,7 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo"); bool_t no_enc=TRUE; - int srtp_id=-1,zrtp_id=-1; + int srtp_id=-1,zrtp_id=-1,dtls_id=-1; GtkTreeModel *model; GtkListStore *store; GtkTreeIter iter; @@ -1239,12 +1241,26 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ srtp_id=1; no_enc=FALSE; } + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionDTLS)){ + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,_("DTLS"),-1); + if (srtp_id!=-1) dtls_id=2; + else dtls_id=1; + no_enc=FALSE; + } if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){ gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("ZRTP"),-1); no_enc=FALSE; - if (srtp_id!=-1) zrtp_id=2; - else zrtp_id=1; + if (srtp_id!=-1) { + if (dtls_id!=-1) + zrtp_id=3; + else zrtp_id=2; + } else { + if (dtls_id!=-1) + zrtp_id=2; + else zrtp_id=1; + } } if (no_enc){ /*hide this setting*/ @@ -1264,6 +1280,12 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); } break; + case LinphoneMediaEncryptionDTLS: + if (dtls_id!=-1) { + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),dtls_id); + linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE); + } + break; case LinphoneMediaEncryptionZRTP: if (zrtp_id!=-1) { gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id); diff --git a/include/sal/sal.h b/include/sal/sal.h index 5fb0fbd92..a4c155b99 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -129,6 +129,8 @@ typedef enum{ SalProtoRtpSavp, SalProtoRtpAvpf, SalProtoRtpSavpf, + SalProtoUdpTlsRtpSavp, + SalProtoUdpTlsRtpSavpf, SalProtoOther }SalMediaProto; const char* sal_media_proto_to_string(SalMediaProto type); @@ -182,6 +184,13 @@ typedef struct SalSrtpCryptoAlgo { #define SAL_CRYPTO_ALGO_MAX 4 +typedef enum { + SalDtlsRoleInvalid, + SalDtlsRoleIsServer, + SalDtlsRoleIsClient, + SalDtlsRoleUnset +} SalDtlsRole; + typedef struct SalStreamDescription{ char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/ SalMediaProto proto; @@ -207,6 +216,8 @@ typedef struct SalStreamDescription{ bool_t ice_mismatch; bool_t ice_completed; bool_t pad[2]; + char dtls_fingerprint[256]; + SalDtlsRole dtls_role; } SalStreamDescription; const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc); @@ -231,6 +242,8 @@ typedef struct SalMediaDescription{ bool_t ice_lite; bool_t ice_completed; bool_t pad[2]; + char dtls_fingerprint[256]; + SalDtlsRole dtls_role; } SalMediaDescription; typedef struct SalMessage{ @@ -265,8 +278,10 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ bool_t sal_stream_description_active(const SalStreamDescription *sd); bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd); bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd); +bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd); bool_t sal_media_description_has_avpf(const SalMediaDescription *md); bool_t sal_media_description_has_srtp(const SalMediaDescription *md); +bool_t sal_media_description_has_dtls(const SalMediaDescription *md); int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); @@ -510,6 +525,18 @@ void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, */ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd); +/** + * Parse a directory for files containing certificate with the given subject CNAME + * @param[out] certificate_pem the address of a string to store the certificate in PEM format. To be freed by caller + * @param[out] key_pem the address of a string to store the key in PEM format. To be freed by caller + * @param[in] path directory to parse + * @param[in] subject subject CNAME + * @param[in] format either PEM or DER + * @param[in] generate_certificate if true, if matching certificate and key can't be found, generate it and store it into the given dir, filename will be subject.pem + * @param[in] generate_dtls_fingerprint if true and we have a certificate, generate the dtls fingerprint as described in rfc4572 + */ +void sal_certificates_chain_parse_directory(unsigned char **certificate_pem, unsigned char **key_pem, unsigned char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint); + void sal_certificates_chain_delete(SalCertificatesChain *chain); void sal_signing_key_delete(SalSigningKey *key); diff --git a/mediastreamer2 b/mediastreamer2 index 90bad6f9e..dd1d93944 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 90bad6f9e48f7d18cba2d1a50c4e55fbc6b3c686 +Subproject commit dd1d93944369d5e19808109ea94b51f28b0e5a92 diff --git a/oRTP b/oRTP index 5333d998c..29802b08d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 5333d998c8eaf3c43e66c4a5335c0606c8dea3df +Subproject commit 29802b08dac2de2f320db28249d5d459a47507e8 From 94b4002cbf36a979a55fe33d59a6773dfb8bf598 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Dec 2014 08:35:42 +0100 Subject: [PATCH 02/20] fix ice parsing --- coreapi/bellesip_sal/sal_sdp.c | 7 ++++--- coreapi/misc.c | 4 ++-- mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index cc6db442f..63a735717 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -489,10 +489,11 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_ if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; - int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", - candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, + char proto[4]; + int nb = sscanf(value, "%s %u %3s %u %s %d typ %s raddr %s rport %d", + candidate->foundation, &candidate->componentID, proto, &candidate->priority, candidate->addr, &candidate->port, candidate->type, candidate->raddr, &candidate->rport); - if ((nb == 6) || (nb == 8)) nb_ice_candidates++; + if (strcasecmp("udp",proto)==0 && ((nb == 7) || (nb == 9))) nb_ice_candidates++; else memset(candidate, 0, sizeof(*candidate)); } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { SalIceRemoteCandidate candidate; diff --git a/coreapi/misc.c b/coreapi/misc.c index 50ebe68ee..6ed3bb709 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -896,8 +896,8 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { if (ice_restarted == FALSE - && ice_check_list_remote_ufrag(cl) - && ice_check_list_remote_pwd(cl)) { + && ice_check_list_get_remote_ufrag(cl) + && ice_check_list_get_remote_pwd(cl)) { /* restart onlu if remote ufrag/paswd was already set*/ ice_session_restart(call->ice_session); ice_restarted = TRUE; diff --git a/mediastreamer2 b/mediastreamer2 index 6ef87545a..4b87cdd23 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6ef87545afabc2f66e28b1092bc490cbe7a994c3 +Subproject commit 4b87cdd23ca14e9b39212b73f0a545d4f89a9d56 From 0cd96056444c4abcec9acacdcd7099421bf71c90 Mon Sep 17 00:00:00 2001 From: johan Date: Thu, 11 Dec 2014 14:52:59 +0100 Subject: [PATCH 03/20] Add Dtls proto when looking for best stream in media description --- coreapi/sal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/sal.c b/coreapi/sal.c index 5d43546be..6aa444947 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -120,7 +120,9 @@ SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMedia } SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) { - SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); + SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type); From 20fe706f7d4e5f3832a9e3fd15f31c533454dd33 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 11 Dec 2014 14:56:28 +0100 Subject: [PATCH 04/20] check if number of ice candidate does not exceed stirage size --- coreapi/bellesip_sal/sal_sdp.c | 4 +++- include/sal/sal.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 63a735717..34720f5b4 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -487,7 +487,9 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_ att_name = belle_sdp_attribute_get_name(attribute); value = belle_sdp_attribute_get_value(attribute); - if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { + if ( (nb_ice_candidates < sizeof (stream->ice_candidates)/sizeof(SalIceCandidate)) + && (keywordcmp("candidate", att_name) == 0) + && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; char proto[4]; int nb = sscanf(value, "%s %u %3s %u %s %d typ %s raddr %s rport %d", diff --git a/include/sal/sal.h b/include/sal/sal.h index 47a5f71fc..43284179e 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -164,7 +164,7 @@ typedef struct SalIceCandidate { int rport; } SalIceCandidate; -#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10 +#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 20 typedef struct SalIceRemoteCandidate { char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN]; From 45e1da743ce82fa35cd357b7c51cdf410aba83fd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Dec 2014 15:47:09 +0100 Subject: [PATCH 05/20] make sure rtp destination is change as soon as ice is terminated --- coreapi/linphonecall.c | 26 ++++++++++++++++++++++++++ mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ded5c53e4..504a6c214 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2906,6 +2906,31 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ linphone_core_play_named_tone(lc,LinphoneToneCallLost); } +static void change_ice_media_destinations(LinphoneCall *call) { + const char *rtp_addr; + const char *rtcp_addr; + int rtp_port; + int rtcp_port; + bool_t result; + + if (call->audiostream && ice_session_check_list(call->ice_session, 0)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 0), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (result == TRUE) { + ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + } + } +#ifdef VIDEO_ENABLED + if (call->videostream && ice_session_check_list(call->ice_session, 1)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 1), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (result == TRUE) { + ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + } + } +#endif +} + static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ OrtpEventType evt=ortp_event_get_type(ev); OrtpEventData *evd=ortp_event_get_data(ev); @@ -2923,6 +2948,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ if (ice_session_role(call->ice_session) == IR_Controlling) { linphone_core_update_call(call->core, call, params); } + change_ice_media_destinations(call); break; case IS_Failed: if (ice_session_has_completed_check_list(call->ice_session) == TRUE) { diff --git a/mediastreamer2 b/mediastreamer2 index 4b87cdd23..f47428f68 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4b87cdd23ca14e9b39212b73f0a545d4f89a9d56 +Subproject commit f47428f6880ec1a9afd5206ff84646168595cf19 diff --git a/oRTP b/oRTP index 1ad385634..2c94d5783 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 1ad38563419acb9665af4bf65543ccdcfd76fda6 +Subproject commit 2c94d5783a48efda91191c922e077560f3df5876 From 52dc1aacdcb2b6e01252c6656f0eb92c4d250621 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Dec 2014 16:21:29 +0100 Subject: [PATCH 06/20] finilize stun files move from ortp to ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f47428f68..32fcc17e3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f47428f6880ec1a9afd5206ff84646168595cf19 +Subproject commit 32fcc17e34a0a5559b7bc154116aa46d72c03a1b From 25532e628544475d0b044fd7c35969c4ef1b6d6d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Dec 2014 16:56:13 +0100 Subject: [PATCH 07/20] ms2:stun api shall be public --- coreapi/misc.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 6ed3bb709..c238b13a0 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif /*_WIN32_WCE*/ #undef snprintf -#include +#include #ifdef HAVE_GETIFADDRS #include diff --git a/mediastreamer2 b/mediastreamer2 index 32fcc17e3..d7e7fb21f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 32fcc17e34a0a5559b7bc154116aa46d72c03a1b +Subproject commit d7e7fb21f2c45e32e641ca4349ca5f1242ee4fe8 From 2a5e6eafb9ac1049779611c1bde64af80d1fe39e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Dec 2014 17:04:44 +0100 Subject: [PATCH 08/20] fix stun_tester.c --- tester/stun_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 99b1190ed..58a069f3d 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -21,7 +21,7 @@ #include "linphonecore.h" #include "private.h" #include "liblinphone_tester.h" -#include "ortp/stun.h" +#include "mediastreamer2/stun.h" #include "ortp/port.h" From 39399545003c1487cd6e6aec5aa4e24a387b85f7 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 15 Dec 2014 13:04:40 +0100 Subject: [PATCH 09/20] add ssrc attribute in case of srtp dtls --- coreapi/bellesip_sal/sal_sdp.c | 12 +++++++ coreapi/linphonecall.c | 62 +++++++++++++++++++++++++--------- coreapi/offeranswer.c | 6 ++++ coreapi/private.h | 1 + include/sal/sal.h | 2 ++ 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 34720f5b4..67a583a31 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -236,6 +236,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session /* insert DTLS session attribute if needed */ if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) { + char* ssrc_attribute = ms_strdup_printf("%u cname:%s",htonl(stream->rtp_ssrc),stream->rtcp_cname); if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) { switch(stream->dtls_role) { case SalDtlsRoleIsClient: @@ -251,6 +252,10 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session } belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint)); } + + belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); + ms_free(ssrc_attribute); + } switch ( stream->dir ) { @@ -321,6 +326,13 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session belle_sip_object_unref((belle_sip_object_t*)media_attribute); } } + /* + * rfc5576 + * 4.1. The "ssrc" Media Attribute + * is the synchronization source (SSRC) ID of the + * source being described, interpreted as a 32-bit unsigned integer in + * network byte order and represented in decimal.*/ + belle_sdp_session_description_add_media_description(session_desc, media_desc); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 504a6c214..964f6e30f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -448,6 +448,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; + if (call->audiostream && call->audiostream->ms.sessions.rtp_session) { + char* me = linphone_address_as_string_uri_only(call->me); + md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session); + strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname)); + ms_free(me); + } + else + ms_warning("Cannot get audio local ssrc for call [%p]",call); nb_active_streams++; if (call->params->has_video){ @@ -460,6 +468,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; + if (call->videostream && call->videostream->ms.sessions.rtp_session) { + char* me = linphone_address_as_string_uri_only(call->me); + md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session); + strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname)); + ms_free(me); + } + else + ms_warning("Cannot get video local ssrc for call [%p]",call); nb_active_streams++; } @@ -831,6 +847,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro ms_warning("ICE not supported for incoming INVITE without SDP."); } } + + + if (linphone_call_log_get_dir(call->log) == LinphoneCallIncoming) + call->me=linphone_call_log_get_to_address(call->log); + else + call->me=linphone_call_log_get_from_address(call->log); + + /*reserve the sockets immediately*/ linphone_call_init_media_streams(call); switch (fpol) { @@ -1115,6 +1139,11 @@ static void linphone_call_destroy(LinphoneCall *obj){ linphone_call_params_unref(obj->remote_params); obj->remote_params=NULL; } + if (obj->me) { + linphone_address_destroy(obj->me); + obj->me = NULL; + } + sal_error_info_reset(&obj->non_op_error); } @@ -1587,10 +1616,16 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ AudioStream *audiostream; const char *location; int dscp; + char rtcp_tool[128]={0}; + char* cname; + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->audiostream != NULL) return; if (call->sessions[0].rtp_session==NULL){ call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6); + cname = linphone_address_as_string_uri_only(call->me); + audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); + ms_free(cname); rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { MSDtlsSrtpParams params; @@ -1684,6 +1719,9 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; + char* cname; + char rtcp_tool[128]; + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->videostream == NULL){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); @@ -1692,10 +1730,14 @@ void linphone_call_init_video_stream(LinphoneCall *call){ if (call->sessions[1].rtp_session==NULL){ call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6); + cname = linphone_address_as_string_uri_only(call->me); + video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); + ms_free(cname); rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); }else{ call->videostream=video_stream_new_with_sessions(&call->sessions[1]); } + if (call->media_ports[1].rtp_port==-1){ port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session); } @@ -2008,7 +2050,7 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca rtp_session_configure_rtcp_xr(session, ¤tconfig); } -static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){ +static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){ LinphoneCore *lc=call->core; LpConfig* conf; int used_pt=-1; @@ -2100,7 +2142,6 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna } } configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); - audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); audio_stream_start_full( call->audiostream, call->audio_profile, @@ -2136,16 +2177,14 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna } } -static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){ +static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inputs_muted){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; - char rtcp_tool[128]={0}; const SalStreamDescription *vstream; MSFilter* source = NULL; bool_t reused_preview = FALSE; - snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); /* shutdown preview */ if (lc->previewstream!=NULL) { @@ -2225,7 +2264,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_set_direction (call->videostream, dir); ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); video_stream_set_device_rotation(call->videostream, lc->device_rotation); - video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0)); if( lc->video_conf.reuse_preview_source && source ){ ms_message("video_stream_start_with_source kept: %p", source); @@ -2257,8 +2295,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ LinphoneCore *lc=call->core; - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); - char *cname; bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); #ifdef VIDEO_ENABLED const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo); @@ -2271,8 +2307,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut ms_fatal("start_media_stream() called without prior init !"); return; } - cname=linphone_address_as_string_uri_only(me); - #if defined(VIDEO_ENABLED) if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ /*when video is used, do not make adaptive rate control on audio, it is stupid.*/ @@ -2283,12 +2317,12 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc)); if (call->audiostream!=NULL) { - linphone_call_start_audio_stream(call,cname,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc); + linphone_call_start_audio_stream(call,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc); } call->current_params->has_video=FALSE; if (call->videostream!=NULL) { if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream); - linphone_call_start_video_stream(call,cname,all_inputs_muted); + linphone_call_start_video_stream(call,all_inputs_muted); } call->all_muted=all_inputs_muted; @@ -2340,10 +2374,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut ice_session_start_connectivity_checks(call->ice_session); } - goto end; - end: - ms_free(cname); - linphone_address_destroy(me); } void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 9f2ce5f6b..755c6bcd7 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -247,6 +247,9 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) result->rtp_port = 0; } + result->rtp_ssrc=local_offer->rtp_ssrc; + strncpy(result->rtcp_cname,local_offer->rtcp_cname,sizeof(result->rtcp_cname)); + } @@ -281,6 +284,9 @@ static void initiate_incoming(const SalStreamDescription *local_cap, memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); strcpy(result->name,local_cap->name); + result->rtp_ssrc=local_cap->rtp_ssrc; + strncpy(result->rtcp_cname,local_cap->rtcp_cname,sizeof(result->rtcp_cname)); + } /** diff --git a/coreapi/private.h b/coreapi/private.h index 62a31fc74..0b929929f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -213,6 +213,7 @@ struct _LinphoneCall{ struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; + LinphoneAddress *me; /*Either from or to based on call dir*/ SalOp *op; SalOp *ping_op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 43284179e..b7238b9b4 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -202,6 +202,8 @@ typedef struct SalStreamDescription{ char proto_other[32]; char rtp_addr[64]; char rtcp_addr[64]; + unsigned int rtp_ssrc; + char rtcp_cname[255]; int rtp_port; int rtcp_port; MSList *payloads; // Date: Mon, 15 Dec 2014 16:02:27 +0100 Subject: [PATCH 10/20] various ice fix for better interwork --- coreapi/bellesip_sal/sal_sdp.c | 2 +- coreapi/linphonecall.c | 3 ++- mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 67a583a31..6023ef7e4 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -253,7 +253,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint)); } - belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); + /*belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute));*/ ms_free(ssrc_attribute); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 964f6e30f..131a3a933 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -854,6 +854,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro else call->me=linphone_call_log_get_from_address(call->log); + linphone_address_ref(call->me); /*reserve the sockets immediately*/ linphone_call_init_media_streams(call); @@ -1140,7 +1141,7 @@ static void linphone_call_destroy(LinphoneCall *obj){ obj->remote_params=NULL; } if (obj->me) { - linphone_address_destroy(obj->me); + linphone_address_unref(obj->me); obj->me = NULL; } diff --git a/mediastreamer2 b/mediastreamer2 index d7e7fb21f..d2d7291eb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d7e7fb21f2c45e32e641ca4349ca5f1242ee4fe8 +Subproject commit d2d7291eb0dece51a68dfd2b8d005618e945c73b diff --git a/oRTP b/oRTP index 2c94d5783..f4d6250a9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2c94d5783a48efda91191c922e077560f3df5876 +Subproject commit f4d6250a9de606025669f6caa6819c7d8d0cd77d From 551cb17583647e8a96f3831e8c6504d3b9808bf4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Dec 2014 11:22:14 +0100 Subject: [PATCH 11/20] fix crash in outgoing call case --- coreapi/linphonecall.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 131a3a933..530706ada 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -603,6 +603,11 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->current_params = linphone_call_params_new(); call->current_params->media_encryption=LinphoneMediaEncryptionNone; call->dtls_certificate_fingerprint = NULL; + if (call->dir == LinphoneCallIncoming) + call->me=to; + else + call->me=from; + linphone_address_ref(call->me); linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); @@ -848,14 +853,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } } - - if (linphone_call_log_get_dir(call->log) == LinphoneCallIncoming) - call->me=linphone_call_log_get_to_address(call->log); - else - call->me=linphone_call_log_get_from_address(call->log); - - linphone_address_ref(call->me); - /*reserve the sockets immediately*/ linphone_call_init_media_streams(call); switch (fpol) { From d7437ef1f5cd41b582b36ac9efc51d0b5a3506bc Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 22 Dec 2014 21:47:35 +0100 Subject: [PATCH 12/20] enable ice with tunnel --- coreapi/TunnelManager.cc | 15 ++++++------- coreapi/TunnelManager.hh | 1 + coreapi/callbacks.c | 2 +- coreapi/linphonecall.c | 40 +++++++++++++++++++--------------- coreapi/linphonecore.c | 21 +++--------------- coreapi/private.h | 14 ------------ mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 43 ++++++++++++++++++++++++++----------- tester/liblinphone_tester.h | 1 + tester/transport_tester.c | 34 +++++++++++++++++++++++++++++ 11 files changed, 101 insertions(+), 74 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 53d7f288f..bbce579a3 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -16,9 +16,6 @@ #include "ortp/rtpsession.h" #include "linphonecore.h" #include "linphonecore_utils.h" -#ifndef USE_BELLESIP -#include "eXosip2/eXosip_transport_hook.h" -#endif #include "private.h" #ifdef ANDROID @@ -97,7 +94,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){ void TunnelManager::startClient() { ms_message("TunnelManager: Starting tunnel client"); - mTunnelClient = new TunnelClient(); + mTunnelClient = new TunnelClient(TRUE); mTunnelClient->setCallback((TunnelClientController::StateCallback)tunnelCallback,this); list::iterator it; for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){ @@ -122,18 +119,16 @@ int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags } int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){ + memset(&msg->recv_addr,0,sizeof(msg->recv_addr)); int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen); + //to make ice happy + inet_aton(((TunnelManager*)((TunnelSocket*)t->data)->getUserPointer())->mLocalAddr,&msg->recv_addr.addr.ipi_addr); if (err>0) return err; return 0; } - TunnelManager::TunnelManager(LinphoneCore* lc) : mCore(lc), -#ifndef USE_BELLESIP - mSipSocket(NULL), - mExosipTransport(NULL), -#endif mMode(LinphoneTunnelModeDisable), mState(disabled), mTunnelizeSipPackets(true), @@ -153,6 +148,7 @@ TunnelManager::TunnelManager(LinphoneCore* lc) : mVTable = linphone_core_v_table_new(); mVTable->network_reachable = networkReachableCb; linphone_core_add_listener(mCore, mVTable); + linphone_core_get_local_ip_for(AF_INET, NULL, mLocalAddr); } TunnelManager::~TunnelManager(){ @@ -371,6 +367,7 @@ void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) { tunnel->startAutoDetection(); tunnel->mState = autodetecting; } + linphone_core_get_local_ip_for(AF_INET, NULL,tunnel->mLocalAddr); } bool TunnelManager::startAutoDetection() { diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index 0af89fce9..fdda28beb 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -200,6 +200,7 @@ namespace belledonnecomm { LinphoneRtpTransportFactories mTransportFactories; Mutex mMutex; std::queue mEvq; + char mLocalAddr[64]; }; /** diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index c43c84479..fe65a4282 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -321,7 +321,7 @@ static void call_received(SalOp *h){ linphone_core_add_call(lc,call); linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */ - if ((_linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) { + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) { /* Defer ringing until the end of the ICE candidates gathering process. */ ms_message("Defer ringing to gather ICE candidates"); return; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 530706ada..c5c7e6a7a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -698,7 +698,7 @@ static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress } if (res != NULL) freeaddrinfo(res); } - if (_linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress + if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress && (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){ strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE); return; @@ -735,11 +735,11 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_call_init_common(call,from,to); call->params = linphone_call_params_copy(params); - if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); ice_session_set_role(call->ice_session, IR_Controlling); } - if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { call->ping_time=linphone_core_run_stun_tests(call->core,call); } #ifdef BUILD_UPNP @@ -841,7 +841,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. linphone_call_set_compatible_incoming_call_parameters(call, md); } - fpol=_linphone_core_get_firewall_policy(call->core); + fpol=linphone_core_get_firewall_policy(call->core); /*create the ice session now if ICE is required*/ if (fpol==LinphonePolicyUseIce){ if (md){ @@ -1557,7 +1557,7 @@ static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){ MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; - if ((_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ IceCheckList *cl; rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE); rtp_session_set_symmetric_rtp(ms->sessions.rtp_session, FALSE); @@ -1578,7 +1578,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ SalMediaDescription *remote = NULL; bool_t has_video=FALSE; - if ((_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ if (incoming_offer){ remote=sal_call_get_remote_media_description(call->op); has_video=call->params->has_video && linphone_core_media_description_contains_video_stream(remote); @@ -1699,13 +1699,16 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc)); if (lc->rtptf){ - RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port); - RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port); RtpTransport *meta_rtp; RtpTransport *meta_rtcp; - meta_rtp_transport_new(&meta_rtp,TRUE,artp, 0); - meta_rtp_transport_new(&meta_rtcp,FALSE,artcp, 0); - rtp_session_set_transports(audiostream->ms.sessions.rtp_session,meta_rtp,meta_rtcp); + + rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); + if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port)); + } + if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port)); + } } call->audiostream_app_evq = ortp_ev_queue_new(); @@ -1748,13 +1751,16 @@ void linphone_call_init_video_stream(LinphoneCall *call){ video_stream_set_display_filter_name(call->videostream,display_filter); video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); if (lc->rtptf){ - RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port); - RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port); RtpTransport *meta_rtp; RtpTransport *meta_rtcp; - meta_rtp_transport_new(&meta_rtp,TRUE,vrtp, 0); - meta_rtp_transport_new(&meta_rtcp,FALSE,vrtcp, 0); - rtp_session_set_transports(call->videostream->ms.sessions.rtp_session,meta_rtp,meta_rtcp); + + rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); + if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port)); + } + if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port)); + } } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); @@ -3262,7 +3268,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , const char *localip=call->localip; /* first use user's supplied ip address if asked*/ - if (_linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ ctt=linphone_core_get_primary_contact_parsed(lc); linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); ret=ctt; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c3e526db9..66bef51c8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3137,12 +3137,12 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const call->log->start_date_time=ms_time(NULL); linphone_call_init_media_streams(call); - if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { /* Defer the start of the call after the ICE gathering process. */ if (linphone_call_prepare_ice(call,FALSE)==1) defer=TRUE; } - else if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { + else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { #ifdef BUILD_UPNP if (linphone_core_update_upnp(lc,call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ @@ -4965,23 +4965,8 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy if (linphone_core_ready(lc)) lp_config_set_string(lc->config,"net","firewall_policy",policy); } - -LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) { - return _linphone_core_get_firewall_policy_with_lie(lc, FALSE); -} - -LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc) { - return _linphone_core_get_firewall_policy_with_lie(lc, TRUE); -} - -LinphoneFirewallPolicy _linphone_core_get_firewall_policy_with_lie(const LinphoneCore *lc, bool_t lie){ +LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ const char *policy; - if(lie) { - LinphoneTunnel *tunnel = linphone_core_get_tunnel(lc); - if(tunnel != NULL && linphone_tunnel_get_mode(tunnel)) { - return LinphonePolicyNoFirewall; - } - } policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL); if ((policy == NULL) || (strcmp(policy, "0") == 0)) return LinphonePolicyNoFirewall; diff --git a/coreapi/private.h b/coreapi/private.h index 0b929929f..4d94267c2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -298,20 +298,6 @@ void linphone_core_update_proxy_register(LinphoneCore *lc); void linphone_core_refresh_subscribes(LinphoneCore *lc); int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error); const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); -/** - * @brief Equivalent to _linphone_core_get_firewall_policy_with_lie(lc, TRUE) - * @param lc LinphoneCore instance - * @return Fairewall policy - */ -LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc); -/** - * @brief Get the firwall policy which has been set. - * @param lc Instance of LinphoneCore - * @param lie If true, the configured firewall policy will be returned only if no tunnel are enabled. - * Otherwise, NoFirewallPolicy value will be returned. - * @return The firewall policy - */ -LinphoneFirewallPolicy _linphone_core_get_firewall_policy_with_lie(const LinphoneCore *lc, bool_t lie); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); diff --git a/mediastreamer2 b/mediastreamer2 index d2d7291eb..87cf71d76 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d2d7291eb0dece51a68dfd2b8d005618e945c73b +Subproject commit 87cf71d765ae035ad5a1b6bdcaf2970410459c2d diff --git a/oRTP b/oRTP index f4d6250a9..227f06f72 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit f4d6250a9de606025669f6caa6819c7d8d0cd77d +Subproject commit 227f06f7256302404e29d2e2ab40dde00c5d1aca diff --git a/tester/call_tester.c b/tester/call_tester.c index 4e8a323c3..8620485c7 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -32,7 +32,7 @@ #endif static void srtp_call(void); -static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); + static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); static char *create_filepath(const char *dir, const char *filename, const char *ext); @@ -1978,14 +1978,14 @@ static void simple_conference_with_ice(void) { } static void srtp_call() { - call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); } static void zrtp_call() { - call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); } static void zrtp_video_call() { - call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall); + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); } static void call_with_declined_srtp(void) { @@ -2132,13 +2132,31 @@ end: } -static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) { +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (enable_relay) { linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); } + if (enable_tunnel) { + int i; + LinphoneTunnelConfig * tunnel_config = linphone_tunnel_config_new(); + linphone_tunnel_config_set_host(tunnel_config,"tunnel.linphone.org"); + linphone_tunnel_config_set_port(tunnel_config,443); + linphone_tunnel_add_server(linphone_core_get_tunnel(marie->lc),tunnel_config); + linphone_tunnel_enable_sip(linphone_core_get_tunnel(marie->lc),FALSE); + linphone_tunnel_set_mode(linphone_core_get_tunnel(marie->lc),LinphoneTunnelModeEnable); + for (i=0;i<10;i++) { + if (linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))) { + break; + } + linphone_core_iterate(marie->lc); + ms_usleep(200000); + } + CU_ASSERT_TRUE(linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))); + + } if (linphone_core_media_encryption_supported(marie->lc,mode)) { linphone_core_set_media_encryption(marie->lc,mode); linphone_core_set_media_encryption(pauline->lc,mode); @@ -2172,7 +2190,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e } if (policy == LinphonePolicyUseIce) - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); #ifdef VIDEO_ENABLED if (enable_video) { int i=0; @@ -2185,7 +2203,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e add_video(pauline,marie); if (policy == LinphonePolicyUseIce) - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection)); liblinphone_tester_check_rtcp(marie,pauline); /*wait for ice to found the direct path*/ @@ -2208,25 +2226,24 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } - #ifdef VIDEO_ENABLED static void srtp_video_ice_call(void) { - call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_video_ice_call(void) { - call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE); } #endif static void srtp_ice_call(void) { - call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_ice_call(void) { - call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE); } static void zrtp_ice_call_with_relay(void) { - call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce); + call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce,FALSE); } static void early_media_call(void) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 2c926b27d..0c4e658c5 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -304,5 +304,6 @@ void cunit_android_trace_handler(int level, const char *fmt, va_list args) ; #endif int liblinphone_tester_fprintf(FILE * stream, const char * format, ...); +void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel); #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/transport_tester.c b/tester/transport_tester.c index fdc4a194f..c44f84547 100644 --- a/tester/transport_tester.c +++ b/tester/transport_tester.c @@ -59,6 +59,8 @@ static char* get_public_contact_ip(LinphoneCore* lc) { ms_free(contact); return ms_strdup(contact_host_ip); } + + static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption) { if (linphone_core_tunnel_available()){ LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc"); @@ -131,6 +133,7 @@ static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with } } + static void call_with_tunnel(void) { call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone); } @@ -151,12 +154,43 @@ static void call_with_tunnel_auto_without_sip_with_srtp(void) { call_with_transport_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP); } +#ifdef VIDEO_ENABLED +static void tunnel_srtp_video_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); +} +static void tunnel_zrtp_video_ice_call(void) { + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE); +} +static void tunnel_video_ice_call(void) { + call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE); +} +#endif + +static void tunnel_srtp_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); +} + +static void tunnel_zrtp_ice_call(void) { + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE); +} + +static void tunnel_ice_call(void) { + call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE); +} test_t transport_tests[] = { { "Tunnel only", call_with_tunnel }, { "Tunnel with SRTP", call_with_tunnel_srtp }, { "Tunnel without SIP", call_with_tunnel_without_sip }, { "Tunnel in automatic mode", call_with_tunnel_auto }, { "Tunnel in automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp }, + { "Tunnel ice call", tunnel_ice_call }, + { "Tunnel SRTP ice call", tunnel_srtp_ice_call }, + { "Tunnel ZRTP ice call", tunnel_zrtp_ice_call }, +#ifdef VIDEO_ENABLED + { "Tunnel ice video call", tunnel_video_ice_call }, + { "Tunnel SRTP ice video call", tunnel_srtp_video_ice_call }, + { "Tunnel ZRTP ice video call", tunnel_zrtp_video_ice_call }, +#endif }; test_suite_t transport_test_suite = { From 7fe891b4ae172340cb6f62ce34e0f56543ecbc5e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 27 Dec 2014 19:45:19 +0100 Subject: [PATCH 13/20] add ice option to enable backward compatibility with previous version of ice --- coreapi/linphonecall.c | 4 ++++ mediastreamer2 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c5c7e6a7a..0f2f02383 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -737,6 +737,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); + /*for backward compatibility purposes, shall be enabled by default in futur*/ + ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0)); ice_session_set_role(call->ice_session, IR_Controlling); } if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { @@ -846,6 +848,8 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro if (fpol==LinphonePolicyUseIce){ if (md){ call->ice_session = ice_session_new(); + /*for backward compatibility purposes, shall be enabled by default in futur*/ + ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0)); ice_session_set_role(call->ice_session, IR_Controlled); }else{ fpol=LinphonePolicyNoFirewall; diff --git a/mediastreamer2 b/mediastreamer2 index 87cf71d76..08ed3f8a6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 87cf71d765ae035ad5a1b6bdcaf2970410459c2d +Subproject commit 08ed3f8a65ad830baa1023e5c0d3ec9e5421ef32 From c2f64f76d3ad9affaea81d475b791b432cc9d843 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 6 Jan 2015 15:35:56 +0100 Subject: [PATCH 14/20] MS2:fix compilation issue --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c837c019d..bbe9f1f77 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c837c019d5b1ff5e6ba35ba76e6d9b9ad5d1cd51 +Subproject commit bbe9f1f77ce7ae83de3cd3baabc89775a361c53a From 5fdf3b82baca844b9706380e732f412536e619db Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 8 Jan 2015 12:56:10 +0100 Subject: [PATCH 15/20] Enable DTLS-SRTP protection on video stream --- coreapi/linphonecall.c | 58 ++++++++++++++++++++++++++++++++++-------- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index bc7a8c9ee..2336f6498 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -159,12 +159,12 @@ static void propagate_encryption_changed(LinphoneCall *call){ call->current_params->media_encryption=LinphoneMediaEncryptionNone; linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token); } else { - ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); if (call->auth_token) {/* ZRTP only is using auth_token */ call->current_params->media_encryption=LinphoneMediaEncryptionZRTP; } else { /* otherwise it must be DTLS as SDES doesn't go through this function */ call->current_params->media_encryption=LinphoneMediaEncryptionDTLS; } + ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token); } } @@ -1634,7 +1634,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ MSDtlsSrtpParams params; char *certificate, *key; memset(¶ms,0,sizeof(MSDtlsSrtpParams)); - /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or defautl celui par default linphone-dtls-default-identity */ + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ /* This will parse the directory to find a matching fingerprint or generate it if not found */ /* returned string must be freed */ sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); @@ -1650,13 +1650,6 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); /* TODO : check if encryption forced, if yes, stop call */ } - #if TODO_DTLS_VIDEO_ENCRYPTION //VIDEO_ENABLED - if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { - /*audio stream is already encrypted and video stream is active*/ - memset(¶ms,0,sizeof(MSDtlsSrtpParams)); - video_stream_enable_dtls(call->videostream,call->audiostream,¶ms); - } - #endif } }else{ call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); @@ -1742,6 +1735,29 @@ void linphone_call_init_video_stream(LinphoneCall *call){ video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); ms_free(cname); rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); + + if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + MSDtlsSrtpParams params; + char *certificate, *key; + memset(¶ms,0,sizeof(MSDtlsSrtpParams)); + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ + /* This will parse the directory to find a matching fingerprint or generate it if not found */ + /* returned string must be freed */ + sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); + + if (key!= NULL && certificate!=NULL) { + params.pem_certificate = (char *)certificate; + params.pem_pkey = (char *)key; + params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ + video_stream_enable_dtls(call->videostream,¶ms); + ms_free(certificate); + ms_free(key); + } else { + ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); + /* TODO : check if encryption forced, if yes, stop call */ + } + } + }else{ call->videostream=video_stream_new_with_sessions(&call->sessions[1]); } @@ -2372,7 +2388,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); ms_dtls_srtp_set_peer_fingerprint(call->audiostream->ms.sessions.dtls_context, remote_desc->streams[0].dtls_fingerprint); } else { - ms_warning("unable to start DTLS engine, Dtls role in resulting media description is invalid\n"); + ms_warning("unable to start DTLS engine on audiostream, Dtls role in resulting media description is invalid\n"); } if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */ ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */ @@ -2381,6 +2397,28 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */ /* no need to start engine, we are waiting for DTLS Client Hello */ } +#ifdef VIDEO_ENABLED + salRole = call->resultdesc->streams[1].dtls_role; /* TODO: is streams[1] necessary the videostream in the media description ? */ + if (salRole==SalDtlsRoleInvalid) { /* it's invalid in streams[0] but check also at session level */ + salRole = call->resultdesc->dtls_role; + } + + if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */ + /* give the peer certificate fingerprint to dtls context */ + SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op); + ms_dtls_srtp_set_peer_fingerprint(call->videostream->ms.sessions.dtls_context, remote_desc->streams[1].dtls_fingerprint); + } else { + ms_warning("unable to start DTLS engine on videostream, Dtls role in resulting media description is invalid\n"); + } + if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */ + ms_dtls_srtp_set_role(call->videostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */ + ms_dtls_srtp_start(call->videostream->ms.sessions.dtls_context); /* then start the engine, it will send the DTLS client Hello */ + } else if (salRole == SalDtlsRoleIsServer) { /* local endpoint is server */ + ms_dtls_srtp_set_role(call->videostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */ + /* no need to start engine, we are waiting for DTLS Client Hello */ + } + +#endif } else { call->current_params->media_encryption=linphone_call_all_streams_encrypted(call) ? diff --git a/mediastreamer2 b/mediastreamer2 index bbe9f1f77..712ebd2d8 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bbe9f1f77ce7ae83de3cd3baabc89775a361c53a +Subproject commit 712ebd2d8cae8efdf224539a93c3ce81184f0106 diff --git a/oRTP b/oRTP index dffa5e73c..9eca0967d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit dffa5e73c4e6228766426efd23ff42130ef6c731 +Subproject commit 9eca0967dd773c364dcfce09ec13138338767872 From 54e91b639434450319e0a5292902bf35a0329cda Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 12 Jan 2015 15:35:28 +0100 Subject: [PATCH 16/20] Update srtp to rely on stream sessions structure and not complete stream structure --- coreapi/linphonecall.c | 49 +++++++++++++++++++++--------------------- mediastreamer2 | 2 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2336f6498..25a258067 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1737,27 +1737,26 @@ void linphone_call_init_video_stream(LinphoneCall *call){ rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { - MSDtlsSrtpParams params; - char *certificate, *key; - memset(¶ms,0,sizeof(MSDtlsSrtpParams)); - /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ - /* This will parse the directory to find a matching fingerprint or generate it if not found */ - /* returned string must be freed */ - sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); + MSDtlsSrtpParams params; + char *certificate, *key; + memset(¶ms,0,sizeof(MSDtlsSrtpParams)); + /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */ + /* This will parse the directory to find a matching fingerprint or generate it if not found */ + /* returned string must be freed */ + sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE); - if (key!= NULL && certificate!=NULL) { - params.pem_certificate = (char *)certificate; - params.pem_pkey = (char *)key; - params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ - video_stream_enable_dtls(call->videostream,¶ms); - ms_free(certificate); - ms_free(key); - } else { - ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); - /* TODO : check if encryption forced, if yes, stop call */ + if (key!= NULL && certificate!=NULL) { + params.pem_certificate = (char *)certificate; + params.pem_pkey = (char *)key; + params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */ + video_stream_enable_dtls(call->videostream,¶ms); + ms_free(certificate); + ms_free(key); + } else { + ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled"); + /* TODO : check if encryption forced, if yes, stop call */ + } } - } - }else{ call->videostream=video_stream_new_with_sessions(&call->sessions[1]); } @@ -2166,8 +2165,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); if (crypto_idx >= 0) { - media_stream_set_srtp_recv_key_b64(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key); - media_stream_set_srtp_send_key_b64(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + media_stream_set_srtp_recv_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,stream->crypto[0].master_key); + media_stream_set_srtp_send_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); } else { ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); } @@ -2285,8 +2284,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu if (sal_stream_description_has_srtp(vstream) == TRUE) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); if (crypto_idx >= 0) { - media_stream_set_srtp_recv_key_b64(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); - media_stream_set_srtp_send_key_b64(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + media_stream_set_srtp_recv_key_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,vstream->crypto[0].master_key); + media_stream_set_srtp_send_key_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); } } configure_rtp_session_for_rtcp_xr(lc, call, SalVideo); @@ -2444,9 +2443,9 @@ static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDes int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); if (crypto_idx >= 0) { if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) - media_stream_set_srtp_send_key_b64(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + media_stream_set_srtp_send_key_b64(&(ms->sessions),new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){ - media_stream_set_srtp_recv_key_b64(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key); + media_stream_set_srtp_recv_key_b64(&(ms->sessions),new_stream->crypto[0].algo,new_stream->crypto[0].master_key); } return TRUE; } else { diff --git a/mediastreamer2 b/mediastreamer2 index 712ebd2d8..44b25ea43 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 712ebd2d8cae8efdf224539a93c3ce81184f0106 +Subproject commit 44b25ea43a65afc118d9586fca82bd772c41cd76 From 37e5ccfbc24b9bbc6b1c8c7c4acd5f7eb3ec11ee Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 13 Jan 2015 14:53:18 +0100 Subject: [PATCH 17/20] DTLS-SRTP init linphone console too --- console/linphonec.c | 6 ++++++ coreapi/linphonecore.c | 13 +++++++------ mediastreamer2 | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 439702b85..d768b4a08 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -161,6 +161,7 @@ static int trace_level = 0; static char *logfile_name = NULL; static char configfile_name[PATH_MAX]; static char zrtpsecrets[PATH_MAX]; +static char usr_certificates_path[PATH_MAX]; static const char *factory_configfile_name=NULL; static char *sip_addr_to_call = NULL; /* for autocall */ static int window_id = 0; /* 0=standalone window, or window id for embedding video */ @@ -680,6 +681,8 @@ linphonec_init(int argc, char **argv) getenv("HOME")); snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache", getenv("HOME")); + snprintf(usr_certificates_path, PATH_MAX, "%s/.linphone-usr-crt", + getenv("HOME")); #elif defined(_WIN32_WCE) strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX); mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w"); @@ -689,6 +692,8 @@ linphonec_init(int argc, char **argv) getenv("APPDATA")); snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache", getenv("APPDATA")); + snprintf(usr_certificates_path, PATH_MAX, "%s/Linphone/linphone-usr-crt", + getenv("APPDATA")); #endif /* Handle configuration filename changes */ switch (handle_configfile_migration()) @@ -745,6 +750,7 @@ linphonec_init(int argc, char **argv) linphone_core_set_user_agent(linphonec,"Linphonec", LINPHONE_VERSION); linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets); + linphone_core_set_user_certificates_path(linphonec,usr_certificates_path); linphone_core_enable_video_capture(linphonec, vcap_enabled); linphone_core_enable_video_display(linphonec, display_enabled); if (display_enabled && window_id != 0) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 057e3be32..c8ba1b332 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1489,10 +1489,11 @@ static void misc_config_read(LinphoneCore *lc) { }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/ sal_set_uuid(lc->sal, uuid); - /* DTLS: if media_encryption is DTLS, get or create the certificate directory */ - if (linphone_core_get_media_encryption(lc) == LinphoneMediaEncryptionDTLS) { - /* TODO*/ - } + /* DTLS: if media_encryption DTLS SRTP is available, get or create the certificate directory */ + /*if (ms_dtls_srtp_available()){ + *//*JOHAN: USELESS? REMOVE IT*/ + //const char *user_certificate_config_path = lp_config_get_string(config,"misc","uuid",); +// }*/ } static void linphone_core_start(LinphoneCore * lc) { @@ -6834,7 +6835,7 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone case LinphoneMediaEncryptionSRTP: return ms_srtp_supported(); case LinphoneMediaEncryptionDTLS: - return ms_dtls_available(); + return ms_dtls_srtp_available(); case LinphoneMediaEncryptionZRTP: return ms_zrtp_available(); case LinphoneMediaEncryptionNone: @@ -6859,7 +6860,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption ret=-1; }else type="zrtp"; }else if (menc == LinphoneMediaEncryptionDTLS){ - if (!ms_dtls_available()){ + if (!ms_dtls_srtp_available()){ ms_warning("DTLS not supported by library."); type="none"; ret=-1; diff --git a/mediastreamer2 b/mediastreamer2 index 44b25ea43..c300a5806 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 44b25ea43a65afc118d9586fca82bd772c41cd76 +Subproject commit c300a5806ca1f731fe2899aa39925c20dc825899 From fbcb1007f2d0cd97c6876136320a41d856c1748c Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Wed, 14 Jan 2015 00:06:19 +0100 Subject: [PATCH 18/20] DTLS-SRTP add simple test call --- mediastreamer2 | 2 +- tester/call_tester.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index c300a5806..2f03f8b38 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c300a5806ca1f731fe2899aa39925c20dc825899 +Subproject commit 2f03f8b386bf20ff27a1ecfad916a65ae5653a82 diff --git a/tester/call_tester.c b/tester/call_tester.c index e8c96dc39..9826040cd 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -106,6 +106,7 @@ void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool else counters->number_of_LinphoneCallEncryptedOff++; } + void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); @@ -267,10 +268,10 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone && linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) { - /*wait for encryption to be on, in case of zrtp, it can take a few seconds*/ - if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) + /*wait for encryption to be on, in case of zrtp or dtls, it can take a few seconds*/ + if ((linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS)) wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1); - if (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) + if ((linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionDTLS)) wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); { const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); @@ -2092,6 +2093,10 @@ static void zrtp_video_call() { call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE); } +static void dtls_srtp_call() { + call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE); +} + static void call_with_declined_srtp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -2237,7 +2242,6 @@ end: } - void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -2266,6 +2270,10 @@ void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_r if (linphone_core_media_encryption_supported(marie->lc,mode)) { linphone_core_set_media_encryption(marie->lc,mode); linphone_core_set_media_encryption(pauline->lc,mode); + if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */ + marie->lc->user_certificates_path = ms_strdup_printf("%s/certificates/marie", liblinphone_tester_file_prefix); + pauline->lc->user_certificates_path = ms_strdup_printf("%s/certificates/pauline", liblinphone_tester_file_prefix); + } linphone_core_set_firewall_policy(marie->lc,policy); linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); @@ -3567,6 +3575,7 @@ test_t call_tests[] = { { "Call paused resumed from callee", call_paused_resumed_from_callee }, { "SRTP call", srtp_call }, { "ZRTP call",zrtp_call}, + { "DTLS SRTP call",dtls_srtp_call}, { "ZRTP video call",zrtp_video_call}, { "SRTP call with declined srtp", call_with_declined_srtp }, { "Call with file player", call_with_file_player}, From c95fd55126d88a8cfe7db2ee7929a40ade188d2e Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 20 Jan 2015 00:59:25 +0100 Subject: [PATCH 19/20] DTLS-SRTP fix memory leak --- coreapi/bellesip_sal/sal_impl.c | 3 +++ mediastreamer2 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 4208bd105..84964ecf1 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -1097,6 +1097,9 @@ void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_p } /* generate the fingerprint as described in RFC4572 if needed */ if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) { + if (*fingerprint != NULL) { + ms_free(*fingerprint); + } *fingerprint = belle_sip_certificates_chain_get_fingerprint(certificate); } diff --git a/mediastreamer2 b/mediastreamer2 index a27c77bdc..d5389594e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a27c77bdc96bbc4d727a5d6226a0587cbe8c5aa3 +Subproject commit d5389594e93c3499d70d9ddd556f9aac62aabc0a From f63ec9b8bf94152c0326e0dba231091235762164 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Tue, 27 Jan 2015 11:15:00 +0100 Subject: [PATCH 20/20] update ms --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 30e90d0f8..1f3804020 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 30e90d0f8a1a17fcd5b718a3eb8758f005f2052b +Subproject commit 1f38040205eaeeebeb17eae6c1408cc71e1bfca2