From 1af4a7c091280cbed0982f4180b768db612a4a71 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 28 Feb 2014 16:30:11 +0100 Subject: [PATCH] improve SDP<->SalMediaDescription conversion and offer answer algorithm --- coreapi/bellesip_sal/sal_impl.c | 6 +++++ coreapi/bellesip_sal/sal_sdp.c | 24 ++++++++++--------- coreapi/linphonecall.c | 2 ++ coreapi/offeranswer.c | 42 ++++++++++++++++++++++++++++----- coreapi/proxy.c | 4 +++- coreapi/sal.c | 10 ++++++++ include/sal/sal.h | 14 ++++++++--- 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 62610f406..bfe90e035 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -947,6 +947,12 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } +unsigned int sal_get_random(void){ + unsigned int ret=0; + belle_sip_random_bytes((unsigned char*)&ret,4); + return ret; +} + belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 8f470c052..1f0da7fb0 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -87,7 +87,7 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; - media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type ) + media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 ,sal_media_proto_to_string ( stream->proto ) @@ -351,7 +351,7 @@ static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_ while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; - strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); + strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)-1); remote_candidate->port = candidate.port; } ptr += offset; @@ -360,9 +360,9 @@ static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_ } else break; } } else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) { - strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)); + strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)-1); } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { - strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); + strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd) -1); } else if (keywordcmp("ice-mismatch", att_name) == 0) { stream->ice_mismatch = TRUE; } @@ -383,16 +383,18 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, memset ( stream,0,sizeof ( *stream ) ); proto = belle_sdp_media_get_protocol ( media ); - stream->proto=SalProtoUnknown; + stream->proto=SalProtoOther; if ( proto ) { if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) stream->proto=SalProtoRtpAvp; else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { stream->proto=SalProtoRtpSavp; + }else{ + strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1); } } if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { - strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); + strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 ); } stream->rtp_port=belle_sdp_media_get_media_port ( media ); @@ -439,7 +441,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, if (nb == 1) { /* SDP rtcp attribute only contains the port */ } else if (nb == 2) { - strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)-1); } else { ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); } @@ -470,10 +472,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { - strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) ); + strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 ); } if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ - strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name)); + strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); } if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { @@ -493,10 +495,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /* 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)); + if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); - if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)); + if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 820ee3427..8699b1ec9 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -293,6 +293,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->n_active_streams=1; strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr)); strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr)); + strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); md->streams[0].rtp_port=call->audio_port; md->streams[0].rtcp_port=call->audio_port+1; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? @@ -309,6 +310,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (call->params.has_video){ md->n_active_streams++; + strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1); md->streams[1].rtp_port=call->video_port; md->streams[1].rtcp_port=call->video_port+1; md->streams[1].proto=md->streams[0].proto; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 42d856310..88a62535d 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -262,6 +262,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->ice_completed = local_cap->ice_completed; 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); } /** @@ -291,6 +292,35 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, return 0; } +static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){ + int i; + for(i=0;in_total_streams;++i){ + const SalStreamDescription *ss=&result->streams[i]; + if (strcmp(ss->name,stream->name)==0){ + ms_message("video stream already used in answer"); + return FALSE; + } + } + return TRUE; +} + +/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/ +static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){ + if (local==remote) return TRUE; + if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE; + return FALSE; +} + +static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){ + int i; + for(i=0;in_active_streams;++i){ + const SalStreamDescription *ss=&local_capabilities->streams[i]; + if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto) + && local_stream_not_already_used(result,ss)) return ss; + } + return NULL; +} + /** * Returns a media description to run the streams with, based on the local capabilities and * and the received offer. @@ -305,17 +335,14 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities result->n_active_streams=0; for(i=0;in_total_streams;++i){ rs=&remote_offer->streams[i]; - if (rs->proto!=SalProtoUnknown){ - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); - /* if matching failed, and remote proposes Avp only, ask for local Savp streams */ - if (!ls && rs->proto == SalProtoRtpAvp) { - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type); - } + if (rs->proto!=SalProtoOther){ + ls=find_local_matching_stream(result,local_capabilities,rs); }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); if (result->streams[i].rtp_port!=0) result->n_active_streams++; }else { + ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i); /* create an inactive stream for the answer, as there where no matching stream in local capabilities */ result->streams[i].dir=SalStreamInactive; result->streams[i].rtp_port=0; @@ -324,6 +351,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } + if (rs->proto==SalProtoOther){ + strncpy(result->streams[i].proto_other,rs->proto_other,sizeof(rs->proto_other)-1); + } } } result->n_total_streams=i; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 6bc8e5588..8d485b910 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -42,10 +42,12 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ } static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){ + const char *dial_prefix; memset(obj,0,sizeof(LinphoneProxyConfig)); obj->magic=linphone_proxy_config_magic; obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600); - obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0')); + dial_prefix=LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",NULL); + if (dial_prefix) obj->dial_prefix=ms_strdup(dial_prefix); obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0); obj->privacy=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"privacy",LinphonePrivacyDefault); } diff --git a/coreapi/sal.c b/coreapi/sal.c index 46f7325df..6f2256ac9 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -498,6 +498,11 @@ const char* sal_stream_type_to_string(SalStreamType type) { } } +const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc){ + if (desc->type==SalOther) return desc->typeother; + else return sal_stream_type_to_string(desc->type); +} + const char* sal_media_proto_to_string(SalMediaProto type) { switch (type) { case SalProtoRtpAvp:return "RTP/AVP"; @@ -506,6 +511,11 @@ const char* sal_media_proto_to_string(SalMediaProto type) { } } +const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){ + if (desc->proto==SalProtoOther) return desc->proto_other; + else return sal_media_proto_to_string(desc->proto); +} + const char* sal_stream_dir_to_string(SalStreamDir type) { switch (type) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 3deb3ddb4..0fa968eb2 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -121,9 +121,9 @@ typedef enum { const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ - SalProtoUnknown, SalProtoRtpAvp, - SalProtoRtpSavp + SalProtoRtpSavp, + SalProtoOther }SalMediaProto; const char* sal_media_proto_to_string(SalMediaProto type); @@ -177,9 +177,11 @@ typedef struct SalSrtpCryptoAlgo { #define SAL_CRYPTO_ALGO_MAX 4 typedef struct SalStreamDescription{ + char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/ SalMediaProto proto; SalStreamType type; char typeother[32]; + char proto_other[32]; char rtp_addr[64]; char rtcp_addr[64]; int rtp_port; @@ -197,9 +199,13 @@ typedef struct SalStreamDescription{ char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_mismatch; bool_t ice_completed; + bool_t pad[2]; } SalStreamDescription; -#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 +const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc); +const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc); + +#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 8 typedef struct SalMediaDescription{ int refcount; @@ -217,6 +223,7 @@ typedef struct SalMediaDescription{ char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_lite; bool_t ice_completed; + bool_t pad[2]; } SalMediaDescription; typedef struct SalMessage{ @@ -691,6 +698,7 @@ LINPHONE_PUBLIC void sal_enable_dns_srv(Sal *sal, bool_t enable); LINPHONE_PUBLIC bool_t sal_dns_srv_enabled(const Sal *sal); LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); +unsigned int sal_get_random(void); unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer);