]> sjero.net Git - linphone/commitdiff
use OPTIONS message to try to discover local contact.
authorSimon Morlat <simon.morlat@linphone.org>
Fri, 12 Mar 2010 17:49:44 +0000 (18:49 +0100)
committerSimon Morlat <simon.morlat@linphone.org>
Fri, 12 Mar 2010 17:49:44 +0000 (18:49 +0100)
- before outgoing INVITES
- just after receiving an INVITE

coreapi/callbacks.c
coreapi/linphonecore.c
coreapi/private.h
coreapi/sal.c
coreapi/sal.h
coreapi/sal_eXosip2.c
coreapi/sal_eXosip2.h

index edce2c4e38cb5285f1a0f21470e578b1051fb976..4e8f75028d823768948d69d2d65c914194f56720 100644 (file)
@@ -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
 };
 
 
index 2c163d490e28fe35e1f86d86dd8e9aaffb7dffef..e269f46119dde5f78ec867dd56d59d8c2081f151 100644 (file)
@@ -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);
+       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);
        }
-       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);
-
        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)
index 546b83dc200c5ccd1a0fadb25838a5af0c6474ec..b23dff67ddd7a5fe6dc396d63949231d925c5653 100644 (file)
@@ -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
index ae432d565d4c8b95f77a0c10dd80e544fb1a2155..750555016dbab07db319d606e848a063e0d8e7e6 100644 (file)
@@ -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)
index eb8042361b3de18a1265c4976cca548f64efe709..e672216c9c9600511fcc813fe81b40cd29ad2d23 100644 (file)
@@ -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);
 
 
index daae709db8c883e5895675104616c3ee4bf078aa..cf6074db522c5049b1426f0801a12612eccb9fbd 100644 (file)
@@ -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);
index 4e5d8124015719daf1d920627a6557d7c3700d64..22694813477cac7dbce22777f91ba685b8638386 100644 (file)
@@ -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;