]> sjero.net Git - linphone/blob - coreapi/sal.c
Allow update of SRTP crypto keys without restarting the media streams.
[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         /*
155          Do not compare fmtp right now: they are modified internally when the call is started
156         */
157         /*
158         if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
159             !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
160                 return FALSE;
161         */
162         return TRUE;
163 }
164
165 static bool_t is_recv_only(PayloadType *p){
166         return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
167 }
168
169 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
170         const MSList *e1,*e2;
171         for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
172                 PayloadType *p1=(PayloadType*)e1->data;
173                 PayloadType *p2=(PayloadType*)e2->data;
174                 if (!payload_type_equals(p1,p2))
175                         return FALSE;
176         }
177         if (e1!=NULL){
178                 /*skip possible recv-only payloads*/
179                 for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
180                         ms_message("Skipping recv-only payload type...");
181                 }
182         }
183         if (e1!=NULL || e2!=NULL){
184                 /*means one list is longer than the other*/
185                 return FALSE;
186         }
187         return TRUE;
188 }
189
190 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
191         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
192         int i;
193
194         /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
195            needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
196         if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
197         for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
198                 if ((sd1->crypto[i].tag != sd2->crypto[i].tag)
199                         || (sd1->crypto[i].algo != sd2->crypto[i].algo)
200                         || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) {
201                         result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED;
202                 }
203         }
204
205         if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
206         if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
207         if (sd1->rtp_port != sd2->rtp_port) {
208                 if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
209                 else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
210         }
211         if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
212         if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
213         if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
214         if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
215         if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
216         if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
217
218         return result;
219 }
220
221 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
222         int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
223         int i;
224
225         if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
226         if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
227         if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
228         for(i = 0; i < md1->nstreams; ++i){
229                 result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
230         }
231         return result;
232 }
233
234 static void assign_string(char **str, const char *arg){
235         if (*str){
236                 ms_free(*str);
237                 *str=NULL;
238         }
239         if (arg)
240                 *str=ms_strdup(arg);
241 }
242
243 void sal_op_set_contact(SalOp *op, const char *contact){
244         assign_string(&((SalOpBase*)op)->contact,contact);
245 }
246
247 void sal_op_set_route(SalOp *op, const char *route){
248         assign_string(&((SalOpBase*)op)->route,route);
249 }
250
251 void sal_op_set_from(SalOp *op, const char *from){
252         assign_string(&((SalOpBase*)op)->from,from);
253 }
254
255 void sal_op_set_to(SalOp *op, const char *to){
256         assign_string(&((SalOpBase*)op)->to,to);
257 }
258
259 void sal_op_set_user_pointer(SalOp *op, void *up){
260         ((SalOpBase*)op)->user_pointer=up;
261 }
262
263 Sal *sal_op_get_sal(const SalOp *op){
264         return ((SalOpBase*)op)->root;
265 }
266
267 const char *sal_op_get_from(const SalOp *op){
268         return ((SalOpBase*)op)->from;
269 }
270
271 const char *sal_op_get_to(const SalOp *op){
272         return ((SalOpBase*)op)->to;
273 }
274
275 const char *sal_op_get_contact(const SalOp *op){
276         return ((SalOpBase*)op)->contact;
277 }
278
279 const char *sal_op_get_route(const SalOp *op){
280         return ((SalOpBase*)op)->route;
281 }
282
283 const char *sal_op_get_remote_ua(const SalOp *op){
284         return ((SalOpBase*)op)->remote_ua;
285 }
286
287 void *sal_op_get_user_pointer(const SalOp *op){
288         return ((SalOpBase*)op)->user_pointer;
289 }
290
291 const char *sal_op_get_proxy(const SalOp *op){
292         return ((SalOpBase*)op)->route;
293 }
294
295 const char *sal_op_get_network_origin(const SalOp *op){
296         return ((SalOpBase*)op)->origin;
297 }
298 const char* sal_op_get_call_id(const SalOp *op) {
299         return  ((SalOpBase*)op)->call_id;
300 }
301 void __sal_op_init(SalOp *b, Sal *sal){
302         memset(b,0,sizeof(SalOpBase));
303         ((SalOpBase*)b)->root=sal;
304 }
305
306 void __sal_op_set_network_origin(SalOp *op, const char *origin){
307         assign_string(&((SalOpBase*)op)->origin,origin);
308 }
309
310
311 void __sal_op_free(SalOp *op){
312         SalOpBase *b=(SalOpBase *)op;
313         if (b->from) {
314                 ms_free(b->from);
315                 b->from=NULL;
316         }
317         if (b->to) {
318                 ms_free(b->to);
319                 b->to=NULL;
320         }
321         if (b->route) {
322                 ms_free(b->route);
323                 b->route=NULL;
324         }
325         if (b->contact) {
326                 ms_free(b->contact);
327                 b->contact=NULL;
328         }
329         if (b->origin){
330                 ms_free(b->origin);
331                 b->origin=NULL;
332         }
333         if (b->remote_ua){
334                 ms_free(b->remote_ua);
335                 b->remote_ua=NULL;
336         }
337         if (b->local_media)
338                 sal_media_description_unref(b->local_media);
339         if (b->remote_media)
340                 sal_media_description_unref(b->remote_media);
341         if (b->call_id)
342                 ms_free((void*)b->call_id);
343         ms_free(op);
344 }
345
346 SalAuthInfo* sal_auth_info_new() {
347         return ms_new0(SalAuthInfo,1);
348 }
349
350 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
351         SalAuthInfo* new_auth_info=sal_auth_info_new();
352         new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
353         new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
354         new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
355         new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
356         return new_auth_info;
357 }
358
359 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
360         if (auth_info->username) ms_free(auth_info->username);
361         if (auth_info->userid) ms_free(auth_info->userid);
362         if (auth_info->realm) ms_free(auth_info->realm);
363         if (auth_info->password) ms_free(auth_info->password);
364         ms_free((void*)auth_info);
365 }
366