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;
155 Do not compare fmtp right now: they are modified internally when the call is started
158 if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
159 !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
165 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
166 const MSList *e1,*e2;
167 for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
168 PayloadType *p1=(PayloadType*)e1->data;
169 PayloadType *p2=(PayloadType*)e2->data;
170 if (!payload_type_equals(p1,p2))
173 if (e1!=NULL || e2!=NULL){
174 /*means one list is longer than the other*/
180 bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
181 if (sd1->proto!=sd2->proto) return FALSE;
182 if (sd1->type!=sd2->type) return FALSE;
183 if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE;
184 if (sd1->rtp_port!=sd2->rtp_port) return FALSE;
185 if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
186 if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
187 if (sd1->ptime!=sd2->ptime) return FALSE;
188 /* compare candidates: TODO */
189 if (sd1->dir!=sd2->dir) return FALSE;
193 bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
196 if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
197 if (md1->nstreams!=md2->nstreams) return FALSE;
198 if (md1->bandwidth!=md2->bandwidth) return FALSE;
199 for(i=0;i<md1->nstreams;++i){
200 if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
206 static void assign_string(char **str, const char *arg){
215 void sal_op_set_contact(SalOp *op, const char *contact){
216 assign_string(&((SalOpBase*)op)->contact,contact);
219 void sal_op_set_route(SalOp *op, const char *route){
220 assign_string(&((SalOpBase*)op)->route,route);
223 void sal_op_set_from(SalOp *op, const char *from){
224 assign_string(&((SalOpBase*)op)->from,from);
227 void sal_op_set_to(SalOp *op, const char *to){
228 assign_string(&((SalOpBase*)op)->to,to);
231 void sal_op_set_user_pointer(SalOp *op, void *up){
232 ((SalOpBase*)op)->user_pointer=up;
235 void sal_op_set_ice_session(SalOp *op, IceSession *ice_session){
236 ((SalOpBase*)op)->ice_session=ice_session;
239 Sal *sal_op_get_sal(const SalOp *op){
240 return ((SalOpBase*)op)->root;
243 const char *sal_op_get_from(const SalOp *op){
244 return ((SalOpBase*)op)->from;
247 const char *sal_op_get_to(const SalOp *op){
248 return ((SalOpBase*)op)->to;
251 const char *sal_op_get_contact(const SalOp *op){
252 return ((SalOpBase*)op)->contact;
255 const char *sal_op_get_route(const SalOp *op){
256 return ((SalOpBase*)op)->route;
259 const char *sal_op_get_remote_ua(const SalOp *op){
260 return ((SalOpBase*)op)->remote_ua;
263 void *sal_op_get_user_pointer(const SalOp *op){
264 return ((SalOpBase*)op)->user_pointer;
267 IceSession *sal_op_get_ice_session(const SalOp *op){
268 return ((SalOpBase*)op)->ice_session;
271 const char *sal_op_get_proxy(const SalOp *op){
272 return ((SalOpBase*)op)->route;
275 const char *sal_op_get_network_origin(const SalOp *op){
276 return ((SalOpBase*)op)->origin;
279 void __sal_op_init(SalOp *b, Sal *sal){
280 memset(b,0,sizeof(SalOpBase));
281 ((SalOpBase*)b)->root=sal;
284 void __sal_op_set_network_origin(SalOp *op, const char *origin){
285 assign_string(&((SalOpBase*)op)->origin,origin);
289 void __sal_op_free(SalOp *op){
290 SalOpBase *b=(SalOpBase *)op;
312 ms_free(b->remote_ua);
316 sal_media_description_unref(b->local_media);
318 sal_media_description_unref(b->remote_media);
320 ice_session_destroy(b->ice_session);
324 SalAuthInfo* sal_auth_info_new() {
325 return ms_new0(SalAuthInfo,1);
328 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
329 SalAuthInfo* new_auth_info=sal_auth_info_new();
330 new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
331 new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
332 new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
333 new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
334 return new_auth_info;
337 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
338 if (auth_info->username) ms_free(auth_info->username);
339 if (auth_info->userid) ms_free(auth_info->userid);
340 if (auth_info->realm) ms_free(auth_info->realm);
341 if (auth_info->password) ms_free(auth_info->password);
342 ms_free((void*)auth_info);