start sal sdp implementation

This commit is contained in:
Jehan Monnier 2012-05-09 19:49:21 +02:00
parent f1bb770e2a
commit c8b1916696
7 changed files with 364 additions and 18 deletions

View file

@ -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 \

View file

@ -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_ */

View file

@ -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;

View file

@ -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; i<desc->nstreams;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; j<SAL_CRYPTO_ALGO_MAX; j++) {
switch (desc->streams[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;
}

View file

@ -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");

View file

@ -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";
}
}

View file

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