]> sjero.net Git - linphone/blob - coreapi/sal.c
Aac-eld add missing header according to RFC3640 3.3.6
[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->n_active_streams;++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         if (md->n_active_streams > 0) return FALSE;
88         return TRUE;
89 }
90
91 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
92         int i;
93         for(i=0;i<md->n_active_streams;++i){
94                 SalStreamDescription *ss=&md->streams[i];
95                 ss->dir=stream_dir;
96         }
97 }
98
99
100 static bool_t is_null_address(const char *addr){
101         return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
102 }
103
104 /*check for the presence of at least one stream with requested direction */
105 static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
106         int i;
107
108         /* we are looking for at least one stream with requested direction, inactive streams are ignored*/
109         for(i=0;i<md->n_active_streams;++i){
110                 const SalStreamDescription *ss=&md->streams[i];
111                 if (ss->dir==stream_dir) return TRUE;
112                 /*compatibility check for phones that only used the null address and no attributes */
113                 if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr)))
114                         return TRUE;
115         }
116         return FALSE;
117 }
118
119 bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
120         if (stream_dir==SalStreamRecvOnly){
121                 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
122                 else return TRUE;
123         }else if (stream_dir==SalStreamSendOnly){
124                 if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
125                 else return TRUE;
126         }else if (stream_dir==SalStreamSendRecv){
127                 return has_dir(md,SalStreamSendRecv);
128         }else{
129                 /*SalStreamInactive*/
130                 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)  || has_dir(md,SalStreamRecvOnly))
131                         return FALSE;
132                 else return TRUE;
133         }
134         return FALSE;
135 }
136
137 /*
138 static bool_t fmtp_equals(const char *p1, const char *p2){
139         if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
140         if (p1==NULL && p2==NULL) return TRUE;
141         return FALSE;
142 }
143 */
144
145 static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
146         if (p1->type!=p2->type) return FALSE;
147         if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
148         if (p1->clock_rate!=p2->clock_rate) return FALSE;
149         if (p1->channels!=p2->channels) return FALSE;
150         if (payload_type_get_number(p1) != payload_type_get_number(p2)) return FALSE;
151         /*
152          Do not compare fmtp right now: they are modified internally when the call is started
153         */
154         /*
155         if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
156             !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
157                 return FALSE;
158         */
159         return TRUE;
160 }
161
162 static bool_t is_recv_only(PayloadType *p){
163         return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
164 }
165
166 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
167         const MSList *e1,*e2;
168         for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
169                 PayloadType *p1=(PayloadType*)e1->data;
170                 PayloadType *p2=(PayloadType*)e2->data;
171                 if (!payload_type_equals(p1,p2))
172                         return FALSE;
173         }
174         if (e1!=NULL){
175                 /*skip possible recv-only payloads*/
176                 for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
177                         ms_message("Skipping recv-only payload type...");
178                 }
179         }
180         if (e1!=NULL || e2!=NULL){
181                 /*means one list is longer than the other*/
182                 return FALSE;
183         }
184         return TRUE;
185 }
186
187 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
188         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
189         int i;
190
191         /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
192            needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
193         if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
194         for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
195                 if ((sd1->crypto[i].tag != sd2->crypto[i].tag)
196                         || (sd1->crypto[i].algo != sd2->crypto[i].algo)
197                         || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) {
198                         result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED;
199                 }
200         }
201
202         if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
203         if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
204         if (sd1->rtp_port != sd2->rtp_port) {
205                 if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
206                 else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
207         }
208         if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
209         if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
210         if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
211         if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
212         if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
213         if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
214
215         return result;
216 }
217
218 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
219         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
220         int i;
221
222         if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
223         if (md1->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
224         if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
225         for(i = 0; i < md1->n_total_streams; ++i){
226                 result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
227         }
228         return result;
229 }
230
231 static void assign_string(char **str, const char *arg){
232         if (*str){
233                 ms_free(*str);
234                 *str=NULL;
235         }
236         if (arg)
237                 *str=ms_strdup(arg);
238 }
239
240 void sal_op_set_contact(SalOp *op, const char *contact){
241         assign_string(&((SalOpBase*)op)->contact,contact);
242 }
243
244 void sal_op_set_route(SalOp *op, const char *route){
245         assign_string(&((SalOpBase*)op)->route,route);
246 }
247
248 void sal_op_set_from(SalOp *op, const char *from){
249         assign_string(&((SalOpBase*)op)->from,from);
250 }
251
252 void sal_op_set_to(SalOp *op, const char *to){
253         assign_string(&((SalOpBase*)op)->to,to);
254 }
255
256 void sal_op_set_user_pointer(SalOp *op, void *up){
257         ((SalOpBase*)op)->user_pointer=up;
258 }
259
260 Sal *sal_op_get_sal(const SalOp *op){
261         return ((SalOpBase*)op)->root;
262 }
263
264 const char *sal_op_get_from(const SalOp *op){
265         return ((SalOpBase*)op)->from;
266 }
267
268 const char *sal_op_get_to(const SalOp *op){
269         return ((SalOpBase*)op)->to;
270 }
271
272 const char *sal_op_get_contact(const SalOp *op){
273         return ((SalOpBase*)op)->contact;
274 }
275
276 const char *sal_op_get_remote_contact(const SalOp *op){
277         return ((SalOpBase*)op)->remote_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 void __sal_op_set_remote_contact(SalOp *op, const char *ct){
312         assign_string(&((SalOpBase*)op)->remote_contact,ct);
313 }
314
315 void __sal_op_free(SalOp *op){
316         SalOpBase *b=(SalOpBase *)op;
317         if (b->from) {
318                 ms_free(b->from);
319                 b->from=NULL;
320         }
321         if (b->to) {
322                 ms_free(b->to);
323                 b->to=NULL;
324         }
325         if (b->route) {
326                 ms_free(b->route);
327                 b->route=NULL;
328         }
329         if (b->contact) {
330                 ms_free(b->contact);
331                 b->contact=NULL;
332         }
333         if (b->origin){
334                 ms_free(b->origin);
335                 b->origin=NULL;
336         }
337         if (b->remote_ua){
338                 ms_free(b->remote_ua);
339                 b->remote_ua=NULL;
340         }
341         if (b->remote_contact){
342                 ms_free(b->remote_contact);
343                 b->remote_contact=NULL;
344         }
345         if (b->local_media)
346                 sal_media_description_unref(b->local_media);
347         if (b->remote_media)
348                 sal_media_description_unref(b->remote_media);
349         if (b->call_id)
350                 ms_free(b->call_id);
351         if (b->custom_headers)
352                 sal_custom_header_free(b->custom_headers);
353         ms_free(op);
354 }
355
356 SalAuthInfo* sal_auth_info_new() {
357         return ms_new0(SalAuthInfo,1);
358 }
359
360 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
361         SalAuthInfo* new_auth_info=sal_auth_info_new();
362         new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
363         new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
364         new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
365         new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
366         return new_auth_info;
367 }
368
369 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
370         if (auth_info->username) ms_free(auth_info->username);
371         if (auth_info->userid) ms_free(auth_info->userid);
372         if (auth_info->realm) ms_free(auth_info->realm);
373         if (auth_info->password) ms_free(auth_info->password);
374         ms_free((void*)auth_info);
375 }
376
377 SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
378         SalCustomHeader *h=ms_new0(SalCustomHeader,1);
379         h->header_name=ms_strdup(name);
380         h->header_value=ms_strdup(value);
381         h->node.data=h;
382         return (SalCustomHeader*)ms_list_append_link((MSList*)ch,(MSList*)h);
383 }
384
385 const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
386         const MSList *it;
387         for (it=(const MSList*)ch;it!=NULL;it=it->next){
388                 const SalCustomHeader *itch=(const SalCustomHeader *)it;
389                 if (strcasecmp(itch->header_name,name)==0)
390                         return itch->header_value;
391         }
392         return NULL;
393 }
394
395 static void sal_custom_header_uninit(SalCustomHeader *ch){
396         ms_free(ch->header_name);
397         ms_free(ch->header_value);
398 }
399
400 void sal_custom_header_free(SalCustomHeader *ch){
401         ms_list_for_each((MSList*)ch,(void (*)(void*))sal_custom_header_uninit);
402         ms_list_free((MSList *)ch);
403 }
404
405 SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){
406         const MSList *it;
407         SalCustomHeader *ret=NULL;
408         for (it=(const MSList*)ch;it!=NULL;it=it->next){
409                 const SalCustomHeader *itch=(const SalCustomHeader *)it;
410                 ret=sal_custom_header_append(ret,itch->header_name,itch->header_value);
411         }
412         return ret;
413 }
414
415 const SalCustomHeader *sal_op_get_custom_header(SalOp *op){
416         SalOpBase *b=(SalOpBase *)op;
417         return b->custom_headers;
418 }
419
420 /*
421  * Warning: this function takes owneship of the custom headers
422  */
423 void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch){
424         SalOpBase *b=(SalOpBase *)op;
425         if (b->custom_headers){
426                 sal_custom_header_free(b->custom_headers);
427                 b->custom_headers=NULL;
428         }
429         b->custom_headers=ch;
430 }
431
432
433