]> sjero.net Git - linphone/blob - coreapi/sal.c
2b09212aa02e79f3468aa54d8f6bbcbfaff90484
[linphone] / coreapi / sal.c
1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4
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.
9
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.
14
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.
18 */
19
20 /** 
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...
24 **/
25
26 #include "sal.h"
27 const char* sal_transport_to_string(SalTransport transport) {
28         switch (transport) {
29                 case SalTransportUDP:return "udp";
30                 case SalTransportTCP: return "tcp";
31                 case SalTransportTLS:return "tls";
32                 case SalTransportDTLS:return "dtls";
33                 default: {
34                         ms_fatal("Unexpected transport [%i]",transport);
35                         return NULL;
36                 }    
37         }
38 }
39
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;
47 }
48
49 SalMediaDescription *sal_media_description_new(){
50         SalMediaDescription *md=ms_new0(SalMediaDescription,1);
51         md->refcount=1;
52         return md;
53 }
54
55 static void sal_media_description_destroy(SalMediaDescription *md){
56         int i;
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;
61         }
62         ms_free(md);
63 }
64
65 void sal_media_description_ref(SalMediaDescription *md){
66         md->refcount++;
67 }
68
69 void sal_media_description_unref(SalMediaDescription *md){
70         md->refcount--;
71         if (md->refcount==0){
72                 sal_media_description_destroy (md);
73         }
74 }
75
76 SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
77     SalMediaProto proto, SalStreamType type){
78         int i;
79         for(i=0;i<md->nstreams;++i){
80                 SalStreamDescription *ss=&md->streams[i];
81                 if (ss->proto==proto && ss->type==type) return ss;
82         }
83         return NULL;
84 }
85
86 bool_t sal_media_description_empty(const SalMediaDescription *md){
87         int i;
88         for(i=0;i<md->nstreams;++i){
89                 const SalStreamDescription *ss=&md->streams[i];
90                 if (ss->rtp_port!=0) return FALSE;
91         }
92         return TRUE;
93 }
94
95 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
96         int i;
97         for(i=0;i<md->nstreams;++i){
98                 SalStreamDescription *ss=&md->streams[i];
99                 ss->dir=stream_dir;
100         }
101 }
102
103
104 static bool_t is_null_address(const char *addr){
105         return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
106 }
107
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){
110         int i;
111
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)))
118                         return TRUE;
119         }
120         return FALSE;
121 }
122
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;
126                 else return TRUE;
127         }else if (stream_dir==SalStreamSendOnly){
128                 if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
129                 else return TRUE;
130         }else if (stream_dir==SalStreamSendRecv){
131                 return has_dir(md,SalStreamSendRecv);
132         }else{
133                 /*SalStreamInactive*/
134                 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)  || has_dir(md,SalStreamRecvOnly))
135                         return FALSE;
136                 else return TRUE;
137         }
138         return FALSE;
139 }
140
141 /*
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;
145         return FALSE;
146 }
147 */
148
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;
155         /*
156          Do not compare fmtp right now: they are modified internally when the call is started
157         */
158         /*
159         if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
160             !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
161                 return FALSE;
162         */
163         return TRUE;
164 }
165
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);
168 }
169
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))
176                         return FALSE;
177         }
178         if (e1!=NULL){
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...");
182                 }
183         }
184         if (e1!=NULL || e2!=NULL){
185                 /*means one list is longer than the other*/
186                 return FALSE;
187         }
188         return TRUE;
189 }
190
191 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
192         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
193         int i;
194
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;
203                 }
204         }
205
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;
211         }
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;
218
219         return result;
220 }
221
222 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
223         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
224         int i;
225
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]);
231         }
232         return result;
233 }
234
235 static void assign_string(char **str, const char *arg){
236         if (*str){
237                 ms_free(*str);
238                 *str=NULL;
239         }
240         if (arg)
241                 *str=ms_strdup(arg);
242 }
243
244 void sal_op_set_contact(SalOp *op, const char *contact){
245         assign_string(&((SalOpBase*)op)->contact,contact);
246 }
247
248 void sal_op_set_route(SalOp *op, const char *route){
249         assign_string(&((SalOpBase*)op)->route,route);
250 }
251
252 void sal_op_set_from(SalOp *op, const char *from){
253         assign_string(&((SalOpBase*)op)->from,from);
254 }
255
256 void sal_op_set_to(SalOp *op, const char *to){
257         assign_string(&((SalOpBase*)op)->to,to);
258 }
259
260 void sal_op_set_user_pointer(SalOp *op, void *up){
261         ((SalOpBase*)op)->user_pointer=up;
262 }
263
264 Sal *sal_op_get_sal(const SalOp *op){
265         return ((SalOpBase*)op)->root;
266 }
267
268 const char *sal_op_get_from(const SalOp *op){
269         return ((SalOpBase*)op)->from;
270 }
271
272 const char *sal_op_get_to(const SalOp *op){
273         return ((SalOpBase*)op)->to;
274 }
275
276 const char *sal_op_get_contact(const SalOp *op){
277         return ((SalOpBase*)op)->contact;
278 }
279
280 const char *sal_op_get_route(const SalOp *op){
281         return ((SalOpBase*)op)->route;
282 }
283
284 const char *sal_op_get_remote_ua(const SalOp *op){
285         return ((SalOpBase*)op)->remote_ua;
286 }
287
288 void *sal_op_get_user_pointer(const SalOp *op){
289         return ((SalOpBase*)op)->user_pointer;
290 }
291
292 const char *sal_op_get_proxy(const SalOp *op){
293         return ((SalOpBase*)op)->route;
294 }
295
296 const char *sal_op_get_network_origin(const SalOp *op){
297         return ((SalOpBase*)op)->origin;
298 }
299 const char* sal_op_get_call_id(const SalOp *op) {
300         return  ((SalOpBase*)op)->call_id;
301 }
302 void __sal_op_init(SalOp *b, Sal *sal){
303         memset(b,0,sizeof(SalOpBase));
304         ((SalOpBase*)b)->root=sal;
305 }
306
307 void __sal_op_set_network_origin(SalOp *op, const char *origin){
308         assign_string(&((SalOpBase*)op)->origin,origin);
309 }
310
311
312 void __sal_op_free(SalOp *op){
313         SalOpBase *b=(SalOpBase *)op;
314         if (b->from) {
315                 ms_free(b->from);
316                 b->from=NULL;
317         }
318         if (b->to) {
319                 ms_free(b->to);
320                 b->to=NULL;
321         }
322         if (b->route) {
323                 ms_free(b->route);
324                 b->route=NULL;
325         }
326         if (b->contact) {
327                 ms_free(b->contact);
328                 b->contact=NULL;
329         }
330         if (b->origin){
331                 ms_free(b->origin);
332                 b->origin=NULL;
333         }
334         if (b->remote_ua){
335                 ms_free(b->remote_ua);
336                 b->remote_ua=NULL;
337         }
338         if (b->local_media)
339                 sal_media_description_unref(b->local_media);
340         if (b->remote_media)
341                 sal_media_description_unref(b->remote_media);
342         if (b->call_id)
343                 ms_free((void*)b->call_id);
344         ms_free(op);
345 }
346
347 SalAuthInfo* sal_auth_info_new() {
348         return ms_new0(SalAuthInfo,1);
349 }
350
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;
358 }
359
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);
366 }
367