diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index edce2c4e3..4e8f75028 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -421,6 +421,16 @@ static void internal_message(Sal *sal, const char *msg){ lc->vtable.show(lc); } +static void ping_reply(SalOp *op){ + LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); + ms_message("ping reply !"); + if (call){ + if (call->state==LCStatePreEstablishing){ + linphone_core_start_invite(call->core,call,NULL); + } + } +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -440,7 +450,8 @@ SalCallbacks linphone_sal_callbacks={ notify, subscribe_received, subscribe_closed, - internal_message + internal_message, + ping_reply }; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2c163d490..e269f4611 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -63,20 +63,21 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ } -static MSList *make_codec_list(const MSList *codecs){ +static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){ MSList *l=NULL; const MSList *it; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; if (pt->flags & PAYLOAD_TYPE_ENABLED){ l=ms_list_append(l,payload_type_clone(pt)); + if (only_one_codec) break; } } return l; } static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - const char *localip, const char *username){ + const char *localip, const char *username, bool_t only_one_codec){ MSList *l; PayloadType *pt; SalMediaDescription *md=sal_media_description_new(); @@ -88,7 +89,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[0].port=linphone_core_get_audio_port(lc); md->streams[0].proto=SalProtoRtpAvp; md->streams[0].type=SalAudio; - l=make_codec_list(lc->codecs_conf.audio_codecs); + l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec); pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; @@ -101,7 +102,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[1].port=linphone_core_get_video_port(lc); md->streams[1].proto=SalProtoRtpAvp; md->streams[1].type=SalVideo; - l=make_codec_list(lc->codecs_conf.video_codecs); + l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec); md->streams[1].payloads=l; if (lc->dw_video_bw) md->streams[1].bandwidth=lc->dw_video_bw; @@ -141,7 +142,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(from)); + linphone_address_get_username(from),FALSE); linphone_call_init_common(call,from,to); discover_mtu(lc,linphone_address_get_domain (to)); return call; @@ -150,16 +151,30 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); + char *to_str; + char *from_str; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); call->op=op; call->core=lc; + + if (lc->sip_conf.ping_with_options){ + /*the following sends an option request back to the caller so that + we get a chance to discover our nat'd address before answering.*/ + call->ping_op=sal_op_new(lc->sal); + to_str=linphone_address_as_string(to); + from_str=linphone_address_as_string(from); + sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op)); + sal_ping(call->ping_op,to_str,from_str); + ms_free(to_str); + ms_free(from_str); + } linphone_address_clean(from); linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(me)); + linphone_address_get_username(me),lc->sip_conf.only_one_codec); linphone_call_init_common(call, from, to); discover_mtu(lc,linphone_address_get_domain(from)); linphone_address_destroy(me); @@ -171,9 +186,21 @@ void linphone_call_destroy(LinphoneCall *obj) linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); linphone_call_log_completed(obj->log,obj); linphone_core_update_allocated_audio_bandwidth(obj->core); - if (obj->op!=NULL) sal_op_release(obj->op); - if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc); - if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc); + if (obj->op!=NULL) { + sal_op_release(obj->op); + obj->op=NULL; + } + if (obj->resultdesc!=NULL) { + sal_media_description_unref(obj->resultdesc); + obj->resultdesc=NULL; + } + if (obj->localdesc!=NULL) { + sal_media_description_unref(obj->localdesc); + obj->localdesc=NULL; + } + if (obj->ping_op) { + sal_op_release(obj->ping_op); + } ms_free(obj); } @@ -271,6 +298,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ calllog->duration=time(NULL)-call->start_time; switch(call->state){ case LCStateInit: + case LCStatePreEstablishing: calllog->status=LinphoneCallAborted; break; case LCStateRinging: @@ -630,11 +658,12 @@ static void sip_config_read(LinphoneCore *lc) } } - /*for test*/ + /*for tuning or test*/ lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); lc->sip_conf.only_one_codec=lp_config_get_int(lc->config,"sip","only_one_codec",0); lc->sip_conf.register_only_when_network_is_up= lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); + lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); } static void rtp_config_read(LinphoneCore *lc) @@ -1581,7 +1610,10 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->call!=NULL){ LinphoneCall *call=lc->call; - + if (call->state==LCStatePreEstablishing && (curtime-call->start_time>=2)){ + /*start the call even if the OPTIONS reply did not arrive*/ + linphone_core_start_invite(lc,call,NULL); + } if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){ elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); @@ -1749,16 +1781,18 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr LinphoneAddress *ctt; const char *localip=call->localip; + /* first use user's supplied ip address if asked*/ if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ ctt=linphone_core_get_primary_contact_parsed(lc); return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt), linphone_core_get_nat_address(lc)); } - + + /* if already choosed, don't change it */ if (call->op && sal_op_get_contact(call->op)!=NULL){ return NULL; } - + /*if using a proxy, use the contact address as guessed with the REGISTERs*/ if (dest_proxy && dest_proxy->op){ const char *fixed_contact=sal_op_get_contact(dest_proxy->op); if (fixed_contact) { @@ -1766,6 +1800,16 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr return ms_strdup(fixed_contact); } } + /* if the ping OPTIONS request succeeded use the contact guessed from the + received, rport*/ + if (call->ping_op){ + const char *guessed=sal_op_get_contact(call->ping_op); + if (guessed){ + ms_message("Contact has been fixed using OPTIONS to %s",guessed); + return ms_strdup(guessed); + } + } + ctt=linphone_core_get_primary_contact_parsed(lc); if (ctt!=NULL){ @@ -1781,6 +1825,47 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr return NULL; } +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ + int err; + char *contact; + char *real_url,*barmsg; + char *from; + /*try to be best-effort in giving real local or routable contact address */ + contact=get_fixed_contact(lc,call,dest_proxy); + if (contact){ + sal_op_set_contact(call->op, contact); + ms_free(contact); + } + call->state=LCStateInit; + linphone_core_init_media_streams(lc,lc->call); + if (!lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; + sal_call_set_local_media_description(call->op,call->localdesc); + } + real_url=linphone_address_as_string(call->log->to); + from=linphone_address_as_string(call->log->from); + err=sal_call(call->op,from,real_url); + + if (lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; + sal_call_set_local_media_description(call->op,call->localdesc); + } + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); + lc->vtable.display_status(lc,barmsg); + ms_free(barmsg); + + if (err<0){ + ms_warning("Could not initiate call."); + lc->vtable.display_status(lc,_("could not call")); + linphone_core_stop_media_streams(lc,call); + linphone_call_destroy(call); + lc->call=NULL; + }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); + ms_free(real_url); + ms_free(from); + return err; +} + /** * Initiates an outgoing call * @@ -1790,11 +1875,9 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr **/ int linphone_core_invite(LinphoneCore *lc, const char *url) { - char *barmsg; int err=0; char *route=NULL; const char *from=NULL; - char *contact=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; LinphoneAddress *real_parsed_url=NULL; @@ -1831,42 +1914,21 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); sal_op_set_route(call->op,route); - - /*try to be best-effort in giving real local or routable contact address */ - contact=get_fixed_contact(lc,call,dest_proxy); - if (contact){ - sal_op_set_contact(call->op, contact); - ms_free(contact); - } - - lc->call=call; - - linphone_core_init_media_streams(lc,lc->call); - if (!lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } - err=sal_call(call->op,from,real_url); - - if (lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } - barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); - lc->vtable.display_status(lc,barmsg); - ms_free(barmsg); - if (err<0){ - ms_warning("Could not initiate call."); - lc->vtable.display_status(lc,_("could not call")); - linphone_core_stop_media_streams(lc,call); - linphone_call_destroy(call); - lc->call=NULL; - }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); - + lc->call=call; + if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ + err=linphone_core_start_invite(lc,call,dest_proxy); + }else{ + /*defer the start of the call after the OPTIONS ping*/ + call->state=LCStatePreEstablishing; + call->ping_op=sal_op_new(lc->sal); + sal_ping(call->ping_op,from,real_url); + call->start_time=time(NULL); + } + if (real_url!=NULL) ms_free(real_url); if (route!=NULL) ms_free(route); - return (err<0) ? -1 : 0; + return err; } int linphone_core_refer(LinphoneCore *lc, const char *url) diff --git a/coreapi/private.h b/coreapi/private.h index 546b83dc2..b23dff67d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -56,6 +56,7 @@ typedef enum _LCState{ LCStateInit, + LCStatePreEstablishing, LCStateRinging, LCStateAVRunning }LCState; @@ -71,6 +72,7 @@ typedef struct _LinphoneCall struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; SalOp *op; + SalOp *ping_op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ @@ -180,6 +182,7 @@ void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); void linphone_core_stop_waiting(LinphoneCore *lc); +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); extern SalCallbacks linphone_sal_callbacks; @@ -253,6 +256,7 @@ typedef struct sip_config bool_t sdp_200_ack; bool_t only_one_codec; /*in SDP answers*/ bool_t register_only_when_network_is_up; + bool_t ping_with_options; } sip_config_t; typedef struct rtp_config diff --git a/coreapi/sal.c b/coreapi/sal.c index ae432d565..750555016 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -128,11 +128,20 @@ const char *sal_op_get_proxy(const SalOp *op){ return ((SalOpBase*)op)->route; } +const char *sal_op_get_network_origin(const SalOp *op){ + return ((SalOpBase*)op)->origin; +} + void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); ((SalOpBase*)b)->root=sal; } +void __sal_op_set_network_origin(SalOp *op, const char *origin){ + assign_string(&((SalOpBase*)op)->origin,origin); +} + + void __sal_op_free(SalOp *op){ SalOpBase *b=(SalOpBase *)op; if (b->from) { @@ -151,6 +160,10 @@ void __sal_op_free(SalOp *op){ ms_free(b->contact); b->contact=NULL; } + if (b->origin){ + ms_free(b->origin); + b->origin=NULL; + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) diff --git a/coreapi/sal.h b/coreapi/sal.h index eb8042361..e672216c9 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -124,6 +124,7 @@ typedef struct SalOpBase{ char *contact; char *from; char *to; + char *origin; SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; @@ -186,6 +187,7 @@ typedef void (*SalOnNotify)(SalOp *op, SalSubscribeState ss, SalPresenceStatus s typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg); +typedef void (*SalOnPingReply)(SalOp *salop); typedef struct SalCallbacks{ SalOnCallReceived call_received; @@ -207,6 +209,7 @@ typedef struct SalCallbacks{ SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; SalOnInternalMsg internal_message; + SalOnPingReply ping_reply; }SalCallbacks; typedef struct SalAuthInfo{ @@ -219,7 +222,6 @@ typedef struct SalAuthInfo{ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure); void sal_set_user_agent(Sal *ctx, const char *user_agent); -void sal_masquerade(Sal *ctx, const char *ip); void sal_use_session_timers(Sal *ctx, int expires); int sal_iterate(Sal *sal); MSList * sal_get_pending_auths(Sal *sal); @@ -242,6 +244,8 @@ const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const char *sal_op_get_route(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); +/*for incoming requests, returns the origin of the packet as a sip uri*/ +const char *sal_op_get_network_origin(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); /*Call API*/ @@ -273,6 +277,10 @@ int sal_notify_close(SalOp *op); /*presence publish */ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status); + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to); + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) @@ -282,6 +290,7 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); +void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); void __sal_op_free(SalOp *b); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index daae709db..cf6074db5 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -64,6 +64,36 @@ static void sal_remove_register(Sal *sal, int rid){ } } +static SalOp * sal_find_other(Sal *sal, osip_message_t *response){ + const MSList *elem; + SalOp *op; + osip_call_id_t *callid=osip_message_get_call_id(response); + if (callid==NULL) { + ms_error("There is no call-id in this response !"); + return NULL; + } + for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (osip_call_id_match(callid,op->call_id)==0) return op; + } + return NULL; +} + +static void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ + osip_call_id_t *callid=osip_message_get_call_id(request); + if (callid==NULL) { + ms_error("There is no call id in the request !"); + return; + } + osip_call_id_clone(callid,&op->call_id); + sal->other_transactions=ms_list_append(sal->other_transactions,op); +} + +static void sal_remove_other(Sal *sal, SalOp *op){ + sal->other_transactions=ms_list_remove(sal->other_transactions,op); +} + + static void sal_add_pending_auth(Sal *sal, SalOp *op){ sal->pending_auths=ms_list_append(sal->pending_auths,op); } @@ -107,6 +137,7 @@ SalOp * sal_op_new(Sal *sal){ op->pending_auth=NULL; op->sdp_answer=NULL; op->reinvite=FALSE; + op->call_id=NULL; return op; } @@ -127,6 +158,10 @@ void sal_op_release(SalOp *op){ } if (op->result) sal_media_description_unref(op->result); + if (op->call_id){ + sal_remove_other(op->base.root,op); + osip_call_id_free(op->call_id); + } __sal_op_free(op); } @@ -191,11 +226,6 @@ void *sal_get_user_pointer(const Sal *sal){ return sal->up; } -void sal_masquerade(Sal *ctx, const char *ip){ - ms_message("Masquerading SIP with %s",ip); - eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip); -} - static void unimplemented_stub(){ ms_warning("Unimplemented SAL callback"); } @@ -232,6 +262,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.internal_message==NULL) ctx->callbacks.internal_message=(SalOnInternalMsg)unimplemented_stub; + if (ctx->callbacks.ping_reply==NULL) + ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; } int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ @@ -461,6 +493,24 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ return h->result; } +int sal_ping(SalOp *op, const char *from, const char *to){ + osip_message_t *options=NULL; + + sal_op_set_from(op,from); + sal_op_set_to(op,to); + eXosip_options_build_request (&options, sal_op_get_to(op), + sal_op_get_from(op),sal_op_get_route(op)); + if (options){ + if (op->base.root->session_expires!=0){ + osip_message_set_header(options, "Session-expires", "200"); + osip_message_set_supported(options, "timer"); + } + sal_add_other(sal_op_get_sal(op),op,options); + return eXosip_options_send_request(options); + } + return -1; +} + int sal_refer(SalOp *h, const char *refer_to){ osip_message_t *msg=NULL; int err=0; @@ -518,11 +568,30 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ } } +static void set_network_origin(SalOp *op, osip_message_t *req){ + const char *received=NULL; + int rport=5060; + char origin[64]; + if (extract_received_rport(req,&received,&rport)!=0){ + osip_via_t *via=NULL; + char *tmp; + osip_message_get_via(req,0,&via); + received=osip_via_get_host(via); + tmp=osip_via_get_port(via); + if (tmp) rport=atoi(tmp); + } + snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); + __sal_op_set_network_origin(op,origin); +} + static void inc_new_call(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); osip_from_t *from,*to; char *tmp; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + + set_network_origin(op,ev->request); + if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); @@ -613,22 +682,10 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ } } -static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; +static void update_contact_from_response(SalOp *op, osip_message_t *response){ const char *received; int rport; - - if (op==NULL) { - ms_warning("This call has been canceled."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return -1; - } - op->did=ev->did; - op->tid=ev->tid; - /* update contact if received and rport are set by the server */ - if (extract_received_rport(ev->response,&received,&rport)==0){ + if (extract_received_rport(response,&received,&rport)==0){ const char *contact=sal_op_get_contact(op); if (!contact){ /*no contact given yet, use from instead*/ @@ -640,11 +697,29 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ sal_address_set_domain(addr,received); sal_address_set_port_int(addr,rport); tmp=sal_address_as_string(addr); - ms_message("Contact address automatically updated to %s for this call",tmp); + ms_message("Contact address updated to %s for this dialog",tmp); sal_op_set_contact(op,tmp); ms_free(tmp); } } +} + +static int call_proceeding(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + + if (op==NULL) { + ms_warning("This call has been canceled."); + eXosip_lock(); + eXosip_call_terminate(ev->cid,ev->did); + eXosip_unlock(); + return -1; + } + op->did=ev->did; + op->tid=ev->tid; + + /* update contact if received and rport are set by the server + note: will only be used by remote for next INVITE, if any...*/ + update_contact_from_response(op,ev->response); return 0; } @@ -668,6 +743,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ osip_message_t *msg=NULL; SalOp *op; const char *contact; + op=(SalOp*)ev->external_reference; if (op==NULL){ ms_error("A closed call is accepted ?"); @@ -778,6 +854,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ if (ev->rid>0){ return sal_find_register(sal,ev->rid); } + if (ev->response) return sal_find_other(sal,ev->response); return NULL; } @@ -1152,6 +1229,19 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ return TRUE; } +static void other_request_reply(Sal *sal,eXosip_event_t *ev){ + SalOp *op=find_op(sal,ev); + + if (op==NULL){ + ms_warning("other_request_reply(): Receiving response to unknown request."); + return; + } + if (ev->response){ + update_contact_from_response(op,ev->response); + sal->callbacks.ping_reply(op); + } +} + static bool_t process_event(Sal *sal, eXosip_event_t *ev){ switch(ev->type){ case EXOSIP_CALL_ANSWERED: @@ -1242,6 +1332,13 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ case EXOSIP_MESSAGE_NEW: other_request(sal,ev); break; + case EXOSIP_MESSAGE_PROCEEDING: + case EXOSIP_MESSAGE_ANSWERED: + case EXOSIP_MESSAGE_REDIRECTED: + case EXOSIP_MESSAGE_SERVERFAILURE: + case EXOSIP_MESSAGE_GLOBALFAILURE: + other_request_reply(sal,ev); + break; case EXOSIP_MESSAGE_REQUESTFAILURE: if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ return process_authentication(sal,ev); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 4e5d81240..226948134 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -34,6 +34,7 @@ struct Sal{ MSList *out_subscribes;/*MSList of SalOp */ MSList *in_subscribes;/*MSList of SalOp */ MSList *pending_auths;/*MSList of SalOp */ + MSList *other_transactions; /*MSList of SalOp */ int running; int session_expires; void *up; @@ -51,6 +52,8 @@ struct SalOp{ SalMediaDescription *result; sdp_message_t *sdp_answer; eXosip_event_t *pending_auth; + osip_call_id_t *call_id; /*used for out of calls transaction in order + to retrieve the operation when receiving a response*/ bool_t supports_session_timers; bool_t sdp_offering; bool_t reinvite;