3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 This header files defines the Signaling Abstraction Layer.
22 The purpose of this layer is too allow experiment different call signaling
23 protocols and implementations under linphone, for example SIP, JINGLE...
27 const char* sal_transport_to_string(SalTransport transport) {
29 case SalTransportUDP:return "udp";
30 case SalTransportTCP: return "tcp";
31 case SalTransportTLS:return "tls";
32 case SalTransportDTLS:return "dtls";
34 ms_fatal("Unexpected transport [%i]",transport);
40 SalTransport sal_transport_parse(const char* param) {
41 if (strcasecmp("udp",param)==0) return SalTransportUDP;
42 if (strcasecmp("tcp",param)==0) return SalTransportTCP;
43 if (strcasecmp("tls",param)==0) return SalTransportTLS;
44 if (strcasecmp("dtls",param)==0) return SalTransportDTLS;
45 ms_error("Unknown transport type[%s], returning UDP", param);
46 return SalTransportUDP;
49 SalMediaDescription *sal_media_description_new(){
50 SalMediaDescription *md=ms_new0(SalMediaDescription,1);
55 static void sal_media_description_destroy(SalMediaDescription *md){
57 for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
58 ms_list_for_each(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
59 ms_list_free(md->streams[i].payloads);
60 md->streams[i].payloads=NULL;
65 void sal_media_description_ref(SalMediaDescription *md){
69 void sal_media_description_unref(SalMediaDescription *md){
72 sal_media_description_destroy (md);
76 SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
77 SalMediaProto proto, SalStreamType type){
79 for(i=0;i<md->nstreams;++i){
80 SalStreamDescription *ss=&md->streams[i];
81 if (ss->proto==proto && ss->type==type) return ss;
86 bool_t sal_media_description_empty(const SalMediaDescription *md){
88 for(i=0;i<md->nstreams;++i){
89 const SalStreamDescription *ss=&md->streams[i];
90 if (ss->rtp_port!=0) return FALSE;
95 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
97 for(i=0;i<md->nstreams;++i){
98 SalStreamDescription *ss=&md->streams[i];
104 static bool_t is_null_address(const char *addr){
105 return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
108 /*check for the presence of at least one stream with requested direction */
109 static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
112 /* we are looking for at least one stream with requested direction, inactive streams are ignored*/
113 for(i=0;i<md->nstreams;++i){
114 const SalStreamDescription *ss=&md->streams[i];
115 if (ss->dir==stream_dir) return TRUE;
116 /*compatibility check for phones that only used the null address and no attributes */
117 if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr)))
123 bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
124 if (stream_dir==SalStreamRecvOnly){
125 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
127 }else if (stream_dir==SalStreamSendOnly){
128 if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
130 }else if (stream_dir==SalStreamSendRecv){
131 return has_dir(md,SalStreamSendRecv);
133 /*SalStreamInactive*/
134 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv) || has_dir(md,SalStreamRecvOnly))
142 static bool_t fmtp_equals(const char *p1, const char *p2){
143 if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
144 if (p1==NULL && p2==NULL) return TRUE;
149 static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
150 if (p1->type!=p2->type) return FALSE;
151 if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
152 if (p1->clock_rate!=p2->clock_rate) return FALSE;
153 if (p1->channels!=p2->channels) return FALSE;
154 if (payload_type_get_number(p1) != payload_type_get_number(p2)) return FALSE;
156 Do not compare fmtp right now: they are modified internally when the call is started
159 if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
160 !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
166 static bool_t is_recv_only(PayloadType *p){
167 return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
170 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
171 const MSList *e1,*e2;
172 for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
173 PayloadType *p1=(PayloadType*)e1->data;
174 PayloadType *p2=(PayloadType*)e2->data;
175 if (!payload_type_equals(p1,p2))
179 /*skip possible recv-only payloads*/
180 for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
181 ms_message("Skipping recv-only payload type...");
184 if (e1!=NULL || e2!=NULL){
185 /*means one list is longer than the other*/
191 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
192 int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
195 /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
196 needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
197 if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
198 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
199 if ((sd1->crypto[i].tag != sd2->crypto[i].tag)
200 || (sd1->crypto[i].algo != sd2->crypto[i].algo)
201 || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) {
202 result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED;
206 if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
207 if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
208 if (sd1->rtp_port != sd2->rtp_port) {
209 if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
210 else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
212 if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
213 if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
214 if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
215 if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
216 if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
217 if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
222 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
223 int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
226 if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
227 if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
228 if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
229 for(i = 0; i < md1->nstreams; ++i){
230 result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
235 static void assign_string(char **str, const char *arg){
244 void sal_op_set_contact(SalOp *op, const char *contact){
245 assign_string(&((SalOpBase*)op)->contact,contact);
248 void sal_op_set_route(SalOp *op, const char *route){
249 assign_string(&((SalOpBase*)op)->route,route);
252 void sal_op_set_from(SalOp *op, const char *from){
253 assign_string(&((SalOpBase*)op)->from,from);
256 void sal_op_set_to(SalOp *op, const char *to){
257 assign_string(&((SalOpBase*)op)->to,to);
260 void sal_op_set_user_pointer(SalOp *op, void *up){
261 ((SalOpBase*)op)->user_pointer=up;
264 Sal *sal_op_get_sal(const SalOp *op){
265 return ((SalOpBase*)op)->root;
268 const char *sal_op_get_from(const SalOp *op){
269 return ((SalOpBase*)op)->from;
272 const char *sal_op_get_to(const SalOp *op){
273 return ((SalOpBase*)op)->to;
276 const char *sal_op_get_contact(const SalOp *op){
277 return ((SalOpBase*)op)->contact;
280 const char *sal_op_get_route(const SalOp *op){
281 return ((SalOpBase*)op)->route;
284 const char *sal_op_get_remote_ua(const SalOp *op){
285 return ((SalOpBase*)op)->remote_ua;
288 void *sal_op_get_user_pointer(const SalOp *op){
289 return ((SalOpBase*)op)->user_pointer;
292 const char *sal_op_get_proxy(const SalOp *op){
293 return ((SalOpBase*)op)->route;
296 const char *sal_op_get_network_origin(const SalOp *op){
297 return ((SalOpBase*)op)->origin;
299 const char* sal_op_get_call_id(const SalOp *op) {
300 return ((SalOpBase*)op)->call_id;
302 void __sal_op_init(SalOp *b, Sal *sal){
303 memset(b,0,sizeof(SalOpBase));
304 ((SalOpBase*)b)->root=sal;
307 void __sal_op_set_network_origin(SalOp *op, const char *origin){
308 assign_string(&((SalOpBase*)op)->origin,origin);
312 void __sal_op_free(SalOp *op){
313 SalOpBase *b=(SalOpBase *)op;
335 ms_free(b->remote_ua);
339 sal_media_description_unref(b->local_media);
341 sal_media_description_unref(b->remote_media);
343 ms_free((void*)b->call_id);
347 SalAuthInfo* sal_auth_info_new() {
348 return ms_new0(SalAuthInfo,1);
351 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
352 SalAuthInfo* new_auth_info=sal_auth_info_new();
353 new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
354 new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
355 new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
356 new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
357 return new_auth_info;
360 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
361 if (auth_info->username) ms_free(auth_info->username);
362 if (auth_info->userid) ms_free(auth_info->userid);
363 if (auth_info->realm) ms_free(auth_info->realm);
364 if (auth_info->password) ms_free(auth_info->password);
365 ms_free((void*)auth_info);