3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
\r
5 This program is free software; you can redistribute it and/or
\r
6 modify it under the terms of the GNU General Public License
\r
7 as published by the Free Software Foundation; either version 2
\r
8 of the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU General Public License for more details.
\r
15 You should have received a copy of the GNU General Public License
\r
16 along with this program; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
19 #ifdef HAVE_CONFIG_H
\r
23 #include "sal_eXosip2.h"
\r
24 #include "offeranswer.h"
\r
27 // Necessary to make it linked
\r
28 static void for_linker() { eXosip_transport_hook_register(NULL); }
\r
30 static bool_t call_failure(Sal *sal, eXosip_event_t *ev);
\r
32 static void text_received(Sal *sal, eXosip_event_t *ev);
\r
34 static void masquerade_via(osip_message_t *msg, const char *ip, const char *port);
\r
35 static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact);
\r
36 static void update_contact_from_response(SalOp *op, osip_message_t *response);
\r
39 void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
\r
41 while(!osip_list_eol(l,0)) {
\r
42 data=osip_list_get(l,0);
\r
43 osip_list_remove(l,0);
\r
44 if (data) freefunc(data);
\r
48 void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){
\r
49 if (eXosip_guess_localip(address_family,ip,iplen)<0){
\r
50 /*default to something */
\r
51 strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);
\r
52 ms_error("Could not find default routable ip address !");
\r
56 static SalOp * sal_find_call(Sal *sal, int cid){
\r
59 for(elem=sal->calls;elem!=NULL;elem=elem->next){
\r
60 op=(SalOp*)elem->data;
\r
61 if (op->cid==cid) return op;
\r
66 static void sal_add_call(Sal *sal, SalOp *op){
\r
67 sal->calls=ms_list_append(sal->calls,op);
\r
70 static void sal_remove_call(Sal *sal, SalOp *op){
\r
71 sal->calls=ms_list_remove(sal->calls, op);
\r
74 static SalOp * sal_find_register(Sal *sal, int rid){
\r
77 for(elem=sal->registers;elem!=NULL;elem=elem->next){
\r
78 op=(SalOp*)elem->data;
\r
79 if (op->rid==rid) return op;
\r
84 static void sal_add_register(Sal *sal, SalOp *op){
\r
85 sal->registers=ms_list_append(sal->registers,op);
\r
88 static void sal_remove_register(Sal *sal, int rid){
\r
91 for(elem=sal->registers;elem!=NULL;elem=elem->next){
\r
92 op=(SalOp*)elem->data;
\r
94 sal->registers=ms_list_remove_link(sal->registers,elem);
\r
100 static SalOp * sal_find_other(Sal *sal, osip_message_t *message){
\r
101 const MSList *elem;
\r
103 osip_call_id_t *callid=osip_message_get_call_id(message);
\r
104 if (callid==NULL) {
\r
105 ms_error("There is no call-id in this message !");
\r
108 for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){
\r
109 op=(SalOp*)elem->data;
\r
110 if (osip_call_id_match(callid,op->call_id)==0) return op;
\r
115 void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){
\r
116 osip_call_id_t *callid=osip_message_get_call_id(request);
\r
117 if (callid==NULL) {
\r
118 ms_error("There is no call id in the request !");
\r
121 osip_call_id_clone(callid,&op->call_id);
\r
122 sal->other_transactions=ms_list_append(sal->other_transactions,op);
\r
125 static void sal_remove_other(Sal *sal, SalOp *op){
\r
126 sal->other_transactions=ms_list_remove(sal->other_transactions,op);
\r
130 static void sal_add_pending_auth(Sal *sal, SalOp *op){
\r
131 sal->pending_auths=ms_list_append(sal->pending_auths,op);
\r
135 static void sal_remove_pending_auth(Sal *sal, SalOp *op){
\r
136 sal->pending_auths=ms_list_remove(sal->pending_auths,op);
\r
139 void sal_exosip_fix_route(SalOp *op){
\r
140 if (sal_op_get_route(op)!=NULL){
\r
141 osip_route_t *rt=NULL;
\r
142 osip_uri_param_t *lr_param=NULL;
\r
144 osip_route_init(&rt);
\r
145 if (osip_route_parse(rt,sal_op_get_route(op))<0){
\r
146 ms_warning("Bad route %s!",sal_op_get_route(op));
\r
147 sal_op_set_route(op,NULL);
\r
149 /* check if the lr parameter is set , if not add it */
\r
150 osip_uri_uparam_get_byname(rt->url, "lr", &lr_param);
\r
151 if (lr_param==NULL){
\r
153 osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
\r
154 osip_route_to_str(rt,&tmproute);
\r
155 sal_op_set_route(op,tmproute);
\r
156 osip_free(tmproute);
\r
159 osip_route_free(rt);
\r
163 SalOp * sal_op_new(Sal *sal){
\r
164 SalOp *op=ms_new0(SalOp,1);
\r
165 __sal_op_init(op,sal);
\r
166 op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;
\r
168 op->supports_session_timers=FALSE;
\r
169 op->sdp_offering=TRUE;
\r
170 op->pending_auth=NULL;
\r
171 op->sdp_answer=NULL;
\r
172 op->reinvite=FALSE;
\r
175 op->referred_by=NULL;
\r
176 op->masquerade_via=FALSE;
\r
177 op->auto_answer_asked=FALSE;
\r
178 op->auth_info=NULL;
\r
179 op->terminated=FALSE;
\r
183 bool_t sal_call_autoanswer_asked(SalOp *op)
\r
185 return op->auto_answer_asked;
\r
188 void sal_op_release(SalOp *op){
\r
189 if (op->sdp_answer)
\r
190 sdp_message_free(op->sdp_answer);
\r
191 if (op->pending_auth)
\r
192 eXosip_event_free(op->pending_auth);
\r
194 sal_remove_register(op->base.root,op->rid);
\r
195 eXosip_register_remove(op->rid);
\r
198 ms_message("Cleaning cid %i",op->cid);
\r
199 sal_remove_call(op->base.root,op);
\r
202 sal_remove_out_subscribe(op->base.root,op);
\r
205 sal_remove_in_subscribe(op->base.root,op);
\r
207 osip_call_id_free(op->call_id);
\r
210 if (op->pending_auth){
\r
211 sal_remove_pending_auth(op->base.root,op);
\r
214 sal_media_description_unref(op->result);
\r
216 sal_remove_other(op->base.root,op);
\r
217 osip_call_id_free(op->call_id);
\r
220 ms_free(op->replaces);
\r
222 if (op->referred_by){
\r
223 ms_free(op->referred_by);
\r
225 if (op->auth_info) {
\r
226 sal_auth_info_delete(op->auth_info);
\r
231 static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){
\r
232 int ortp_level=ORTP_DEBUG;
\r
238 ortp_level=ORTP_MESSAGE;
\r
241 ortp_level=ORTP_WARNING;
\r
245 ortp_level=ORTP_ERROR;
\r
248 ortp_level=ORTP_FATAL;
\r
250 case END_TRACE_LEVEL:
\r
253 if (ortp_log_level_enabled(level)){
\r
254 int len=strlen(chfr);
\r
255 char *chfrdup=ortp_strdup(chfr);
\r
256 /*need to remove endline*/
\r
258 if (chfrdup[len-1]=='\n')
\r
259 chfrdup[len-1]='\0';
\r
260 if (chfrdup[len-2]=='\r')
\r
261 chfrdup[len-2]='\0';
\r
263 ortp_logv(ortp_level,chfrdup,ap);
\r
264 ortp_free(chfrdup);
\r
270 static bool_t firsttime=TRUE;
\r
273 osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func);
\r
277 sal=ms_new0(Sal,1);
\r
278 sal->keepalive_period=30;
\r
279 sal->double_reg=TRUE;
\r
280 sal->use_rports=TRUE;
\r
282 sal->reuse_authorization=FALSE;
\r
284 sal->verify_server_certs=TRUE;
\r
285 sal->verify_server_cn=TRUE;
\r
286 sal->expire_old_contact=FALSE;
\r
287 sal->add_dates=FALSE;
\r
292 void sal_uninit(Sal* sal){
\r
295 ms_free(sal->rootCa);
\r
299 void sal_set_user_pointer(Sal *sal, void *user_data){
\r
303 void *sal_get_user_pointer(const Sal *sal){
\r
307 static void unimplemented_stub(){
\r
308 ms_warning("Unimplemented SAL callback");
\r
311 void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
\r
312 memcpy(&ctx->callbacks,cbs,sizeof(*cbs));
\r
313 if (ctx->callbacks.call_received==NULL)
\r
314 ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub;
\r
315 if (ctx->callbacks.call_ringing==NULL)
\r
316 ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub;
\r
317 if (ctx->callbacks.call_accepted==NULL)
\r
318 ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub;
\r
319 if (ctx->callbacks.call_failure==NULL)
\r
320 ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
\r
321 if (ctx->callbacks.call_terminated==NULL)
\r
322 ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
\r
323 if (ctx->callbacks.call_released==NULL)
\r
324 ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;
\r
325 if (ctx->callbacks.call_updating==NULL)
\r
326 ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
\r
327 if (ctx->callbacks.auth_requested==NULL)
\r
328 ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
\r
329 if (ctx->callbacks.auth_success==NULL)
\r
330 ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub;
\r
331 if (ctx->callbacks.register_success==NULL)
\r
332 ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub;
\r
333 if (ctx->callbacks.register_failure==NULL)
\r
334 ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub;
\r
335 if (ctx->callbacks.dtmf_received==NULL)
\r
336 ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub;
\r
337 if (ctx->callbacks.notify==NULL)
\r
338 ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;
\r
339 if (ctx->callbacks.notify_presence==NULL)
\r
340 ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
\r
341 if (ctx->callbacks.subscribe_received==NULL)
\r
342 ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
\r
343 if (ctx->callbacks.text_received==NULL)
\r
344 ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
\r
345 if (ctx->callbacks.ping_reply==NULL)
\r
346 ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
\r
349 int sal_unlisten_ports(Sal *ctx){
\r
353 ctx->running=FALSE;
\r
358 int sal_reset_transports(Sal *ctx){
\r
359 #ifdef HAVE_EXOSIP_RESET_TRANSPORTS
\r
361 ms_message("Exosip transports reset.");
\r
362 eXosip_reset_transports();
\r
366 ms_warning("sal_reset_transports() not implemented in this version.");
\r
372 static void set_tls_options(Sal *ctx){
\r
374 eXosip_tls_ctx_t tlsCtx;
\r
375 memset(&tlsCtx, 0, sizeof(tlsCtx));
\r
376 snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);
\r
377 eXosip_set_tls_ctx(&tlsCtx);
\r
379 #ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
\r
380 eXosip_tls_verify_certificate(ctx->verify_server_certs);
\r
382 #ifdef HAVE_EXOSIP_TLS_VERIFY_CN
\r
383 eXosip_tls_verify_cn(ctx->verify_server_cn);
\r
387 void sal_set_dscp(Sal *ctx, int dscp){
\r
389 #ifdef HAVE_EXOSIP_DSCP
\r
391 eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);
\r
395 int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
\r
398 int proto=IPPROTO_UDP;
\r
399 int keepalive = ctx->keepalive_period;
\r
401 ctx->transport = tr;
\r
403 case SalTransportUDP:
\r
405 eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive);
\r
407 case SalTransportTCP:
\r
408 case SalTransportTLS:
\r
409 proto= IPPROTO_TCP;
\r
410 if (!ctx->tcp_tls_keepalive) keepalive=-1;
\r
411 eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);
\r
412 set_tls_options(ctx);
\r
415 ms_warning("unexpected proto, using datagram");
\r
417 /*see if it looks like an IPv6 address*/
\r
418 int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment
\r
419 eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);
\r
420 int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment
\r
421 eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);
\r
422 sal_set_dscp(ctx,ctx->dscp);
\r
423 sal_use_dates(ctx,ctx->add_dates);
\r
425 ipv6=strchr(addr,':')!=NULL;
\r
426 eXosip_enable_ipv6(ipv6);
\r
428 if (is_secure && tr == SalTransportUDP){
\r
429 ms_fatal("SIP over DTLS is not supported yet.");
\r
432 err=eXosip_listen_addr(proto, addr, port, ipv6 ? PF_INET6 : PF_INET, is_secure);
\r
437 ortp_socket_t sal_get_socket(Sal *ctx){
\r
438 #ifdef HAVE_EXOSIP_GET_SOCKET
\r
439 return eXosip_get_socket(IPPROTO_UDP);
\r
441 ms_warning("Sorry, eXosip does not have eXosip_get_socket() method");
\r
446 void sal_set_user_agent(Sal *ctx, const char *user_agent){
\r
447 eXosip_set_user_agent(user_agent);
\r
450 void sal_use_session_timers(Sal *ctx, int expires){
\r
451 ctx->session_expires=expires;
\r
454 void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
\r
455 ctx->one_matching_codec=one_matching_codec;
\r
458 MSList *sal_get_pending_auths(Sal *sal){
\r
459 return ms_list_copy(sal->pending_auths);
\r
462 void sal_use_double_registrations(Sal *ctx, bool_t enabled){
\r
463 ctx->double_reg=enabled;
\r
466 void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
\r
467 ctx->expire_old_contact=enabled;
\r
470 void sal_use_dates(Sal *ctx, bool_t enabled){
\r
471 ctx->add_dates=enabled;
\r
472 #ifdef EXOSIP_OPT_REGISTER_WITH_DATE
\r
475 eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);
\r
478 if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");
\r
482 void sal_use_rport(Sal *ctx, bool_t use_rports){
\r
483 ctx->use_rports=use_rports;
\r
485 void sal_use_101(Sal *ctx, bool_t use_101){
\r
486 ctx->use_101=use_101;
\r
489 void sal_set_root_ca(Sal* ctx, const char* rootCa) {
\r
491 ms_free(ctx->rootCa);
\r
492 ctx->rootCa = ms_strdup(rootCa);
\r
493 set_tls_options(ctx);
\r
496 const char *sal_get_root_ca(Sal* ctx) {
\r
497 return ctx->rootCa;
\r
500 void sal_verify_server_certificates(Sal *ctx, bool_t verify){
\r
501 ctx->verify_server_certs=verify;
\r
502 #ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
\r
503 eXosip_tls_verify_certificate(verify);
\r
507 void sal_verify_server_cn(Sal *ctx, bool_t verify){
\r
508 ctx->verify_server_cn=verify;
\r
509 #ifdef HAVE_EXOSIP_TLS_VERIFY_CN
\r
510 eXosip_tls_verify_cn(verify);
\r
514 static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){
\r
515 osip_via_t *via=NULL;
\r
516 osip_generic_param_t *param=NULL;
\r
517 const char *rport=NULL;
\r
521 osip_message_get_via(msg,0,&via);
\r
523 ms_warning("extract_received_rport(): no via.");
\r
527 *transport = sal_transport_parse(via->protocol);
\r
529 if (via->port && via->port[0]!='\0')
\r
530 *rportval=atoi(via->port);
\r
532 osip_via_param_get_byname(via,"rport",¶m);
\r
534 rport=param->gvalue;
\r
535 if (rport && rport[0]!='\0') *rportval=atoi(rport);
\r
536 *received=via->host;
\r
539 osip_via_param_get_byname(via,"received",¶m);
\r
540 if (param) *received=param->gvalue;
\r
542 if (rport==NULL && *received==NULL){
\r
543 ms_warning("extract_received_rport(): no rport and no received parameters.");
\r
549 static void set_sdp(osip_message_t *sip,sdp_message_t *msg){
\r
553 sdp_message_to_str(msg,&sdp);
\r
554 sdplen=strlen(sdp);
\r
555 snprintf(clen,sizeof(clen),"%i",sdplen);
\r
556 osip_message_set_body(sip,sdp,sdplen);
\r
557 osip_message_set_content_type(sip,"application/sdp");
\r
558 osip_message_set_content_length(sip,clen);
\r
562 static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){
\r
563 sdp_message_t *msg=media_description_to_sdp(desc);
\r
565 ms_error("Fail to print sdp message !");
\r
569 sdp_message_free(msg);
\r
572 static void sdp_process(SalOp *h){
\r
573 ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");
\r
575 sal_media_description_unref(h->result);
\r
577 h->result=sal_media_description_new();
\r
578 if (h->sdp_offering){
\r
579 offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
\r
582 if (h->sdp_answer){
\r
583 sdp_message_free(h->sdp_answer);
\r
585 offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
\r
586 h->sdp_answer=media_description_to_sdp(h->result);
\r
587 /*once we have generated the SDP answer, we modify the result description for processing by the upper layer.
\r
588 It should contains media parameters constraint from the remote offer, not our response*/
\r
589 strcpy(h->result->addr,h->base.remote_media->addr);
\r
590 h->result->bandwidth=h->base.remote_media->bandwidth;
\r
592 for(i=0;i<h->result->n_active_streams;++i){
\r
593 strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
\r
594 strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
\r
595 h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
\r
596 h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
\r
597 h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
\r
598 h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
\r
599 if (h->result->streams[i].proto == SalProtoRtpSavp) {
\r
600 h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
\r
607 int sal_call_is_offerer(const SalOp *h){
\r
608 return h->sdp_offering;
\r
611 int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){
\r
613 sal_media_description_ref(desc);
\r
614 if (h->base.local_media)
\r
615 sal_media_description_unref(h->base.local_media);
\r
616 h->base.local_media=desc;
\r
617 if (h->base.remote_media){
\r
618 /*case of an incoming call where we modify the local capabilities between the time
\r
619 * the call is ringing and it is accepted (for example if you want to accept without video*/
\r
620 /*reset the sdp answer so that it is computed again*/
\r
621 if (h->sdp_answer){
\r
622 sdp_message_free(h->sdp_answer);
\r
623 h->sdp_answer=NULL;
\r
629 int sal_call(SalOp *h, const char *from, const char *to){
\r
632 osip_message_t *invite=NULL;
\r
633 osip_call_id_t *callid;
\r
634 sal_op_set_from(h,from);
\r
635 sal_op_set_to(h,to);
\r
636 sal_exosip_fix_route(h);
\r
638 h->terminated = FALSE;
\r
640 route = sal_op_get_route(h);
\r
641 err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call");
\r
643 ms_error("Could not create call. Error %d (from=%s to=%s route=%s)",
\r
644 err, from, to, route);
\r
647 osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
\r
648 if (h->base.contact){
\r
649 _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free);
\r
650 osip_message_set_contact(invite,h->base.contact);
\r
652 if (h->base.root->session_expires!=0){
\r
653 osip_message_set_header(invite, "Session-expires", "200");
\r
654 osip_message_set_supported(invite, "timer");
\r
656 sal_exosip_add_custom_headers(invite,h->base.custom_headers);
\r
657 if (h->base.local_media){
\r
658 h->sdp_offering=TRUE;
\r
659 set_sdp_from_desc(invite,h->base.local_media);
\r
660 }else h->sdp_offering=FALSE;
\r
662 osip_message_set_header(invite,"Replaces",h->replaces);
\r
663 if (h->referred_by)
\r
664 osip_message_set_header(invite,"Referred-By",h->referred_by);
\r
668 err=eXosip_call_send_initial_invite(invite);
\r
672 ms_error("Fail to send invite ! Error code %d", err);
\r
676 callid=osip_message_get_call_id(invite);
\r
677 osip_call_id_to_str(callid,&tmp);
\r
678 h->base.call_id=ms_strdup(tmp);
\r
680 sal_add_call(h->base.root,h);
\r
685 int sal_call_notify_ringing(SalOp *h, bool_t early_media){
\r
686 osip_message_t *msg;
\r
688 /*if early media send also 180 and 183 */
\r
692 eXosip_call_build_answer(h->tid,183,&msg);
\r
695 if (h->sdp_answer){
\r
696 set_sdp(msg,h->sdp_answer);
\r
697 sdp_message_free(h->sdp_answer);
\r
698 h->sdp_answer=NULL;
\r
700 eXosip_call_send_answer(h->tid,183,msg);
\r
705 eXosip_call_send_answer(h->tid,180,NULL);
\r
711 int sal_call_accept(SalOp * h){
\r
712 osip_message_t *msg;
\r
713 const char *contact=sal_op_get_contact(h);
\r
714 /* sends a 200 OK */
\r
715 int err=eXosip_call_build_answer(h->tid,200,&msg);
\r
716 if (err<0 || msg==NULL){
\r
717 ms_error("Fail to build answer for call: err=%i",err);
\r
720 if (h->base.root->session_expires!=0){
\r
721 if (h->supports_session_timers) osip_message_set_supported(msg, "timer");
\r
725 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
\r
726 osip_message_set_contact(msg,contact);
\r
729 if (h->base.local_media){
\r
730 /*this is the case where we received an invite without SDP*/
\r
731 if (h->sdp_offering) {
\r
732 set_sdp_from_desc(msg,h->base.local_media);
\r
734 if (h->sdp_answer==NULL) sdp_process(h);
\r
735 if (h->sdp_answer){
\r
736 set_sdp(msg,h->sdp_answer);
\r
737 sdp_message_free(h->sdp_answer);
\r
738 h->sdp_answer=NULL;
\r
742 ms_error("You are accepting a call but not defined any media capabilities !");
\r
744 eXosip_call_send_answer(h->tid,200,msg);
\r
748 int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){
\r
749 if (reason==SalReasonBusy){
\r
751 eXosip_call_send_answer(h->tid,486,NULL);
\r
754 else if (reason==SalReasonTemporarilyUnavailable){
\r
756 eXosip_call_send_answer(h->tid,480,NULL);
\r
758 }else if (reason==SalReasonDoNotDisturb){
\r
760 eXosip_call_send_answer(h->tid,600,NULL);
\r
762 }else if (reason==SalReasonMedia){
\r
764 eXosip_call_send_answer(h->tid,415,NULL);
\r
766 }else if (redirect!=NULL && reason==SalReasonRedirect){
\r
767 osip_message_t *msg;
\r
769 if (strstr(redirect,"sip:")!=0) code=302;
\r
772 eXosip_call_build_answer(h->tid,code,&msg);
\r
773 osip_message_set_contact(msg,redirect);
\r
774 eXosip_call_send_answer(h->tid,code,msg);
\r
776 }else sal_call_terminate(h);
\r
780 SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
\r
781 return h->base.remote_media;
\r
784 SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
\r
785 if (h->base.local_media && h->base.remote_media && !h->result){
\r
791 int sal_call_set_referer(SalOp *h, SalOp *refered_call){
\r
792 if (refered_call->replaces)
\r
793 h->replaces=ms_strdup(refered_call->replaces);
\r
794 if (refered_call->referred_by)
\r
795 h->referred_by=ms_strdup(refered_call->referred_by);
\r
799 static int send_notify_for_refer(int did, const char *sipfrag){
\r
800 osip_message_t *msg;
\r
802 eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
\r
805 ms_warning("Could not build NOTIFY for refer.");
\r
808 osip_message_set_content_type(msg,"message/sipfrag");
\r
809 osip_message_set_header(msg,"Event","refer");
\r
810 osip_message_set_body(msg,sipfrag,strlen(sipfrag));
\r
811 eXosip_call_send_request(did,msg);
\r
816 /* currently only support to notify trying and 200Ok*/
\r
817 int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){
\r
818 if (newcall==NULL){
\r
820 send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
\r
822 else if (newcall->cid!=-1){
\r
823 if (newcall->did==-1){
\r
824 /* not yet established*/
\r
825 if (!newcall->terminated){
\r
827 send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
\r
830 if (!newcall->terminated){
\r
831 if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){
\r
832 /* we need previous notify transaction to complete, so buffer the request for later*/
\r
833 h->sipfrag_pending="SIP/2.0 200 Ok\r\n";
\r
841 int sal_ping(SalOp *op, const char *from, const char *to){
\r
842 osip_message_t *options=NULL;
\r
844 sal_op_set_from(op,from);
\r
845 sal_op_set_to(op,to);
\r
846 sal_exosip_fix_route(op);
\r
848 eXosip_options_build_request (&options, sal_op_get_to(op),
\r
849 sal_op_get_from(op),sal_op_get_route(op));
\r
851 if (op->base.root->session_expires!=0){
\r
852 osip_message_set_header(options, "Session-expires", "200");
\r
853 osip_message_set_supported(options, "timer");
\r
855 sal_add_other(sal_op_get_sal(op),op,options);
\r
856 return eXosip_options_send_request(options);
\r
861 int sal_call_refer(SalOp *h, const char *refer_to){
\r
862 osip_message_t *msg=NULL;
\r
865 eXosip_call_build_refer(h->did,refer_to, &msg);
\r
866 if (msg) err=eXosip_call_send_request(h->did, msg);
\r
872 int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){
\r
873 osip_message_t *msg=NULL;
\r
874 char referto[256]={0};
\r
877 if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){
\r
878 ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);
\r
882 eXosip_call_build_refer(h->did,referto, &msg);
\r
883 osip_message_set_header(msg,"Referred-By",h->base.from);
\r
884 if (msg) err=eXosip_call_send_request(h->did, msg);
\r
890 SalOp *sal_call_get_replaces(SalOp *h){
\r
891 if (h!=NULL && h->replaces!=NULL){
\r
894 cid=eXosip_call_find_by_replaces(h->replaces);
\r
897 SalOp *ret=sal_find_call(h->base.root,cid);
\r
904 int sal_call_send_dtmf(SalOp *h, char dtmf){
\r
905 osip_message_t *msg=NULL;
\r
906 char dtmf_body[128];
\r
910 eXosip_call_build_info(h->did,&msg);
\r
912 snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf);
\r
913 osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));
\r
914 osip_message_set_content_type(msg,"application/dtmf-relay");
\r
915 snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));
\r
916 osip_message_set_content_length(msg,clen);
\r
917 eXosip_call_send_request(h->did,msg);
\r
923 static void push_auth_to_exosip(const SalAuthInfo *info){
\r
924 const char *userid;
\r
925 if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;
\r
926 else userid=info->userid;
\r
927 ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm);
\r
928 eXosip_add_authentication_info (info->username,userid,
\r
929 info->password, NULL,info->realm);
\r
932 * Just for symmetry ;-)
\r
934 static void pop_auth_from_exosip() {
\r
935 eXosip_clear_authentication_info();
\r
938 int sal_call_terminate(SalOp *h){
\r
940 if (h == NULL) return -1;
\r
941 if (h->auth_info) push_auth_to_exosip(h->auth_info);
\r
943 err=eXosip_call_terminate(h->cid,h->did);
\r
945 if (!h->base.root->reuse_authorization) pop_auth_from_exosip();
\r
947 ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);
\r
949 h->terminated=TRUE;
\r
953 void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
\r
954 bool_t terminating=FALSE;
\r
955 if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) {
\r
958 if (h->terminated && !terminating) return;
\r
960 if (h->pending_auth){
\r
961 push_auth_to_exosip(info);
\r
963 /*FIXME exosip does not take into account this update register message*/
\r
965 if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) {
\r
969 update_contact_from_response(h,h->pending_auth->response);
\r
971 eXosip_default_action(h->pending_auth);
\r
973 ms_message("eXosip_default_action() done");
\r
974 if (!h->base.root->reuse_authorization) pop_auth_from_exosip();
\r
976 if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/
\r
977 h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/
\r
980 void sal_op_cancel_authentication(SalOp *h) {
\r
982 sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure");
\r
983 } else if (h->cid >0) {
\r
984 sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);
\r
986 ms_warning("Auth failure not handled");
\r
990 static void set_network_origin(SalOp *op, osip_message_t *req){
\r
991 const char *received=NULL;
\r
993 char origin[64]={0};
\r
994 SalTransport transport;
\r
995 if (extract_received_rport(req,&received,&rport,&transport)!=0){
\r
996 osip_via_t *via=NULL;
\r
998 osip_message_get_via(req,0,&via);
\r
999 received=osip_via_get_host(via);
\r
1000 tmp=osip_via_get_port(via);
\r
1001 if (tmp) rport=atoi(tmp);
\r
1003 if (transport != SalTransportUDP) {
\r
1004 snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport);
\r
1006 snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport));
\r
1008 __sal_op_set_network_origin(op,origin);
\r
1011 static void set_remote_ua(SalOp* op, osip_message_t *req){
\r
1012 if (op->base.remote_ua==NULL){
\r
1013 osip_header_t *h=NULL;
\r
1014 osip_message_get_user_agent(req,0,&h);
\r
1016 op->base.remote_ua=ms_strdup(h->hvalue);
\r
1021 static void set_remote_contact(SalOp* op, osip_message_t *req){
\r
1022 if (op->base.remote_contact==NULL){
\r
1023 osip_contact_t *h=NULL;
\r
1024 osip_message_get_contact(req,0,&h);
\r
1027 osip_contact_to_str(h,&tmp);
\r
1028 __sal_op_set_remote_contact(op,tmp);
\r
1034 static void set_replaces(SalOp *op, osip_message_t *req){
\r
1035 osip_header_t *h=NULL;
\r
1037 if (op->replaces){
\r
1038 ms_free(op->replaces);
\r
1039 op->replaces=NULL;
\r
1041 osip_message_header_get_byname(req,"replaces",0,&h);
\r
1043 if (h->hvalue && h->hvalue[0]!='\0'){
\r
1044 op->replaces=ms_strdup(h->hvalue);
\r
1049 static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
\r
1051 return sal_find_call(sal,ev->cid);
\r
1054 return sal_find_register(sal,ev->rid);
\r
1057 return sal_find_out_subscribe(sal,ev->sid);
\r
1060 return sal_find_in_subscribe(sal,ev->nid);
\r
1062 if (ev->response) return sal_find_other(sal,ev->response);
\r
1063 else if (ev->request) return sal_find_other(sal,ev->request);
\r
1067 static void inc_new_call(Sal *sal, eXosip_event_t *ev){
\r
1068 SalOp *op=sal_op_new(sal);
\r
1069 osip_from_t *from,*to;
\r
1070 osip_call_info_t *call_info;
\r
1072 sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
\r
1074 osip_call_id_t *callid=osip_message_get_call_id(ev->request);
\r
1076 osip_call_id_to_str(callid,&tmp);
\r
1077 op->base.call_id=ms_strdup(tmp);
\r
1080 set_network_origin(op,ev->request);
\r
1081 set_remote_contact(op,ev->request);
\r
1082 set_remote_ua(op,ev->request);
\r
1083 set_replaces(op,ev->request);
\r
1084 sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));
\r
1087 op->sdp_offering=FALSE;
\r
1088 op->base.remote_media=sal_media_description_new();
\r
1089 sdp_to_media_description(sdp,op->base.remote_media);
\r
1090 sdp_message_free(sdp);
\r
1091 }else op->sdp_offering=TRUE;
\r
1093 from=osip_message_get_from(ev->request);
\r
1094 to=osip_message_get_to(ev->request);
\r
1095 osip_from_to_str(from,&tmp);
\r
1096 sal_op_set_from(op,tmp);
\r
1098 osip_from_to_str(to,&tmp);
\r
1099 sal_op_set_to(op,tmp);
\r
1102 osip_message_get_call_info(ev->request,0,&call_info);
\r
1105 osip_call_info_to_str(call_info,&tmp);
\r
1106 if( strstr(tmp,"answer-after=") != NULL)
\r
1108 op->auto_answer_asked=TRUE;
\r
1109 ms_message("The caller asked to automatically answer the call(Emergency?)\n");
\r
1117 sal_add_call(op->base.root,op);
\r
1118 sal->callbacks.call_received(op);
\r
1121 static void handle_reinvite(Sal *sal, eXosip_event_t *ev){
\r
1122 SalOp *op=find_op(sal,ev);
\r
1123 sdp_message_t *sdp;
\r
1126 ms_warning("Reinvite for non-existing operation !");
\r
1129 op->reinvite=TRUE;
\r
1131 sdp=eXosip_get_sdp_info(ev->request);
\r
1132 if (op->base.remote_media){
\r
1133 sal_media_description_unref(op->base.remote_media);
\r
1134 op->base.remote_media=NULL;
\r
1137 sal_media_description_unref(op->result);
\r
1141 op->sdp_offering=FALSE;
\r
1142 op->base.remote_media=sal_media_description_new();
\r
1143 sdp_to_media_description(sdp,op->base.remote_media);
\r
1144 sdp_message_free(sdp);
\r
1147 op->sdp_offering=TRUE;
\r
1149 sal->callbacks.call_updating(op);
\r
1152 static void handle_ack(Sal *sal, eXosip_event_t *ev){
\r
1153 SalOp *op=find_op(sal,ev);
\r
1154 sdp_message_t *sdp;
\r
1157 ms_warning("ack for non-existing call !");
\r
1160 if (op->terminated) {
\r
1161 ms_warning("ack for terminated call, ignoring");
\r
1165 if (op->sdp_offering){
\r
1166 sdp=eXosip_get_sdp_info(ev->ack);
\r
1168 if (op->base.remote_media)
\r
1169 sal_media_description_unref(op->base.remote_media);
\r
1170 op->base.remote_media=sal_media_description_new();
\r
1171 sdp_to_media_description(sdp,op->base.remote_media);
\r
1173 sdp_message_free(sdp);
\r
1176 if (op->reinvite){
\r
1177 op->reinvite=FALSE;
\r
1179 sal->callbacks.call_ack(op);
\r
1182 static void update_contact_from_response(SalOp *op, osip_message_t *response){
\r
1183 const char *received;
\r
1185 SalTransport transport;
\r
1186 if (extract_received_rport(response,&received,&rport,&transport)==0){
\r
1187 const char *contact=sal_op_get_contact(op);
\r
1189 /*no contact given yet, use from instead*/
\r
1190 contact=sal_op_get_from(op);
\r
1193 SalAddress *addr=sal_address_new(contact);
\r
1195 sal_address_set_domain(addr,received);
\r
1196 sal_address_set_port_int(addr,rport);
\r
1197 if (transport!=SalTransportUDP)
\r
1198 sal_address_set_transport(addr,transport);
\r
1199 tmp=sal_address_as_string(addr);
\r
1200 ms_message("Contact address updated to %s",tmp);
\r
1201 sal_op_set_contact(op,tmp);
\r
1202 sal_address_destroy(addr);
\r
1208 static int call_proceeding(Sal *sal, eXosip_event_t *ev){
\r
1209 SalOp *op=find_op(sal,ev);
\r
1211 if (op==NULL || op->terminated==TRUE) {
\r
1212 ms_warning("This call has been canceled.");
\r
1214 eXosip_call_terminate(ev->cid,ev->did);
\r
1222 /* update contact if received and rport are set by the server
\r
1223 note: will only be used by remote for next INVITE, if any...*/
\r
1224 update_contact_from_response(op,ev->response);
\r
1228 static void call_ringing(Sal *sal, eXosip_event_t *ev){
\r
1229 sdp_message_t *sdp;
\r
1230 SalOp *op=find_op(sal,ev);
\r
1231 if (call_proceeding(sal, ev)==-1) return;
\r
1233 set_remote_ua(op,ev->response);
\r
1234 sdp=eXosip_get_sdp_info(ev->response);
\r
1236 op->base.remote_media=sal_media_description_new();
\r
1237 sdp_to_media_description(sdp,op->base.remote_media);
\r
1238 sdp_message_free(sdp);
\r
1239 if (op->base.local_media) sdp_process(op);
\r
1241 sal->callbacks.call_ringing(op);
\r
1244 static void call_accepted(Sal *sal, eXosip_event_t *ev){
\r
1245 sdp_message_t *sdp;
\r
1246 osip_message_t *msg=NULL;
\r
1247 SalOp *op=find_op(sal,ev);
\r
1248 const char *contact;
\r
1250 if (op==NULL || op->terminated==TRUE) {
\r
1251 ms_warning("This call has been already terminated.");
\r
1253 eXosip_call_terminate(ev->cid,ev->did);
\r
1259 set_remote_ua(op,ev->response);
\r
1260 set_remote_contact(op,ev->response);
\r
1262 sdp=eXosip_get_sdp_info(ev->response);
\r
1264 op->base.remote_media=sal_media_description_new();
\r
1265 sdp_to_media_description(sdp,op->base.remote_media);
\r
1266 sdp_message_free(sdp);
\r
1267 if (op->base.local_media) sdp_process(op);
\r
1269 eXosip_call_build_ack(ev->did,&msg);
\r
1271 ms_warning("This call has been already terminated.");
\r
1273 eXosip_call_terminate(ev->cid,ev->did);
\r
1277 contact=sal_op_get_contact(op);
\r
1279 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
\r
1280 osip_message_set_contact(msg,contact);
\r
1282 if (op->sdp_answer){
\r
1283 set_sdp(msg,op->sdp_answer);
\r
1284 sdp_message_free(op->sdp_answer);
\r
1285 op->sdp_answer=NULL;
\r
1287 eXosip_call_send_ack(ev->did,msg);
\r
1288 sal->callbacks.call_accepted(op);
\r
1291 static void call_terminated(Sal *sal, eXosip_event_t *ev){
\r
1293 SalOp *op=find_op(sal,ev);
\r
1295 ms_warning("Call terminated for already closed call ?");
\r
1299 osip_from_to_str(ev->request->from,&from);
\r
1301 sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));
\r
1302 if (from) osip_free(from);
\r
1303 op->terminated=TRUE;
\r
1306 static void call_released(Sal *sal, eXosip_event_t *ev){
\r
1307 SalOp *op=find_op(sal,ev);
\r
1309 ms_warning("No op associated to this call_released()");
\r
1312 if (!op->terminated){
\r
1313 /* no response received so far */
\r
1314 call_failure(sal,ev);
\r
1316 sal->callbacks.call_released(op);
\r
1319 static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){
\r
1320 const char *prx_realm=NULL,*www_realm=NULL;
\r
1321 osip_proxy_authenticate_t *prx_auth;
\r
1322 osip_www_authenticate_t *www_auth;
\r
1324 *username=osip_uri_get_username(resp->from->url);
\r
1325 prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0);
\r
1326 www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0);
\r
1327 if (prx_auth!=NULL)
\r
1328 prx_realm=osip_proxy_authenticate_get_realm(prx_auth);
\r
1329 if (www_auth!=NULL)
\r
1330 www_realm=osip_www_authenticate_get_realm(www_auth);
\r
1334 }else if (www_realm){
\r
1342 static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){
\r
1343 osip_authorization_t *auth=NULL;
\r
1344 osip_proxy_authorization_t *prx_auth=NULL;
\r
1346 *username=osip_uri_get_username(msg->from->url);
\r
1347 osip_message_get_authorization(msg, 0, &auth);
\r
1349 *realm=osip_authorization_get_realm(auth);
\r
1352 osip_message_get_proxy_authorization(msg,0,&prx_auth);
\r
1354 *realm=osip_proxy_authorization_get_realm(prx_auth);
\r
1360 static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){
\r
1361 if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0;
\r
1362 if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0;
\r
1366 int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){
\r
1367 if (op->pending_auth){
\r
1368 return get_auth_data(op->pending_auth,realm,username);
\r
1373 static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){
\r
1375 const char *username,*realm;
\r
1376 op=find_op(sal,ev);
\r
1378 ms_warning("No operation associated with this authentication !");
\r
1381 if (get_auth_data(ev,&realm,&username)==0){
\r
1382 if (op->pending_auth!=NULL){
\r
1383 eXosip_event_free(op->pending_auth);
\r
1384 op->pending_auth=ev;
\r
1386 op->pending_auth=ev;
\r
1387 sal_add_pending_auth(sal,op);
\r
1390 sal->callbacks.auth_requested(op,realm,username);
\r
1396 static void authentication_ok(Sal *sal, eXosip_event_t *ev){
\r
1398 const char *username,*realm;
\r
1399 op=find_op(sal,ev);
\r
1401 ms_warning("No operation associated with this authentication_ok!");
\r
1404 if (op->pending_auth){
\r
1405 eXosip_event_free(op->pending_auth);
\r
1406 sal_remove_pending_auth(sal,op);
\r
1407 op->pending_auth=NULL;
\r
1409 if (get_auth_data(ev,&realm,&username)==0){
\r
1410 sal->callbacks.auth_success(op,realm,username);
\r
1414 static bool_t call_failure(Sal *sal, eXosip_event_t *ev){
\r
1417 char* computedReason=NULL;
\r
1418 const char *reason=NULL;
\r
1419 SalError error=SalErrorUnknown;
\r
1420 SalReason sr=SalReasonUnknown;
\r
1423 op=(SalOp*)find_op(sal,ev);
\r
1426 ms_warning("Call failure reported for a closed call, ignored.");
\r
1430 if (ev->response){
\r
1431 code=osip_message_get_status_code(ev->response);
\r
1432 reason=osip_message_get_reason_phrase(ev->response);
\r
1433 osip_header_t *h=NULL;
\r
1434 if (!osip_message_header_get_byname( ev->response
\r
1438 computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h));
\r
1439 reason = computedReason;
\r
1447 return process_authentication(sal,ev);
\r
1450 error=SalErrorUnknown;
\r
1453 error=SalErrorFailure;
\r
1454 sr=SalReasonNotFound;
\r
1457 error=SalErrorFailure;
\r
1458 sr=SalReasonMedia;
\r
1461 eXosip_default_action(ev);
\r
1465 error=SalErrorFailure;
\r
1466 sr=SalReasonTemporarilyUnavailable;
\r
1469 error=SalErrorFailure;
\r
1475 error=SalErrorFailure;
\r
1476 sr=SalReasonDoNotDisturb;
\r
1479 error=SalErrorFailure;
\r
1480 sr=SalReasonDeclined;
\r
1484 error=SalErrorFailure;
\r
1485 sr=SalReasonUnknown;
\r
1486 }else error=SalErrorNoResponse;
\r
1488 op->terminated=TRUE;
\r
1489 sal->callbacks.call_failure(op,error,sr,reason,code);
\r
1490 if (computedReason != NULL){
\r
1491 ms_free(computedReason);
\r
1496 /* Request remote side to send us VFU */
\r
1497 void sal_call_send_vfu_request(SalOp *h){
\r
1498 osip_message_t *msg=NULL;
\r
1499 char info_body[] =
\r
1500 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
\r
1504 " <picture_fast_update></picture_fast_update>"
\r
1506 " </vc_primitive>"
\r
1507 "</media_control>";
\r
1512 eXosip_call_build_info(h->did,&msg);
\r
1514 osip_message_set_body(msg,info_body,strlen(info_body));
\r
1515 osip_message_set_content_type(msg,"application/media_control+xml");
\r
1516 snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body));
\r
1517 osip_message_set_content_length(msg,clen);
\r
1518 eXosip_call_send_request(h->did,msg);
\r
1519 ms_message("Sending VFU request !");
\r
1524 static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){
\r
1525 SalOp *op=find_op(sal,ev);
\r
1526 osip_body_t *body=NULL;
\r
1529 ms_warning("media control xml received without operation context!");
\r
1533 osip_message_get_body(ev->request,0,&body);
\r
1534 if (body && body->body!=NULL &&
\r
1535 strstr(body->body,"picture_fast_update")){
\r
1536 osip_message_t *ans=NULL;
\r
1537 ms_message("Receiving VFU request !");
\r
1538 if (sal->callbacks.vfu_request){
\r
1539 sal->callbacks.vfu_request(op);
\r
1540 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1542 eXosip_call_send_answer(ev->tid,200,ans);
\r
1546 /*in all other cases we must say it is not implemented.*/
\r
1548 osip_message_t *ans=NULL;
\r
1550 eXosip_call_build_answer(ev->tid,501,&ans);
\r
1552 eXosip_call_send_answer(ev->tid,501,ans);
\r
1557 static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
\r
1558 SalOp *op=find_op(sal,ev);
\r
1559 osip_body_t *body=NULL;
\r
1562 ms_warning("media dtmf relay received without operation context!");
\r
1566 osip_message_get_body(ev->request,0,&body);
\r
1567 if (body && body->body!=NULL){
\r
1568 osip_message_t *ans=NULL;
\r
1569 const char *name=strstr(body->body,"Signal");
\r
1570 if (name==NULL) name=strstr(body->body,"signal");
\r
1572 ms_warning("Could not extract the dtmf name from the SIP INFO.");
\r
1575 name+=strlen("signal");
\r
1576 if (sscanf(name," = %1s",tmp)==1){
\r
1577 ms_message("Receiving dtmf %s via SIP INFO.",tmp);
\r
1578 if (sal->callbacks.dtmf_received != NULL)
\r
1579 sal->callbacks.dtmf_received(op, tmp[0]);
\r
1583 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1585 eXosip_call_send_answer(ev->tid,200,ans);
\r
1590 static void fill_options_answer(osip_message_t *options){
\r
1591 osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
\r
1592 osip_message_set_accept(options,"application/sdp");
\r
1595 static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
\r
1596 osip_header_t *h=NULL;
\r
1597 osip_message_t *ans=NULL;
\r
1598 ms_message("Receiving REFER request !");
\r
1599 osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
\r
1602 osip_from_t *from=NULL;
\r
1604 osip_from_init(&from);
\r
1606 if (osip_from_parse(from,h->hvalue)==0){
\r
1608 osip_uri_header_t *uh=NULL;
\r
1609 osip_header_t *referred_by=NULL;
\r
1610 osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);
\r
1611 if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){
\r
1612 ms_message("Found replaces in Refer-To");
\r
1613 if (op->replaces){
\r
1614 ms_free(op->replaces);
\r
1616 op->replaces=ms_strdup(uh->gvalue);
\r
1618 osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);
\r
1619 if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){
\r
1620 if (op->referred_by)
\r
1621 ms_free(op->referred_by);
\r
1622 op->referred_by=ms_strdup(referred_by->hvalue);
\r
1625 osip_uri_header_freelist(&from->url->url_headers);
\r
1626 osip_from_to_str(from,&tmp);
\r
1627 sal->callbacks.refer_received(sal,op,tmp);
\r
1629 osip_from_free(from);
\r
1632 eXosip_call_build_answer(ev->tid,202,&ans);
\r
1634 eXosip_call_send_answer(ev->tid,202,ans);
\r
1639 ms_warning("cannot do anything with the refer without destination\n");
\r
1643 static void process_notify(Sal *sal, eXosip_event_t *ev){
\r
1644 osip_header_t *h=NULL;
\r
1646 SalOp *op=find_op(sal,ev);
\r
1647 osip_message_t *ans=NULL;
\r
1649 ms_message("Receiving NOTIFY request !");
\r
1650 osip_from_to_str(ev->request->from,&from);
\r
1651 osip_message_header_get_byname(ev->request,"Event",0,&h);
\r
1653 osip_body_t *body=NULL;
\r
1654 //osip_content_type_t *ct=NULL;
\r
1655 osip_message_get_body(ev->request,0,&body);
\r
1656 //ct=osip_message_get_content_type(ev->request);
\r
1657 if (h->hvalue && strncasecmp(h->hvalue,"refer",strlen("refer"))==0){
\r
1658 /*special handling of refer events*/
\r
1659 if (body && body->body){
\r
1660 osip_message_t *msg;
\r
1661 osip_message_init(&msg);
\r
1662 if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){
\r
1663 int code=osip_message_get_status_code(msg);
\r
1665 sal->callbacks.notify_refer(op,SalReferTrying);
\r
1666 }else if (code==200){
\r
1667 sal->callbacks.notify_refer(op,SalReferSuccess);
\r
1668 }else if (code>=400){
\r
1669 sal->callbacks.notify_refer(op,SalReferFailed);
\r
1672 osip_message_free(msg);
\r
1675 /*generic handling*/
\r
1676 sal->callbacks.notify(op,from,h->hvalue);
\r
1679 /*answer that we received the notify*/
\r
1681 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1683 eXosip_call_send_answer(ev->tid,200,ans);
\r
1688 static void call_message_new(Sal *sal, eXosip_event_t *ev){
\r
1689 osip_message_t *ans=NULL;
\r
1691 if (MSG_IS_INFO(ev->request)){
\r
1692 osip_content_type_t *ct;
\r
1693 ct=osip_message_get_content_type(ev->request);
\r
1694 if (ct && ct->subtype){
\r
1695 if (strcmp(ct->subtype,"media_control+xml")==0)
\r
1696 process_media_control_xml(sal,ev);
\r
1697 else if (strcmp(ct->subtype,"dtmf-relay")==0)
\r
1698 process_dtmf_relay(sal,ev);
\r
1700 ms_message("Unhandled SIP INFO.");
\r
1701 /*send an "Not implemented" answer*/
\r
1703 eXosip_call_build_answer(ev->tid,501,&ans);
\r
1705 eXosip_call_send_answer(ev->tid,501,ans);
\r
1709 /*empty SIP INFO, probably to test we are alive. Send an empty answer*/
\r
1711 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1713 eXosip_call_send_answer(ev->tid,200,ans);
\r
1716 }else if(MSG_IS_MESSAGE(ev->request)){
\r
1717 /* SIP messages could be received into call */
\r
1718 text_received(sal, ev);
\r
1720 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1722 eXosip_call_send_answer(ev->tid,200,ans);
\r
1724 }else if(MSG_IS_REFER(ev->request)){
\r
1725 SalOp *op=find_op(sal,ev);
\r
1727 ms_message("Receiving REFER request !");
\r
1728 process_refer(sal,op,ev);
\r
1729 }else if(MSG_IS_NOTIFY(ev->request)){
\r
1730 process_notify(sal,ev);
\r
1731 }else if (MSG_IS_OPTIONS(ev->request)){
\r
1733 eXosip_call_build_answer(ev->tid,200,&ans);
\r
1735 fill_options_answer(ans);
\r
1736 eXosip_call_send_answer(ev->tid,200,ans);
\r
1740 }else ms_warning("call_message_new: No request ?");
\r
1743 static void inc_update(Sal *sal, eXosip_event_t *ev){
\r
1744 osip_message_t *msg=NULL;
\r
1745 ms_message("Processing incoming UPDATE");
\r
1747 eXosip_message_build_answer(ev->tid,200,&msg);
\r
1749 eXosip_message_send_answer(ev->tid,200,msg);
\r
1753 static bool_t comes_from_local_if(osip_message_t *msg){
\r
1754 osip_via_t *via=NULL;
\r
1755 osip_message_get_via(msg,0,&via);
\r
1758 host=osip_via_get_host(via);
\r
1759 if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){
\r
1760 osip_generic_param_t *param=NULL;
\r
1761 osip_via_param_get_byname(via,"received",¶m);
\r
1762 if (param==NULL) return TRUE;
\r
1763 if (param->gvalue &&
\r
1764 (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){
\r
1772 static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
\r
1773 static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
\r
1775 static int utc_offset() {
\r
1776 time_t ref = 24 * 60 * 60L;
\r
1777 struct tm * timeptr;
\r
1780 /* get the local reference time for Jan 2, 1900 00:00 UTC */
\r
1781 timeptr = localtime(&ref);
\r
1782 gmtime_hours = timeptr->tm_hour;
\r
1784 /* if the local time is the "day before" the UTC, subtract 24 hours
\r
1785 from the hours to get the UTC offset */
\r
1786 if (timeptr->tm_mday < 2) gmtime_hours -= 24;
\r
1788 return gmtime_hours;
\r
1791 time_t mktime_utc(struct tm *timeptr) {
\r
1792 return mktime(timeptr) + utc_offset() * 3600;
\r
1795 static void text_received(Sal *sal, eXosip_event_t *ev){
\r
1796 osip_body_t *body=NULL;
\r
1797 char *from=NULL,*msg=NULL;
\r
1798 osip_content_type_t* content_type;
\r
1799 osip_uri_param_t* external_body_url;
\r
1800 char unquoted_external_body_url [256];
\r
1801 int external_body_size=0;
\r
1802 SalMessage salmsg;
\r
1803 char message_id[256]={0};
\r
1804 osip_header_t *date=NULL;
\r
1805 struct tm ret={0};
\r
1806 char tmp1[80]={0};
\r
1807 char tmp2[80]={0};
\r
1808 SalOp *op=sal_op_new(sal);
\r
1810 osip_message_get_date(ev->request,0,&date);
\r
1813 sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2,
\r
1814 &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec);
\r
1815 ret.tm_year-=1900;
\r
1816 for(i=0;i<7;i++) {
\r
1817 if(strcmp(tmp1,days[i])==0) ret.tm_wday=i;
\r
1819 for(j=0;j<12;j++) {
\r
1820 if(strcmp(tmp2,months[j])==0) ret.tm_mon=j;
\r
1823 }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent.");
\r
1825 content_type= osip_message_get_content_type(ev->request);
\r
1826 if (!content_type) {
\r
1827 ms_error("Could not get message because no content type");
\r
1830 osip_from_to_str(ev->request->from,&from);
\r
1831 if (content_type->type
\r
1832 && strcmp(content_type->type, "text")==0
\r
1833 && content_type->subtype
\r
1834 && strcmp(content_type->subtype, "plain")==0 ) {
\r
1835 osip_message_get_body(ev->request,0,&body);
\r
1837 ms_error("Could not get text message from SIP body");
\r
1842 }else if (content_type->type
\r
1843 && strcmp(content_type->type, "message")==0
\r
1844 && content_type->subtype
\r
1845 && strcmp(content_type->subtype, "external-body")==0 ) {
\r
1847 osip_content_type_param_get_byname(content_type, "URL", &external_body_url);
\r
1848 /*remove both first and last character*/
\r
1849 strncpy(unquoted_external_body_url
\r
1850 ,&external_body_url->gvalue[1]
\r
1851 ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));
\r
1852 unquoted_external_body_url[external_body_size-1]='\0';
\r
1854 ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);
\r
1858 sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));
\r
1860 snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);
\r
1864 salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;
\r
1865 salmsg.message_id=message_id;
\r
1866 salmsg.time=date!=NULL ? mktime_utc(&ret) : time(NULL);
\r
1867 sal->callbacks.text_received(op,&salmsg);
\r
1868 sal_op_release(op);
\r
1872 static void other_request(Sal *sal, eXosip_event_t *ev){
\r
1873 ms_message("in other_request");
\r
1874 if (ev->request==NULL) return;
\r
1875 if (strcmp(ev->request->sip_method,"MESSAGE")==0){
\r
1876 text_received(sal,ev);
\r
1877 eXosip_message_send_answer(ev->tid,200,NULL);
\r
1878 }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){
\r
1879 osip_message_t *options=NULL;
\r
1880 eXosip_options_build_answer(ev->tid,200,&options);
\r
1881 fill_options_answer(options);
\r
1882 eXosip_options_send_answer(ev->tid,200,options);
\r
1883 }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){
\r
1884 ms_message("Receiving REFER request !");
\r
1885 if (comes_from_local_if(ev->request)) {
\r
1886 process_refer(sal,NULL,ev);
\r
1887 }else ms_warning("Ignored REFER not coming from this local loopback interface.");
\r
1888 }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){
\r
1889 inc_update(sal,ev);
\r
1893 osip_message_to_str(ev->request,&tmp,&msglen);
\r
1895 ms_message("Unsupported request received:\n%s",tmp);
\r
1898 /*answer with a 501 Not implemented*/
\r
1899 eXosip_message_send_answer(ev->tid,501,NULL);
\r
1903 static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){
\r
1904 osip_via_t *via=NULL;
\r
1905 osip_message_get_via(msg,0,&via);
\r
1907 osip_free(via->port);
\r
1908 via->port=osip_strdup(port);
\r
1909 osip_free(via->host);
\r
1910 via->host=osip_strdup(ip);
\r
1915 static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {
\r
1916 osip_contact_t *ctt=NULL;
\r
1917 const char *received;
\r
1919 SalTransport transport;
\r
1922 if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;
\r
1923 osip_message_get_contact(request,0,&ctt);
\r
1924 if (ctt == NULL) {
\r
1925 ms_warning("fix_message_contact(): no contact to update");
\r
1928 if (expire_last_contact){
\r
1929 osip_contact_t *oldct=NULL,*prevct;
\r
1930 osip_generic_param_t *param=NULL;
\r
1931 osip_contact_clone(ctt,&oldct);
\r
1932 while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){
\r
1933 osip_contact_free(prevct);
\r
1934 osip_list_remove(&request->contacts,1);
\r
1936 osip_list_add(&request->contacts,oldct,1);
\r
1937 osip_contact_param_get_byname(oldct,"expires",¶m);
\r
1939 if (param->gvalue) osip_free(param->gvalue);
\r
1940 param->gvalue=osip_strdup("0");
\r
1942 osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));
\r
1945 if (ctt->url->host!=NULL){
\r
1946 osip_free(ctt->url->host);
\r
1948 ctt->url->host=osip_strdup(received);
\r
1949 if (ctt->url->port!=NULL){
\r
1950 osip_free(ctt->url->port);
\r
1952 snprintf(port,sizeof(port),"%i",rport);
\r
1953 ctt->url->port=osip_strdup(port);
\r
1954 if (op->masquerade_via) masquerade_via(request,received,port);
\r
1956 if (transport != SalTransportUDP) {
\r
1957 sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport));
\r
1962 static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){
\r
1963 osip_contact_t *ctt=NULL;
\r
1964 SalAddress* ori_contact_address=NULL;
\r
1965 const char *received;
\r
1967 SalTransport transport;
\r
1969 osip_message_t *msg=NULL;
\r
1970 Sal* sal=op->base.root;
\r
1972 bool_t found_valid_contact=FALSE;
\r
1973 bool_t from_request=FALSE;
\r
1975 if (sal->double_reg==FALSE ) return FALSE;
\r
1977 if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;
\r
1980 osip_message_get_contact(last_answer,i,&ctt);
\r
1981 if (!from_request && ctt==NULL) {
\r
1982 osip_message_get_contact(orig_request,0,&ctt);
\r
1983 from_request=TRUE;
\r
1986 osip_contact_to_str(ctt,&tmp);
\r
1987 ori_contact_address = sal_address_new(tmp);
\r
1989 /*check if contact is up to date*/
\r
1990 if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0
\r
1991 && sal_address_get_port_int(ori_contact_address) == rport
\r
1992 && sal_address_get_transport(ori_contact_address) == transport) {
\r
1993 if (!from_request){
\r
1994 ms_message("Register response has up to date contact, doing nothing.");
\r
1996 ms_warning("Register response does not have up to date contact, but last request had."
\r
1997 "Stupid registrar detected, giving up.");
\r
1999 found_valid_contact=TRUE;
\r
2002 sal_address_destroy(ori_contact_address);
\r
2005 }while(!found_valid_contact);
\r
2006 if (!found_valid_contact)
\r
2007 ms_message("Contact do not match, resending register.");
\r
2008 else return FALSE;
\r
2011 eXosip_register_build_register(op->rid,op->expires,&msg);
\r
2014 ms_warning("Fail to create a contact updated register.");
\r
2017 if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {
\r
2018 eXosip_register_send_register(op->rid,msg);
\r
2020 ms_message("Resending new register with updated contact");
\r
2021 update_contact_from_response(op,last_answer);
\r
2024 ms_warning("Fail to send updated register.");
\r
2032 static void registration_success(Sal *sal, eXosip_event_t *ev){
\r
2033 SalOp *op=sal_find_register(sal,ev->rid);
\r
2034 osip_header_t *h=NULL;
\r
2035 bool_t registered;
\r
2037 ms_error("Receiving register response for unknown operation");
\r
2040 osip_message_get_expires(ev->request,0,&h);
\r
2041 if (h!=NULL && atoi(h->hvalue)!=0){
\r
2043 if (!register_again_with_updated_contact(op,ev->request,ev->response)){
\r
2044 sal->callbacks.register_success(op,registered);
\r
2047 sal->callbacks.register_success(op,FALSE);
\r
2051 static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
\r
2052 int status_code=0;
\r
2053 const char *reason=NULL;
\r
2054 SalOp *op=sal_find_register(sal,ev->rid);
\r
2055 SalReason sr=SalReasonUnknown;
\r
2056 SalError se=SalErrorUnknown;
\r
2059 ms_error("Receiving register failure for unknown operation");
\r
2062 if (ev->response){
\r
2063 status_code=osip_message_get_status_code(ev->response);
\r
2064 reason=osip_message_get_reason_phrase(ev->response);
\r
2066 switch(status_code){
\r
2069 return process_authentication(sal,ev);
\r
2071 case 423: /*interval too brief*/
\r
2072 {/*retry with greater interval */
\r
2073 osip_header_t *h=NULL;
\r
2074 osip_message_t *msg=NULL;
\r
2075 osip_message_header_get_byname(ev->response,"min-expires",0,&h);
\r
2076 if (h && h->hvalue && h->hvalue[0]!='\0'){
\r
2077 int val=atoi(h->hvalue);
\r
2078 if (val>op->expires)
\r
2080 }else op->expires*=2;
\r
2082 eXosip_register_build_register(op->rid,op->expires,&msg);
\r
2083 eXosip_register_send_register(op->rid,msg);
\r
2087 case 606: /*Not acceptable, workaround for proxies that don't like private addresses
\r
2088 in vias, such as ekiga.net
\r
2089 On the opposite, freephonie.net bugs when via are masqueraded.
\r
2091 op->masquerade_via=TRUE;
\r
2093 /* if contact is up to date, process the failure, otherwise resend a new register with
\r
2094 updated contact first, just in case the faillure is due to incorrect contact */
\r
2095 if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response))
\r
2096 return TRUE; /*we are retrying with an updated contact*/
\r
2097 if (status_code==403){
\r
2098 se=SalErrorFailure;
\r
2099 sr=SalReasonForbidden;
\r
2100 }else if (status_code==0){
\r
2101 se=SalErrorNoResponse;
\r
2103 sal->callbacks.register_failure(op,se,sr,reason);
\r
2108 static void other_request_reply(Sal *sal,eXosip_event_t *ev){
\r
2109 SalOp *op=find_op(sal,ev);
\r
2111 ms_warning("other_request_reply(): Receiving response to unknown request.");
\r
2114 if (ev->response){
\r
2115 ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));
\r
2116 update_contact_from_response(op,ev->response);
\r
2117 if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)
\r
2118 sal->callbacks.ping_reply(op);
\r
2120 if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {
\r
2121 /*out of call message acknolegment*/
\r
2122 SalTextDeliveryStatus status=SalTextDeliveryFailed;
\r
2123 if (ev->response){
\r
2124 if (ev->response->status_code<200){
\r
2125 status=SalTextDeliveryInProgress;
\r
2126 }else if (ev->response->status_code<300 && ev->response->status_code>=200){
\r
2127 status=SalTextDeliveryDone;
\r
2130 sal->callbacks.text_delivery_update(op,status);
\r
2134 static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){
\r
2135 SalOp *op=find_op(sal,ev);
\r
2136 if (ev->response){
\r
2137 if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){
\r
2138 if (op->sipfrag_pending){
\r
2139 send_notify_for_refer(op->did,op->sipfrag_pending);
\r
2140 op->sipfrag_pending=NULL;
\r
2146 static bool_t process_event(Sal *sal, eXosip_event_t *ev){
\r
2147 ms_message("linphone process event get a message %d\n",ev->type);
\r
2149 case EXOSIP_CALL_ANSWERED:
\r
2150 ms_message("CALL_ANSWERED\n");
\r
2151 call_accepted(sal,ev);
\r
2152 authentication_ok(sal,ev);
\r
2154 case EXOSIP_CALL_CLOSED:
\r
2155 case EXOSIP_CALL_CANCELLED:
\r
2156 ms_message("CALL_CLOSED or CANCELLED\n");
\r
2157 call_terminated(sal,ev);
\r
2159 case EXOSIP_CALL_TIMEOUT:
\r
2160 case EXOSIP_CALL_NOANSWER:
\r
2161 ms_message("CALL_TIMEOUT or NOANSWER\n");
\r
2162 return call_failure(sal,ev);
\r
2164 case EXOSIP_CALL_REQUESTFAILURE:
\r
2165 case EXOSIP_CALL_GLOBALFAILURE:
\r
2166 case EXOSIP_CALL_SERVERFAILURE:
\r
2167 ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n");
\r
2168 return call_failure(sal,ev);
\r
2170 case EXOSIP_CALL_RELEASED:
\r
2171 ms_message("CALL_RELEASED\n");
\r
2172 call_released(sal, ev);
\r
2174 case EXOSIP_CALL_INVITE:
\r
2175 ms_message("CALL_NEW\n");
\r
2176 inc_new_call(sal,ev);
\r
2178 case EXOSIP_CALL_REINVITE:
\r
2179 handle_reinvite(sal,ev);
\r
2181 case EXOSIP_CALL_ACK:
\r
2182 ms_message("CALL_ACK");
\r
2183 handle_ack(sal,ev);
\r
2185 case EXOSIP_CALL_REDIRECTED:
\r
2186 ms_message("CALL_REDIRECTED");
\r
2187 eXosip_default_action(ev);
\r
2189 case EXOSIP_CALL_PROCEEDING:
\r
2190 ms_message("CALL_PROCEEDING");
\r
2191 call_proceeding(sal,ev);
\r
2193 case EXOSIP_CALL_RINGING:
\r
2194 ms_message("CALL_RINGING");
\r
2195 call_ringing(sal,ev);
\r
2196 authentication_ok(sal,ev);
\r
2198 case EXOSIP_CALL_MESSAGE_NEW:
\r
2199 ms_message("EXOSIP_CALL_MESSAGE_NEW");
\r
2200 call_message_new(sal,ev);
\r
2202 case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:
\r
2203 if (ev->response &&
\r
2204 (ev->response->status_code==407 || ev->response->status_code==401)){
\r
2205 return process_authentication(sal,ev);
\r
2208 case EXOSIP_CALL_MESSAGE_ANSWERED:
\r
2209 ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");
\r
2210 process_in_call_reply(sal,ev);
\r
2212 case EXOSIP_IN_SUBSCRIPTION_NEW:
\r
2213 ms_message("CALL_IN_SUBSCRIPTION_NEW ");
\r
2214 sal_exosip_subscription_recv(sal,ev);
\r
2216 case EXOSIP_IN_SUBSCRIPTION_RELEASED:
\r
2217 ms_message("CALL_SUBSCRIPTION_NEW ");
\r
2218 sal_exosip_in_subscription_closed(sal,ev);
\r
2220 case EXOSIP_SUBSCRIPTION_UPDATE:
\r
2221 ms_message("CALL_SUBSCRIPTION_UPDATE");
\r
2223 case EXOSIP_SUBSCRIPTION_NOTIFY:
\r
2224 ms_message("CALL_SUBSCRIPTION_NOTIFY");
\r
2225 sal_exosip_notify_recv(sal,ev);
\r
2227 case EXOSIP_SUBSCRIPTION_ANSWERED:
\r
2228 ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);
\r
2229 sal_exosip_subscription_answered(sal,ev);
\r
2231 case EXOSIP_SUBSCRIPTION_CLOSED:
\r
2232 ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");
\r
2233 sal_exosip_subscription_closed(sal,ev);
\r
2235 case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /**< announce a request failure */
\r
2236 if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
\r
2237 return process_authentication(sal,ev);
\r
2239 case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
\r
2240 case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
\r
2241 sal_exosip_subscription_closed(sal,ev);
\r
2243 case EXOSIP_REGISTRATION_FAILURE:
\r
2244 ms_message("REGISTRATION_FAILURE\n");
\r
2245 return registration_failure(sal,ev);
\r
2247 case EXOSIP_REGISTRATION_SUCCESS:
\r
2248 authentication_ok(sal,ev);
\r
2249 registration_success(sal,ev);
\r
2251 case EXOSIP_MESSAGE_NEW:
\r
2252 other_request(sal,ev);
\r
2254 case EXOSIP_MESSAGE_PROCEEDING:
\r
2255 case EXOSIP_MESSAGE_ANSWERED:
\r
2256 case EXOSIP_MESSAGE_REDIRECTED:
\r
2257 case EXOSIP_MESSAGE_SERVERFAILURE:
\r
2258 case EXOSIP_MESSAGE_GLOBALFAILURE:
\r
2259 other_request_reply(sal,ev);
\r
2261 case EXOSIP_MESSAGE_REQUESTFAILURE:
\r
2262 case EXOSIP_NOTIFICATION_REQUESTFAILURE:
\r
2263 if (ev->response) {
\r
2264 switch (ev->response->status_code) {
\r
2267 return process_authentication(sal,ev);
\r
2269 eXosip_automatic_action ();
\r
2274 other_request_reply(sal,ev);
\r
2277 ms_message("Unhandled exosip event ! %i",ev->type);
\r
2283 int sal_iterate(Sal *sal){
\r
2284 eXosip_event_t *ev;
\r
2285 while((ev=eXosip_event_wait(0,0))!=NULL){
\r
2286 if (process_event(sal,ev))
\r
2287 eXosip_event_free(ev);
\r
2289 #ifdef HAVE_EXOSIP_TRYLOCK
\r
2290 if (eXosip_trylock()==0){
\r
2291 eXosip_automatic_refresh();
\r
2294 ms_warning("eXosip_trylock busy.");
\r
2298 eXosip_automatic_refresh();
\r
2304 static void register_set_contact(osip_message_t *msg, const char *contact){
\r
2305 osip_uri_param_t *param = NULL;
\r
2306 osip_contact_t *ct=NULL;
\r
2308 /*we get the line parameter choosed by exosip, and add it to our own contact*/
\r
2309 osip_message_get_contact(msg,0,&ct);
\r
2311 osip_uri_uparam_get_byname(ct->url, "line", ¶m);
\r
2312 if (param && param->gvalue)
\r
2313 line=osip_strdup(param->gvalue);
\r
2315 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
\r
2316 osip_message_set_contact(msg,contact);
\r
2317 osip_message_get_contact(msg,0,&ct);
\r
2318 osip_uri_uparam_add(ct->url,osip_strdup("line"),line);
\r
2321 void sal_message_add_route(osip_message_t *msg, const char *proxy){
\r
2322 osip_route_t *route;
\r
2324 osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);
\r
2326 osip_route_init(&route);
\r
2327 if (osip_route_parse(route,proxy)==0){
\r
2328 osip_uri_param_t *lr_param = NULL;
\r
2329 osip_uri_uparam_get_byname(route->url, "lr", &lr_param);
\r
2330 if (lr_param == NULL){
\r
2331 osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);
\r
2333 osip_list_add(&msg->routes,route,0);
\r
2336 osip_route_free(route);
\r
2340 int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
\r
2341 osip_message_t *msg;
\r
2342 const char *contact=sal_op_get_contact(h);
\r
2344 sal_op_set_route(h,proxy);
\r
2346 SalAddress *from_parsed=sal_address_new(from);
\r
2348 char *uri, *domain_ptr = NULL;
\r
2349 if (from_parsed==NULL) {
\r
2350 ms_warning("sal_register() bad from %s",from);
\r
2353 /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of
\r
2354 using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */
\r
2355 uri = sal_address_as_string_uri_only(from_parsed);
\r
2356 if (uri) domain_ptr = strchr(uri, '@');
\r
2358 snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);
\r
2360 snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));
\r
2362 if (uri) ms_free(uri);
\r
2363 sal_address_destroy(from_parsed);
\r
2365 h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);
\r
2367 if (contact) register_set_contact(msg,contact);
\r
2368 sal_message_add_route(msg,proxy);
\r
2369 sal_add_register(h->base.root,h);
\r
2371 ms_error("Could not build initial register.");
\r
2377 eXosip_register_build_register(h->rid,expires,&msg);
\r
2378 sal_message_add_route(msg,proxy);
\r
2381 eXosip_register_send_register(h->rid,msg);
\r
2384 h->expires=expires;
\r
2385 return (msg != NULL) ? 0 : -1;
\r
2388 int sal_register_refresh(SalOp *op, int expires){
\r
2389 osip_message_t *msg=NULL;
\r
2390 const char *contact=sal_op_get_contact(op);
\r
2393 ms_error("Unexistant registration context, not possible to refresh.");
\r
2396 #ifdef HAVE_EXOSIP_TRYLOCK
\r
2399 /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.
\r
2400 * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take
\r
2401 * the exosip lock in a non blocking way, and give up if it takes too long*/
\r
2402 while (eXosip_trylock()!=0){
\r
2403 ms_usleep(100000);
\r
2405 if (tries>30) {/*after 3 seconds, give up*/
\r
2406 ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");
\r
2414 eXosip_register_build_register(op->rid,expires,&msg);
\r
2416 if (contact) register_set_contact(msg,contact);
\r
2417 sal_message_add_route(msg,sal_op_get_route(op));
\r
2418 eXosip_register_send_register(op->rid,msg);
\r
2419 }else ms_error("Could not build REGISTER refresh message.");
\r
2421 return (msg != NULL) ? 0 : -1;
\r
2425 int sal_unregister(SalOp *h){
\r
2426 osip_message_t *msg=NULL;
\r
2428 eXosip_register_build_register(h->rid,0,&msg);
\r
2429 if (msg) eXosip_register_send_register(h->rid,msg);
\r
2430 else ms_warning("Could not build unREGISTER !");
\r
2435 SalAddress * sal_address_new(const char *uri){
\r
2436 osip_from_t *from;
\r
2437 osip_from_init(&from);
\r
2439 // Remove front spaces
\r
2440 while (uri[0]==' ') {
\r
2444 if (osip_from_parse(from,uri)!=0){
\r
2445 osip_from_free(from);
\r
2448 if (from->displayname!=NULL && from->displayname[0]=='"'){
\r
2449 char *unquoted=osip_strdup_without_quote(from->displayname);
\r
2450 osip_free(from->displayname);
\r
2451 from->displayname=unquoted;
\r
2453 return (SalAddress*)from;
\r
2456 SalAddress * sal_address_clone(const SalAddress *addr){
\r
2457 osip_from_t *ret=NULL;
\r
2458 osip_from_clone((osip_from_t*)addr,&ret);
\r
2459 return (SalAddress*)ret;
\r
2462 #define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )
\r
2464 const char *sal_address_get_scheme(const SalAddress *addr){
\r
2465 const osip_from_t *u=(const osip_from_t*)addr;
\r
2466 return null_if_empty(u->url->scheme);
\r
2469 const char *sal_address_get_display_name(const SalAddress* addr){
\r
2470 const osip_from_t *u=(const osip_from_t*)addr;
\r
2471 return null_if_empty(u->displayname);
\r
2474 const char *sal_address_get_username(const SalAddress *addr){
\r
2475 const osip_from_t *u=(const osip_from_t*)addr;
\r
2476 return null_if_empty(u->url->username);
\r
2479 const char *sal_address_get_domain(const SalAddress *addr){
\r
2480 const osip_from_t *u=(const osip_from_t*)addr;
\r
2481 return null_if_empty(u->url->host);
\r
2484 void sal_address_set_display_name(SalAddress *addr, const char *display_name){
\r
2485 osip_from_t *u=(osip_from_t*)addr;
\r
2486 if (u->displayname!=NULL){
\r
2487 osip_free(u->displayname);
\r
2488 u->displayname=NULL;
\r
2490 if (display_name!=NULL && display_name[0]!='\0'){
\r
2491 u->displayname=osip_strdup(display_name);
\r
2495 void sal_address_set_username(SalAddress *addr, const char *username){
\r
2496 osip_from_t *uri=(osip_from_t*)addr;
\r
2497 if (uri->url->username!=NULL){
\r
2498 osip_free(uri->url->username);
\r
2499 uri->url->username=NULL;
\r
2502 uri->url->username=osip_strdup(username);
\r
2505 void sal_address_set_domain(SalAddress *addr, const char *host){
\r
2506 osip_from_t *uri=(osip_from_t*)addr;
\r
2507 if (uri->url->host!=NULL){
\r
2508 osip_free(uri->url->host);
\r
2509 uri->url->host=NULL;
\r
2512 uri->url->host=osip_strdup(host);
\r
2515 void sal_address_set_port(SalAddress *addr, const char *port){
\r
2516 osip_from_t *uri=(osip_from_t*)addr;
\r
2517 if (uri->url->port!=NULL){
\r
2518 osip_free(uri->url->port);
\r
2519 uri->url->port=NULL;
\r
2522 uri->url->port=osip_strdup(port);
\r
2525 void sal_address_set_port_int(SalAddress *uri, int port){
\r
2528 /*this is the default, special case to leave the port field blank*/
\r
2529 sal_address_set_port(uri,NULL);
\r
2532 snprintf(tmp,sizeof(tmp),"%i",port);
\r
2533 sal_address_set_port(uri,tmp);
\r
2536 void sal_address_clean(SalAddress *addr){
\r
2537 osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params);
\r
2538 osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params);
\r
2541 char *sal_address_as_string(const SalAddress *u){
\r
2543 osip_from_t *from=(osip_from_t *)u;
\r
2544 char *old_displayname=NULL;
\r
2545 /* hack to force use of quotes around the displayname*/
\r
2546 if (from->displayname!=NULL
\r
2547 && from->displayname[0]!='"'){
\r
2548 old_displayname=from->displayname;
\r
2549 from->displayname=osip_enquote(from->displayname);
\r
2551 osip_from_to_str(from,&tmp);
\r
2552 if (old_displayname!=NULL){
\r
2553 ms_free(from->displayname);
\r
2554 from->displayname=old_displayname;
\r
2556 ret=ms_strdup(tmp);
\r
2561 char *sal_address_as_string_uri_only(const SalAddress *u){
\r
2562 char *tmp=NULL,*ret;
\r
2563 osip_uri_to_str(((osip_from_t*)u)->url,&tmp);
\r
2564 ret=ms_strdup(tmp);
\r
2568 void sal_address_set_param(SalAddress *u,const char* name,const char* value) {
\r
2569 osip_uri_param_t *param=NULL;
\r
2570 osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,¶m);
\r
2571 if (param == NULL){
\r
2572 osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL);
\r
2574 osip_free(param->gvalue);
\r
2575 param->gvalue=value ? osip_strdup(value) : NULL;
\r
2580 void sal_address_destroy(SalAddress *u){
\r
2581 osip_from_free((osip_from_t*)u);
\r
2584 void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {
\r
2585 ctx->tcp_tls_keepalive = enabled;
\r
2588 void sal_set_keepalive_period(Sal *ctx,unsigned int value) {
\r
2589 switch (ctx->transport) {
\r
2590 case SalTransportUDP:
\r
2591 ctx->keepalive_period = value;
\r
2593 case SalTransportTCP:
\r
2594 case SalTransportTLS:
\r
2595 if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value;
\r
2596 else ctx->keepalive_period = -1;
\r
2601 eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);
\r
2603 unsigned int sal_get_keepalive_period(Sal *ctx) {
\r
2604 return ctx->keepalive_period;
\r
2607 const char * sal_address_get_port(const SalAddress *addr) {
\r
2608 const osip_from_t *u=(const osip_from_t*)addr;
\r
2609 return null_if_empty(u->url->port);
\r
2612 int sal_address_get_port_int(const SalAddress *uri) {
\r
2613 const char* port = sal_address_get_port(uri);
\r
2614 if (port != NULL) {
\r
2615 return atoi(port);
\r
2620 SalTransport sal_address_get_transport(const SalAddress* addr) {
\r
2621 const osip_from_t *u=(const osip_from_t*)addr;
\r
2622 osip_uri_param_t *transport_param=NULL;
\r
2623 osip_uri_uparam_get_byname(u->url,"transport",&transport_param);
\r
2624 if (transport_param == NULL){
\r
2625 return SalTransportUDP;
\r
2627 return sal_transport_parse(transport_param->gvalue);
\r
2630 void sal_address_set_transport(SalAddress* addr,SalTransport transport) {
\r
2631 sal_address_set_param(addr, "transport", sal_transport_to_string(transport));
\r
2634 /* sends a reinvite. Local media description may have changed by application since call establishment*/
\r
2635 int sal_call_update(SalOp *h, const char *subject){
\r
2637 osip_message_t *reinvite=NULL;
\r
2640 if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){
\r
2645 osip_message_set_subject(reinvite,subject);
\r
2646 osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
\r
2647 if (h->base.contact){
\r
2648 _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);
\r
2649 osip_message_set_contact(reinvite,h->base.contact);
\r
2651 if (h->base.root->session_expires!=0){
\r
2652 osip_message_set_header(reinvite, "Session-expires", "200");
\r
2653 osip_message_set_supported(reinvite, "timer");
\r
2655 if (h->base.local_media){
\r
2656 h->sdp_offering=TRUE;
\r
2657 set_sdp_from_desc(reinvite,h->base.local_media);
\r
2658 }else h->sdp_offering=FALSE;
\r
2660 err = eXosip_call_send_request(h->did, reinvite);
\r
2665 void sal_reuse_authorization(Sal *ctx, bool_t value) {
\r
2666 ctx->reuse_authorization=value;
\r
2669 void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){
\r
2670 MSList *elem=(MSList*)ch;
\r
2671 for (;elem!=NULL;elem=elem->next){
\r
2672 SalCustomHeader *it=(SalCustomHeader*)elem;
\r
2673 osip_message_set_header(msg,it->header_name,it->header_value);
\r
2677 SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){
\r
2679 osip_header_t *header;
\r
2680 SalCustomHeader *ret=NULL;
\r
2682 while((header=osip_list_get(&msg->headers,i))!=NULL){
\r
2683 ret=sal_custom_header_append(ret,header->hname,header->hvalue);
\r