From 5cc1aeb9c4586e7377882bdf7f90d6b1a70251b5 Mon Sep 17 00:00:00 2001
From: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
Date: Wed, 19 Sep 2012 14:30:51 -0400
Subject: [PATCH] * #15545: respond to INVITE that has no SDP with an OK that
 has an SDP

---
 daemon/src/call.h              |  2 --
 daemon/src/iax/iaxcall.h       |  3 ++-
 daemon/src/iax/iaxvoiplink.cpp |  2 +-
 daemon/src/sip/sdp.cpp         | 11 ++++++-----
 daemon/src/sip/sipcall.cpp     |  4 ++--
 daemon/src/sip/sipcall.h       |  6 ++++--
 daemon/src/sip/sipvoiplink.cpp | 21 +++++++++++++++++++--
 7 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/daemon/src/call.h b/daemon/src/call.h
index 281f896724..2a4b8da43b 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -173,8 +173,6 @@ class Call : public Recordable {
             isIPToIP_ = IPToIP;
         }
 
-        virtual void answer() = 0;
-
         /**
          * Set my IP [not protected]
          * @param ip  The local IP address
diff --git a/daemon/src/iax/iaxcall.h b/daemon/src/iax/iaxcall.h
index 1cf5233cea..d9dfde7700 100644
--- a/daemon/src/iax/iaxcall.h
+++ b/daemon/src/iax/iaxcall.h
@@ -71,10 +71,11 @@ class IAXCall : public Call {
 
         int getAudioCodec() const;
 
+        void answer();
+
         int format;
         iax_session* session;
     private:
-        virtual void answer();
         NON_COPYABLE(IAXCall);
 };
 
diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp
index aaf1333cf2..0518937d6e 100644
--- a/daemon/src/iax/iaxvoiplink.cpp
+++ b/daemon/src/iax/iaxvoiplink.cpp
@@ -278,7 +278,7 @@ IAXVoIPLink::answer(Call *call)
     Manager::instance().addStream(call->getCallId());
 
     mutexIAX_.enter();
-    call->answer();
+    static_cast<IAXCall*>(call)->answer();
     mutexIAX_.leave();
 
     call->setState(Call::ACTIVE);
diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp
index 0f54dd6621..1c9a547dba 100644
--- a/daemon/src/sip/sdp.cpp
+++ b/daemon/src/sip/sdp.cpp
@@ -386,15 +386,16 @@ bool
 Sdp::createOffer(const vector<int> &selectedCodecs,
                  const vector<map<string, string> > &videoCodecs)
 {
-    bool result = true;
     if (createLocalSession(selectedCodecs, videoCodecs) != PJ_SUCCESS) {
         ERROR("Failed to create initial offer");
-        result = false;
-    } else if (pjmedia_sdp_neg_create_w_local_offer(memPool_, localSession_, &negotiator_) != PJ_SUCCESS) {
+        return false;
+    }
+
+    if (pjmedia_sdp_neg_create_w_local_offer(memPool_, localSession_, &negotiator_) != PJ_SUCCESS) {
         ERROR("Failed to create an initial SDP negotiator");
-        result = false;
+        return false;
     }
-    return result;
+    return true;
 }
 
 void Sdp::receiveOffer(const pjmedia_sdp_session* remote,
diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp
index f91a00af42..8359bf2fe3 100644
--- a/daemon/src/sip/sipcall.cpp
+++ b/daemon/src/sip/sipcall.cpp
@@ -62,10 +62,10 @@ SIPCall::~SIPCall()
     pj_pool_release(pool_);
 }
 
-void SIPCall::answer()
+void SIPCall::answer(bool needsSdp)
 {
     pjsip_tx_data *tdata;
-    if (pjsip_inv_answer(inv, PJSIP_SC_OK, NULL, NULL, &tdata) != PJ_SUCCESS)
+    if (pjsip_inv_answer(inv, PJSIP_SC_OK, NULL, needsSdp ? local_sdp_->getLocalSdpSession() : NULL, &tdata) != PJ_SUCCESS)
         throw std::runtime_error("Could not init invite request answer (200 OK)");
 
     if (pjsip_inv_send_msg(inv, tdata) != PJ_SUCCESS)
diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h
index ba7e5e2878..edd56b6afe 100644
--- a/daemon/src/sip/sipcall.h
+++ b/daemon/src/sip/sipcall.h
@@ -100,6 +100,10 @@ class SIPCall : public Call {
             return pool_;
         }
 
+        // @param needsSdp: true if the invite was received without an SDP
+        // and thus one must been added, false otherwise
+        void answer(bool needsSdp);
+
         /**
          * The invite session to be reused in case of transfer
          */
@@ -114,8 +118,6 @@ class SIPCall : public Call {
         std::map<std::string, std::string>
         createHistoryEntry() const;
 
-        virtual void answer();
-
         NON_COPYABLE(SIPCall);
 
         /**
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index 2c1182b213..6967efe2a4 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -902,7 +902,17 @@ SIPVoIPLink::answer(Call *call)
 {
     if (!call)
         return;
-    call->answer();
+
+    SIPCall *sipCall = static_cast<SIPCall*>(call);
+    bool needsSdp = false;
+    if (!sipCall->inv->neg) {
+        WARN("Negotiator is NULL, we've received an INVITE without an SDP");
+        pjmedia_sdp_session *dummy;
+        sdp_create_offer_cb(sipCall->inv, &dummy);
+        needsSdp = true;
+    }
+
+    sipCall->answer(needsSdp);
 }
 
 namespace {
@@ -946,8 +956,15 @@ SIPVoIPLink::hangup(const std::string& id)
 
     pjsip_tx_data *tdata = NULL;
 
+    const int status =
+        inv->state <= PJSIP_INV_STATE_EARLY and inv->role != PJSIP_ROLE_UAC ?
+                      PJSIP_SC_CALL_TSX_DOES_NOT_EXIST :
+        inv->state >= PJSIP_INV_STATE_DISCONNECTED ? PJSIP_SC_DECLINE :
+        0;
+
+
     // User hangup current call. Notify peer
-    if (pjsip_inv_end_session(inv, 0, NULL, &tdata) != PJ_SUCCESS || !tdata)
+    if (pjsip_inv_end_session(inv, status, NULL, &tdata) != PJ_SUCCESS || !tdata)
         return;
 
     // add contact header
-- 
GitLab