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->n_active_streams;++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){
87 if (md->n_active_streams > 0) return FALSE;
91 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
93 for(i=0;i<md->n_active_streams;++i){
94 SalStreamDescription *ss=&md->streams[i];
100 static bool_t is_null_address(const char *addr){
101 return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
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){
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)))
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;
123 }else if (stream_dir==SalStreamSendOnly){
124 if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
126 }else if (stream_dir==SalStreamSendRecv){
127 return has_dir(md,SalStreamSendRecv);
129 /*SalStreamInactive*/
130 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv) || has_dir(md,SalStreamRecvOnly))
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;
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;
152 Do not compare fmtp right now: they are modified internally when the call is started
155 if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
156 !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
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);
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))
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...");
180 if (e1!=NULL || e2!=NULL){
181 /*means one list is longer than the other*/
187 int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
188 int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
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;
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;
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;
218 int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
219 int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
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]);
231 static void assign_string(char **str, const char *arg){
240 void sal_op_set_contact(SalOp *op, const char *contact){
241 assign_string(&((SalOpBase*)op)->contact,contact);
244 void sal_op_set_route(SalOp *op, const char *route){
245 assign_string(&((SalOpBase*)op)->route,route);
248 void sal_op_set_from(SalOp *op, const char *from){
249 assign_string(&((SalOpBase*)op)->from,from);
252 void sal_op_set_to(SalOp *op, const char *to){
253 assign_string(&((SalOpBase*)op)->to,to);
256 void sal_op_set_user_pointer(SalOp *op, void *up){
257 ((SalOpBase*)op)->user_pointer=up;
260 Sal *sal_op_get_sal(const SalOp *op){
261 return ((SalOpBase*)op)->root;
264 const char *sal_op_get_from(const SalOp *op){
265 return ((SalOpBase*)op)->from;
268 const char *sal_op_get_to(const SalOp *op){
269 return ((SalOpBase*)op)->to;
272 const char *sal_op_get_contact(const SalOp *op){
273 return ((SalOpBase*)op)->contact;
276 const char *sal_op_get_route(const SalOp *op){
277 return ((SalOpBase*)op)->route;
280 const char *sal_op_get_remote_ua(const SalOp *op){
281 return ((SalOpBase*)op)->remote_ua;
284 void *sal_op_get_user_pointer(const SalOp *op){
285 return ((SalOpBase*)op)->user_pointer;
288 const char *sal_op_get_proxy(const SalOp *op){
289 return ((SalOpBase*)op)->route;
292 const char *sal_op_get_network_origin(const SalOp *op){
293 return ((SalOpBase*)op)->origin;
295 const char* sal_op_get_call_id(const SalOp *op) {
296 return ((SalOpBase*)op)->call_id;
298 void __sal_op_init(SalOp *b, Sal *sal){
299 memset(b,0,sizeof(SalOpBase));
300 ((SalOpBase*)b)->root=sal;
303 void __sal_op_set_network_origin(SalOp *op, const char *origin){
304 assign_string(&((SalOpBase*)op)->origin,origin);
308 void __sal_op_free(SalOp *op){
309 SalOpBase *b=(SalOpBase *)op;
331 ms_free(b->remote_ua);
335 sal_media_description_unref(b->local_media);
337 sal_media_description_unref(b->remote_media);
339 ms_free((void*)b->call_id);
343 SalAuthInfo* sal_auth_info_new() {
344 return ms_new0(SalAuthInfo,1);
347 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
348 SalAuthInfo* new_auth_info=sal_auth_info_new();
349 new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
350 new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
351 new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
352 new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
353 return new_auth_info;
356 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
357 if (auth_info->username) ms_free(auth_info->username);
358 if (auth_info->userid) ms_free(auth_info->userid);
359 if (auth_info->realm) ms_free(auth_info->realm);
360 if (auth_info->password) ms_free(auth_info->password);
361 ms_free((void*)auth_info);