diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 1a5975a09..208ab3ff6 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -42,7 +42,8 @@ liblinphone_la_SOURCES=\ if USE_BELLESIP liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c \ - bellesip_sal/sal_op_impl.c + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_sdp.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 63b97b351..e322bd052 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SAL_IMPL_H_ #include "sal.h" #include "belle-sip/belle-sip.h" +#include "belle-sip/belle-sdp.h" struct Sal{ SalCallbacks callbacks; @@ -41,5 +42,8 @@ struct SalOp{ unsigned long int registration_refresh_timer; }; +belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); +int sdp_to_media_description(belle_sdp_session_description_t *sdp, SalMediaDescription *desc); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 8eb1b3893..67a9ac098 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -314,7 +314,11 @@ static void send_register_request(SalOp* op, belle_sip_request_t* request) { /*if expire = -1, does not change expires*/ static void send_register_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); - + belle_sip_header_route_t* route_header; + if (sal_op_get_route_address(op)) { + route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(route_header)); + } if (!expires_header) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); } @@ -327,25 +331,30 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_contact_t* contact_header =belle_sip_header_contact_new(); belle_sip_header_from_t* from_header; + const char* from_user; belle_sip_header_to_t* to_header; belle_sip_uri_t* req_uri; belle_sip_uri_t* contact_uri; sal_op_set_from(op,from); sal_op_set_to(op,from); belle_sip_uri_t* route_uri=NULL; - belle_sip_header_route_t* route_header; + belle_sip_header_address_t* route_address; + char token[10]; if (expires<0) goto error; from_header = belle_sip_header_from_create(from,belle_sip_random_token(token,sizeof(token))); if (!from_header) goto error; to_header=belle_sip_header_to_create(from,NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); + from_user=belle_sip_uri_get_user(req_uri); /*save username for contact header*/ belle_sip_uri_set_user(req_uri,NULL); if (sal_op_get_contact(op)) contact_uri= belle_sip_uri_parse(sal_op_get_contact(op)); - else + else { contact_uri=belle_sip_uri_new(); + belle_sip_uri_set_user(contact_uri,from_user); + } if (!contact_uri) goto error; belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,contact_uri); @@ -369,10 +378,12 @@ int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); if (route_uri && !belle_sip_uri_equals(req_uri,route_uri)) { - route_header = belle_sip_header_route_new(); belle_sip_uri_set_lr_param(route_uri,1); - belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(route_header),route_uri); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); + route_address=belle_sip_header_address_new(); + belle_sip_header_address_set_uri(route_address,route_uri); + sal_op_set_route_address(op,(const SalAddress*)route_address); /*save route for subsequent register*/ + belle_sip_object_unref(route_address); + } else if (route_uri){ belle_sip_object_unref(route_uri); route_uri=NULL; diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c new file mode 100644 index 000000000..417ee58b7 --- /dev/null +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -0,0 +1,281 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +#define keywordcmp(key,b) strncmp(key,b,sizeof(key)) + +belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *desc) { + belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new(); + bool_t inet6; + belle_sdp_origin_t* origin; + belle_sdp_mime_parameter_t* mime_param; + belle_sdp_media_description_t* media_desc; + int i,j; + MSList* pt_it; + PayloadType* pt; + char buffer[1024]; + + if (strchr(desc->addr,':')!=NULL){ + inet6=1; + }else inet6=0; + belle_sdp_session_description_set_version(session_desc,belle_sdp_version_create(0)); + + origin = belle_sdp_origin_create(desc->username + ,desc->session_id + ,desc->session_ver + ,"IN" + , inet6 ? "IP6" :"IP4" + ,desc->addr); + + belle_sdp_session_description_set_origin(session_desc,origin); + + belle_sdp_session_description_set_session_name(session_desc,belle_sdp_session_name_create("Talk")); + + if(!sal_media_description_has_dir (desc,SalStreamSendOnly) && !sal_media_description_has_dir (desc,SalStreamInactive)) { + belle_sdp_session_description_set_connection(session_desc + ,belle_sdp_connection_create("IN",inet6 ? "IP6" :"IP4",desc->addr)); + + } else { + belle_sdp_session_description_set_connection(session_desc + ,belle_sdp_connection_create("IN" + ,inet6 ? "IP6" :"IP4" + ,inet6 ? "::0" :"0.0.0.0")); + + } + + belle_sdp_session_description_set_time_description(session_desc,belle_sdp_time_description_create(0,0)); + + if (desc->bandwidth>0) { + belle_sdp_session_description_set_bandwidth(session_desc,"AS",desc->bandwidth); + } + + for (i=0; instreams;i++) { + media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type) + ,desc->streams[i].port + ,1 + ,sal_media_proto_to_string(desc->streams[i].proto) + ,NULL); + for (pt_it=desc->streams[i].payloads;pt_it!=NULL;pt_it=pt_it->next) { + pt=(PayloadType*)pt_it->data; + mime_param= belle_sdp_mime_parameter_create(pt->mime_type + , pt->type + , pt->clock_rate + ,desc->streams[i].type==SalAudio?1:-1); + belle_sdp_mime_parameter_set_parameters(mime_param,pt->recv_fmtp); + if (desc->streams[i].ptime>0) { + belle_sdp_mime_parameter_set_ptime(mime_param,desc->streams[i].ptime); + } + belle_sdp_media_description_append_values_from_mime_parameter(media_desc,mime_param); + belle_sip_object_unref(mime_param); + } + if (desc->streams[i].bandwidth>0) + belle_sdp_media_description_set_bandwidth(media_desc,"AS",desc->streams[i].bandwidth); + + if (desc->streams[i].proto == SalProtoRtpSavp) { + /* add crypto lines */ + for(j=0; jstreams[i].crypto[j].algo) { + case AES_128_SHA1_80: + snprintf(buffer, sizeof(buffer), "%d %s inline:%s", + desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", desc->streams[i].crypto[j].master_key); + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); + break; + case AES_128_SHA1_32: + snprintf(buffer, sizeof(buffer), "%d %s inline:%s", + desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", desc->streams[i].crypto[j].master_key); + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer)); + break; + case AES_128_NO_AUTH: + ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); + break; + case NO_CIPHER_SHA1_80: + ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); + break; + default: + j = SAL_CRYPTO_ALGO_MAX; + /* no break */ + } + } + + } + belle_sdp_session_description_add_media_description(session_desc,media_desc); + + } + return session_desc; + +} + + +int sdp_to_media_description(belle_sdp_session_description_t *session_desc, SalMediaDescription *desc) { + /* + typedef struct SalMediaDescription{ + int refcount; + char addr[64]; + char username[64]; + int nstreams; + int bandwidth; + unsigned int session_ver; + unsigned int session_id; + SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + } SalMediaDescription; + */ + belle_sdp_connection_t* cnx; + belle_sip_list_t* media_desc_it; + belle_sdp_media_description_t* media_desc; + const char *mtype,*proto; + SalStreamDescription *stream; + belle_sdp_media_t* media; + belle_sip_list_t* mime_param_it=NULL; + belle_sdp_mime_parameter_t* mime_param; + PayloadType *pt; + belle_sip_list_t* attribute_it; + belle_sdp_attribute_t* attribute; + int valid_count = 0; + char tmp[256], tmp2[256]; + int nb=0; + + desc->nstreams=0; + + 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)); + } + if (belle_sdp_session_description_get_bandwidth(session_desc,"AS") >0) { + desc->bandwidth=belle_sdp_session_description_get_bandwidth(session_desc,"AS"); + } + for(media_desc_it=belle_sdp_session_description_get_media_descriptions(session_desc) + ;media_desc_it!=NULL + ;media_desc_it=media_desc_it->next) { + media_desc=BELLE_SDP_MEDIA_DESCRIPTION(media_desc_it->data); + stream=&desc->streams[desc->nstreams]; + media=belle_sdp_media_description_get_media(media_desc); + + memset(stream,0,sizeof(*stream)); + + proto = belle_sdp_media_get_protocol(media); + stream->proto=SalProtoUnknown; + if (proto){ + if (strcasecmp(proto,"RTP/AVP")==0) + stream->proto=SalProtoRtpAvp; + else if (strcasecmp(proto,"RTP/SAVP")==0){ + stream->proto=SalProtoRtpSavp; + } + } + if ((cnx=belle_sdp_media_description_get_connection(media_desc)) && belle_sdp_connection_get_address(cnx)) { + strncpy(stream->addr,belle_sdp_connection_get_address(cnx),sizeof(stream->addr)); + } + + stream->port=belle_sdp_media_get_media_port(media); + + mtype = belle_sdp_media_get_media_type(media); + if (strcasecmp("audio", mtype) == 0){ + stream->type=SalAudio; + }else if (strcasecmp("video", mtype) == 0){ + stream->type=SalVideo; + }else { + stream->type=SalOther; + strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1); + } + + if (belle_sdp_media_description_get_bandwidth(media_desc,"AS") >0) { + stream->bandwidth=belle_sdp_media_description_get_bandwidth(media_desc,"AS"); + } + + + if (belle_sdp_media_description_get_attribute(media_desc,"sendrecv")) { + stream->dir=SalStreamSendRecv; + } else if (belle_sdp_media_description_get_attribute(media_desc,"sendonly")) { + stream->dir=SalStreamSendOnly; + } else if (belle_sdp_media_description_get_attribute(media_desc,"recvonly")) { + stream->dir=SalStreamRecvOnly; + } else if (belle_sdp_media_description_get_attribute(media_desc,"inactive")) { + stream->dir=SalStreamInactive; + } else { + stream->dir=SalStreamSendRecv; + } + + /* for each payload type */ + for(mime_param_it=belle_sdp_media_description_build_mime_parameters(media_desc) + ;mime_param_it!=NULL + ;mime_param_it=mime_param_it->next) { + mime_param=BELLE_SDP_MIME_PARAMETER(mime_param_it->data) + + pt=payload_type_new(); + payload_type_set_number(pt,belle_sdp_mime_parameter_get_media_format(mime_param)); + pt->clock_rate=belle_sdp_mime_parameter_get_rate(mime_param); + pt->mime_type=ms_strdup(belle_sdp_mime_parameter_get_type(mime_param)); + pt->channels=belle_sdp_mime_parameter_get_channel_count(mime_param); + payload_type_set_send_fmtp(pt,belle_sdp_mime_parameter_get_parameters(mime_param)); + stream->payloads=ms_list_append(stream->payloads,pt); + stream->ptime=belle_sdp_mime_parameter_get_ptime(mime_param); + ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : ""); + } + if (mime_param_it) belle_sip_list_free_with_data(mime_param_it,belle_sip_object_unref); + /* read crypto lines if any */ + if (stream->proto == SalProtoRtpSavp) { + + memset(&stream->crypto, 0, sizeof(stream->crypto)); + for (attribute_it=belle_sdp_media_description_get_attributes(media_desc) + ;valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; + attribute_it=attribute_it->next){ + attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); + + if (keywordcmp("crypto",belle_sdp_attribute_get_name(attribute))==0 && belle_sdp_attribute_get_value(attribute)!=NULL){ + nb = sscanf(belle_sdp_attribute_get_value(attribute), "%d %256s inline:%256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2); + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + tmp2); + if (nb == 3) { + if (keywordcmp("AES_CM_128_HMAC_SHA1_80",tmp) == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_80; + else if (keywordcmp("AES_CM_128_HMAC_SHA1_32",tmp) == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_32; + else { + ms_warning("Failed to parse crypto-algo: '%s'", tmp); + stream->crypto[valid_count].algo = 0; + } + if (stream->crypto[valid_count].algo) { + strncpy(stream->crypto[valid_count].master_key, tmp2, 41); + stream->crypto[valid_count].master_key[40] = '\0'; + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + stream->crypto[valid_count].master_key); + valid_count++; + } + } else { + ms_warning("sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value(attribute),nb); + } + } + } + ms_message("Found: %d valid crypto lines", valid_count); + } + desc->nstreams++; + } + + return 0; +} + + + + diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ea530e6b2..f25a1cbaa 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -248,7 +248,7 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) obj->lc=lc; linphone_proxy_config_done(obj); } - +#ifndef USE_BELLESIP static char *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); char *ret=NULL; @@ -280,16 +280,20 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_address_destroy (proxy); return ret; } - +#endif static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ +#ifndef USE_BELLESIP char *contact; +#endif if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); +#ifndef USE_BELLESIP /*contact is automatically guessed by belle-sip*/ contact=guess_contact_for_register(obj); sal_op_set_contact(obj->op,contact); ms_free(contact); +#endif sal_op_set_user_pointer(obj->op,obj); if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress"); diff --git a/coreapi/sal.c b/coreapi/sal.c index 09bb6e02d..afddc0e3a 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -220,6 +220,8 @@ static void assign_string(char **str, const char *arg){ if (arg) *str=ms_strdup(arg); } + + void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ char* address_string=sal_address_as_string(address); /*can probably be optimized*/ sal_op_set_contact(op,address_string); @@ -228,20 +230,31 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ const SalAddress* sal_op_get_contact_address(const SalOp *op) { return ((SalOpBase*)op)->contact_address; } + +#define SET_PARAM(op,name) \ + char* name##_string=NULL; \ + assign_address(&((SalOpBase*)op)->name##_address,name); \ + if (((SalOpBase*)op)->name##_address) { \ + name##_string=sal_address_as_string(((SalOpBase*)op)->name##_address); \ + }\ + assign_string(&((SalOpBase*)op)->name,name##_string); \ + if(name##_string) ms_free(name##_string); + void sal_op_set_contact(SalOp *op, const char *contact){ - char* contact_string=NULL; - assign_address(&((SalOpBase*)op)->contact_address,contact); - if (((SalOpBase*)op)->contact_address) { - contact_string=sal_address_as_string(((SalOpBase*)op)->contact_address); - } - assign_string(&((SalOpBase*)op)->contact,contact_string); - if(contact_string) ms_free(contact_string); + SET_PARAM(op,contact); } void sal_op_set_route(SalOp *op, const char *route){ - assign_string(&((SalOpBase*)op)->route,route); + SET_PARAM(op,route); +} +const SalAddress* sal_op_get_route_address(const SalOp *op) { + return ((SalOpBase*)op)->route_address; +} +void sal_op_set_route_address(SalOp *op, const SalAddress *address){ + char* address_string=sal_address_as_string(address); /*can probably be optimized*/ + sal_op_set_route(op,address_string); + ms_free(address_string); } - void sal_op_set_from(SalOp *op, const char *from){ assign_string(&((SalOpBase*)op)->from,from); } @@ -354,3 +367,29 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info) { ms_free((void*)auth_info); } +const char* sal_stream_type_to_string(SalStreamType type) { + switch (type) { + case SalAudio:return "audio"; + case SalVideo:return "video"; + default: return "other"; + } +} + +const char* sal_media_proto_to_string(SalMediaProto type) { + switch (type) { + case SalProtoRtpAvp:return "RTP/AVP"; + case SalProtoRtpSavp:return "RTP/SAVP"; + default: return "unknown"; + } +} + + +const char* sal_stream_dir_to_string(SalStreamDir type) { + switch (type) { + case SalStreamSendRecv:return "sendrecv"; + case SalStreamSendOnly:return "sendonly"; + case SalStreamRecvOnly:return "recvonly"; + case SalStreamInactive:return "inative"; + default: return "unknown"; + } +} diff --git a/coreapi/sal.h b/coreapi/sal.h index 5b3883d89..6ca4deb32 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -91,12 +91,14 @@ typedef enum { SalVideo, SalOther } SalStreamType; +const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ SalProtoUnknown, SalProtoRtpAvp, SalProtoRtpSavp }SalMediaProto; +const char* sal_media_proto_to_string(SalMediaProto type); typedef enum{ SalStreamSendRecv, @@ -104,6 +106,7 @@ typedef enum{ SalStreamRecvOnly, SalStreamInactive }SalStreamDir; +const char* sal_stream_dir_to_string(SalStreamDir type); typedef struct SalEndpointCandidate{ char addr[64]; @@ -163,6 +166,7 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ + SalAddress* route_address; char *contact; SalAddress* contact_address; char *from; @@ -309,6 +313,7 @@ Sal *sal_op_get_sal(const SalOp *op); void sal_op_set_contact(SalOp *op, const char *contact); void sal_op_set_contact_address(SalOp *op, const SalAddress* address); void sal_op_set_route(SalOp *op, const char *route); +void sal_op_set_route_address(SalOp *op, const SalAddress* address); void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_to(SalOp *op, const char *to); void sal_op_release(SalOp *h); @@ -321,6 +326,7 @@ const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const SalAddress *sal_op_get_contact_address(const SalOp *op); const char *sal_op_get_route(const SalOp *op); +const SalAddress* sal_op_get_route_address(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op);