[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "threading" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Thu May 12 15:02:19 CDT 2011


branch "threading" has been updated
       via  275aecd899a44502b0a4f76eab747691bd92af5f (commit)
      from  78e5e7f41cc406ab6fd735cd3bc2684f2ededd38 (commit)

Summary of changes:
 src/PJSipSessionModule.cpp |  459 ++++++++++++++++++++++++++------------------
 src/PJSipSessionModule.h   |   24 +++
 2 files changed, 298 insertions(+), 185 deletions(-)


- Log -----------------------------------------------------------------
commit 275aecd899a44502b0a4f76eab747691bd92af5f
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu May 12 14:59:29 2011 -0500

    Adding content just so it doesn't get lost.
    
    My first attempt at queueing an operation that originates from PJSIP.
    I'm starting with a complex one that makes AMI calls.
    
    This doesn't come close to compiling.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 32ed923..19a6c81 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -100,55 +100,6 @@ private:
 };
 typedef IceUtil::Handle<RouteSessionCallback> RouteSessionCallbackPtr;
 
-class ConnectBridgedSessionsCallback : public IceUtil::Shared
-{
-public:
-    ConnectBridgedSessionsCallback(pjsip_inv_session *inv_session,
-                                   pjsip_tx_data *tdata, 
-                                   pjsip_transaction *tsx,
-                                   const SipSessionPtr& session,
-                                   const SipSessionPtr& otherSession,
-                                   const std::string& operationId)
-        : mInvSession(inv_session), 
-          mTData(tdata), 
-          mTsx(tsx),
-          mSession(session),
-          mOtherSession(otherSession),
-          mOperationId(operationId)
-
-    { 
-    }
-
-    void callback(const Ice::AsyncResultPtr &r)
-    {
-        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(r->getProxy());
-        try
-        {
-            router->end_connectBridgedSessions(r);
-        }
-        catch (const std::exception &e)
-        {
-            lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
-            pjsip_dlg_modify_response(mInvSession->dlg, mTData, 400, NULL);
-            pjsip_dlg_send_response(mInvSession->dlg, mTsx, mTData);
-            return;
-        }
-        pjsip_dlg_send_response(mInvSession->dlg, mTsx, mTData);
-        
-        Ice::Current current;
-        lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
-        mSession->stop(new ResponseCode(16), current);
-    }
-private:
-    pjsip_inv_session *mInvSession;
-    pjsip_tx_data *mTData;
-    pjsip_transaction *mTsx;
-    SipSessionPtr mSession;
-    SipSessionPtr mOtherSession;
-    std::string mOperationId;
-};
-
-typedef IceUtil::Handle<ConnectBridgedSessionsCallback> ConnectBridgedSessionsCallbackPtr;
 
 class ConnectBridgedSessionsWithDestinationCallback : public IceUtil::Shared
 {
@@ -491,6 +442,9 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
 
     //XXX Put caller identification code in here!
 
+    //We handle most of the processing here synchronously since
+    //at this point there is no associated session, plus the lead-up
+    //to creating a session is not especially intensive.
     pjsip_tx_data *tdata = NULL;
     unsigned options = PJSIP_INV_SUPPORT_100REL;
 
@@ -559,6 +513,10 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     pjsip_timer_setting_default(&session_timer_settings);
     pjsip_timer_init_session(inv_session, &session_timer_settings);
 
+    //XXX This marks the last time we actually make use of the 
+    //rdata in this function. The times past this point are to get
+    //data from within the rdata. We can just as easily get that
+    //earlier.
     if (pjsip_inv_initial_answer(inv_session, rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS)
     {
         lg(Warning) << "Failed to create 100 Trying response";
@@ -609,6 +567,16 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
         lg(Debug) << "Call is destined for " << destination;
     }
 
+    //XXX This is the point where it would be nice to just return. The SessionWork is created
+    //in the createSession() method at the moment, which actually makes this a tad tough. What
+    //would be better would be to create the SessionWork here. Then we could queue the
+    //createSession operation onto it and just return here. Then, when the createSession()
+    //operation runs, when it needs to call out to the media component to create the media
+    //session, it can use AMI to call out and return "Suspended." Then the AMI callback can
+    //return to us and we can complete the session creation operation and then call out to the
+    //routing service and again return "Suspended." Then once *THAT* returns, we can finally
+    //return "Complete".
+    
     SipSessionPtr session;
     try
     {
@@ -657,176 +625,282 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     }
 }
 
-void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+class HandleReferOperation : public SuspendableWork, public IceUtil::Shared
 {
-    const pj_str_t str_refer_to = { (char*)"Refer-To", 8 };
-    pjsip_generic_string_hdr *refer_to =
-        static_cast<pjsip_generic_string_hdr *>(pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL));
-
-    lg(Debug) << "Handling a REFER";
-    if (!refer_to)
+public:
+    HandleReferOperation(
+            pjsip_inv_session *inv,
+            pjsip_transaction *tsx,
+            pjsip_tx_data *tdata,
+            pjsip_sip_uri *target_sip_uri,
+            const SipSessionPtr& session,
+            const SmartProxy<SessionRouterPrx>& sessionRouter)
+        : mState(Initial), mInv(inv), mTsx(tsx), mTdata(tdata), 
+        mTargetSipUri(target_sip_uri), mSession(session), mSessionRouter(sessionRouter) { }
+
+    SuspendableWorkResult execute(const SuspendableWorkListenerPtr& workListener)
     {
-        // Uh... so they didn't tell us where to REFER this to... yeah no
-        lg(Debug) << "handleRefer() sending 400 due to no refer_to. ";
-        pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
-        return;
+        switch (mState)
+        {
+        case Initial:
+            return processRefer(workListener);
+        case CalledBack:
+            return processRoutingResponse(workListener);
+        default:
+            lg(Error) << "We're in a bad state here...and I don't mean South Dakota!";
+            return Complete;
+        }
     }
 
-    // TODO: Add support for subscription
-
-    // TODO: Provide method to send back suitable response
-
-    // Now parse the URI to get the actual target they want to refer to
-    pjsip_uri *target_uri = static_cast<pjsip_uri *>(pjsip_parse_uri(inv->dlg->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0));
-
-    // We only support SIP URIs, anything else is rubbish to us
-    if (!PJSIP_URI_SCHEME_IS_SIP(target_uri) && !PJSIP_URI_SCHEME_IS_SIPS(target_uri))
+    void changeState()
     {
-        // TODO: Place proper response code in here
-        lg(Debug) << "handleRefer() sending 400 due to non-SIP URI. ";
-        pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
-        return;
+        ++mState;
     }
 
-    pjsip_sip_uri *target_sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(target_uri);
-
-    // Determine if this is a blind transfer or an attended transfer
-    pj_str_t replaces = pj_str((char*)"Replaces");
-    pjsip_param *replaces_param = pjsip_param_find(&target_sip_uri->other_param, &replaces);
-
-    if (!replaces_param)
+    SuspendableWorkResult processRoutingResponse(workListener)
     {
-        replaces_param = pjsip_param_find(&target_sip_uri->header_param, &replaces);
+        assert(mAsyncResult);
+        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(r->getProxy());
+        try
+        {
+            router->end_connectBridgedSessions(r);
+        }
+        catch (const std::exception &e)
+        {
+            lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
+            pjsip_dlg_modify_response(mInv->dlg, mTData, 400, NULL);
+            pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+            return;
+        }
+        pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+        
+        Ice::Current current;
+        lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
+        mSession->stop(new ResponseCode(16), current);
     }
 
-    if (replaces_param)
+    SuspendableWorkResult processRefer(const SuspendableWorKListenerPtr& workListener)
     {
-        pj_str_t to_tag = pj_str((char*)"To-tag");
-        pj_str_t from_tag = pj_str((char*)"From-tag");
-        pjsip_param *to_tag_param = pjsip_param_find(&target_sip_uri->other_param, &to_tag);
-        pjsip_param *from_tag_param = pjsip_param_find(&target_sip_uri->other_param, &from_tag);
-        pjsip_dialog *other_dlg = NULL;
+        // Determine if this is a blind transfer or an attended transfer
+        pj_str_t replaces = pj_str((char*)"Replaces");
+        pjsip_param *replaces_param = pjsip_param_find(&mTargetSipUri->other_param, &replaces);
 
-        if (to_tag_param && from_tag_param)
+        if (!replaces_param)
         {
-            other_dlg = pjsip_ua_find_dialog(&replaces_param->value, &to_tag_param->value, &from_tag_param->value,
-                    PJ_TRUE);
+            replaces_param = pjsip_param_find(&mTargetSipUri->header_param, &replaces);
         }
-        else
+
+        if (replaces_param)
         {
-            // It is possible for the to and from tag value to be present within the Replaces parameter value, so try to
-            // parse it out
-            std::string replaces_value_tmp = std::string(pj_strbuf(&replaces_param->value),
-                    pj_strlen(&replaces_param->value));
-            size_t from_tag_pos = replaces_value_tmp.find(";from-tag=");
-            size_t to_tag_pos = replaces_value_tmp.find(";to-tag=");
-
-            if (from_tag_pos == std::string::npos || to_tag_pos == std::string::npos)
+            pj_str_t to_tag = pj_str((char*)"To-tag");
+            pj_str_t from_tag = pj_str((char*)"From-tag");
+            pjsip_param *to_tag_param = pjsip_param_find(&mTargetSipUri->other_param, &to_tag);
+            pjsip_param *from_tag_param = pjsip_param_find(&mTargetSipUri->other_param, &from_tag);
+            pjsip_dialog *other_dlg = NULL;
+
+            if (to_tag_param && from_tag_param)
             {
-                lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
-                pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
-                return;
+                other_dlg = pjsip_ua_find_dialog(&replaces_param->value, &to_tag_param->value, &from_tag_param->value,
+                        PJ_TRUE);
             }
+            else
+            {
+                // It is possible for the to and from tag value to be present within the Replaces parameter value, so try to
+                // parse it out
+                std::string replaces_value_tmp = std::string(pj_strbuf(&replaces_param->value),
+                        pj_strlen(&replaces_param->value));
+                size_t from_tag_pos = replaces_value_tmp.find(";from-tag=");
+                size_t to_tag_pos = replaces_value_tmp.find(";to-tag=");
+
+                if (from_tag_pos == std::string::npos || to_tag_pos == std::string::npos)
+                {
+                    lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
+                    pjsip_dlg_modify_response(mInv->dlg, mTData, 400, NULL);
+                    pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+                    return Complete;
+                }
 
-            std::string to_tag_value = replaces_value_tmp.substr(to_tag_pos + 8, from_tag_pos - to_tag_pos - 8);
-            std::string from_tag_value = replaces_value_tmp.substr(from_tag_pos + 10);
-            std::string replaces_value = replaces_value_tmp.substr(0, to_tag_pos);
-
-            pj_str_t to_tag_str = pj_str((char*)to_tag_value.c_str());
-            pj_str_t from_tag_str = pj_str((char*)from_tag_value.c_str());
-            pj_str_t replaces_tag_str = pj_str((char*)replaces_value.c_str());
+                std::string to_tag_value = replaces_value_tmp.substr(to_tag_pos + 8, from_tag_pos - to_tag_pos - 8);
+                std::string from_tag_value = replaces_value_tmp.substr(from_tag_pos + 10);
+                std::string replaces_value = replaces_value_tmp.substr(0, to_tag_pos);
 
-            other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
-        }
+                pj_str_t to_tag_str = pj_str((char*)to_tag_value.c_str());
+                pj_str_t from_tag_str = pj_str((char*)from_tag_value.c_str());
+                pj_str_t replaces_tag_str = pj_str((char*)replaces_value.c_str());
 
-        if (!other_dlg)
-        {
-            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_dlg. ";
-            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
-            return;
-        }
+                other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
+            }
 
-        pjsip_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
+            if (!other_dlg)
+            {
+                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_dlg. ";
+                pjsip_dlg_modify_response(mInv->dlg, mTData, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+                pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+                return Complete;
+            }
 
-        if (!other_inv)
-        {
-            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_inv. ";
-            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
-            pjsip_dlg_dec_lock(other_dlg);
-            return;
-        }
+            pjsip_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
 
-        if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
-        {
-            lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
+            if (!other_inv)
+            {
+                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to no other_inv. ";
+                pjsip_dlg_modify_response(mInv->dlg, mTData, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+                pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+                pjsip_dlg_dec_lock(other_dlg);
+                return Complete;
+            }
 
-            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_DECLINE, NULL, NULL, NULL);
-            pjsip_dlg_dec_lock(other_dlg);
-            return;
-        }
+            if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
+            {
+                lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
 
-        if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
-        {
-            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
+                pjsip_dlg_modify_response(mInv->dlg, mTData, PJSIP_SC_DECLINE, NULL);
+                pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+                pjsip_dlg_dec_lock(other_dlg);
+                return Complete;
+            }
 
-            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
-            pjsip_dlg_dec_lock(other_dlg);
-            return;
-        }
+            if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
+            {
+                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
 
-        PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
-        SipSessionPtr session = session_mod_info->getSessionPtr();
+                pjsip_dlg_modify_response(mInv->dlg, mTData, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
+                pjsip_dlg_send_response(mInv->dlg, mTsx, mTData);
+                pjsip_dlg_dec_lock(other_dlg);
+                return Complete;
+            }
 
-        PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModule.id];
-        SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
+            PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModule.id];
+            SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
 
-        try
-        {
-            pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-            pjsip_tx_data *tdata;
-            pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
-            std::string operationId = ::IceUtil::generateUUID();
-            ConnectBridgedSessionsCallbackPtr cb(new ConnectBridgedSessionsCallback(inv, tdata, tsx, session, other_session, operationId));
-            Ice::CallbackPtr d = Ice::newCallback(cb, &ConnectBridgedSessionsCallback::callback);
+            try
+            {
+                std::string operationId = ::IceUtil::generateUUID();
+                SipAMICallbackPtr cb(new SipAMICallback(workListener, this));
+                Ice::CallbackPtr d = Ice::newCallback(cb, &ConnectBridgedSessionsCallback::callback);
 
-            lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
-            mSessionRouter->begin_connectBridgedSessions(operationId, session->getSessionProxy(), other_session->getSessionProxy(), d);
+                lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
+                mSessionRouter->begin_connectBridgedSessions(operationId, mSession->getSessionProxy(), other_session->getSessionProxy(), d);
+                return Suspended;
+            }
+            catch (const Ice::CommunicatorDestroyedException &)
+            {
+                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
+                pjsip_dlg_respond(mInv->dlg, rdata, 503, NULL, NULL, NULL);
+                return Complete;
+            }
+            pjsip_dlg_dec_lock(other_dlg);
         }
-        catch (const Ice::CommunicatorDestroyedException &)
+        else
         {
-            lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
-            pjsip_dlg_respond(inv->dlg, rdata, 503, NULL, NULL, NULL);
-            return;
+            std::string target = std::string(pj_strbuf(&mTargetSipUri->user), pj_strlen(&mTargetSipUri->user));
+
+            // Now that we have the target user we can pass this into routing and go on our marry way
+            try
+            {
+                std::string operationId = ::IceUtil::generateUUID();
+                PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModule.id];
+                SipSessionPtr session = session_mod_info->getSessionPtr();
+                SipAMICallbackPtr cb(new SipAMICallback(workListener, this));
+                Ice::CallbackPtr d = Ice::newCallback(cb, &ConnectBridgedSessionsWithDestinationCallback::callback);
+
+                lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
+                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), target, d);
+                return Suspended;
+            }
+            catch (const Ice::CommunicatorDestroyedException &)
+            {
+                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
+                pjsip_dlg_respond(mInv->dlg, rdata, 503, NULL, NULL, NULL);
+                return Complete;
+            }
         }
-        pjsip_dlg_dec_lock(other_dlg);
-    }
-    else
+    };
+
+    enum states
     {
-        std::string target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
+        Initial,
+        CalledBack,
+    } mState;
+    /**
+     * The INVITE session, which contains the dialog on which the
+     * REFER was received.
+     */
+    pjsip_inv_session *mInv;
+    /**
+     * The REFER transaction
+     */
+    pjsip_transaction *mTsx;
+    /**
+     * The transmission data for our REFER response. We set this
+     * up to default to a 200 OK response and alter it if necessary.
+     */
+    pjsip_tx_data *mTdata;
+    /**
+     * The SIP URI from the Refer-To header in the REFER request.
+     */
+    pjsip_sip_uri *mTargetSipUri;
+    /**
+     * The SipSession on which this work is executed
+     */
+    SipSessionPtr mSession;
+    /**
+     * Session router...nothing more to say really
+     */
+    SmartProxy<SessionRouterPrx> mSessionRouter;
+    /**
+     * The result of any AMI calls we make
+     */
+    Ice::AsyncResultPtr mAsyncResult;
+};
 
-        // Now that we have the target user we can pass this into routing and go on our marry way
-        try
-        {
-            std::string operationId = ::IceUtil::generateUUID();
-            PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
-            SipSessionPtr session = session_mod_info->getSessionPtr();
-            pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
-            pjsip_tx_data *tdata;
-            pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
-            ConnectBridgedSessionsWithDestinationCallbackPtr cb(
-                    new ConnectBridgedSessionsWithDestinationCallback(inv, tdata, tsx, session, target, operationId));
-            Ice::CallbackPtr d = Ice::newCallback(cb, &ConnectBridgedSessionsWithDestinationCallback::callback);
-
-            lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
-            mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), target, d);
-        }
-        catch (const Ice::CommunicatorDestroyedException &)
-        {
-            lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
-            pjsip_dlg_respond(inv->dlg, rdata, 503, NULL, NULL, NULL);
-            return;
-        }
+void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+{
+    //rdata structures are not safe to shallow copy to a queuable operation. Get
+    //what we need out of it.
+    const pj_str_t str_refer_to = { (char*)"Refer-To", 8 };
+    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+    pjsip_generic_string_hdr *refer_to =
+        static_cast<pjsip_generic_string_hdr *>(pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL));
+
+    lg(Debug) << "Handling a REFER";
+    if (!refer_to)
+    {
+        // Uh... so they didn't tell us where to REFER this to... yeah no
+        lg(Debug) << "handleRefer() sending 400 due to no refer_to. ";
+        pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
+        return;
+    }
+
+    // TODO: Add support for subscription
+
+    // TODO: Provide method to send back suitable response
+
+    // Now parse the URI to get the actual target they want to refer to
+    //
+    // Parsing the URI allocates memory in the dialog's pool, thus allowing a
+    // safe shallow copy to a queueable operation.
+    pjsip_uri *target_uri = static_cast<pjsip_uri *>(pjsip_parse_uri(inv->dlg->pool, refer_to->hvalue.ptr, refer_to->hvalue.slen, 0));
+
+    // We only support SIP URIs, anything else is rubbish to us
+    if (!PJSIP_URI_SCHEME_IS_SIP(target_uri) && !PJSIP_URI_SCHEME_IS_SIPS(target_uri))
+    {
+        // TODO: Place proper response code in here
+        lg(Debug) << "handleRefer() sending 400 due to non-SIP URI. ";
+        pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
+        return;
     }
+
+    pjsip_sip_uri *target_sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(target_uri);
+
+    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*) inv->mod_data[mModule.id];
+    SipSessionPtr session = session_mod_info->getSessionPtr();
+
+    //Create our initial response that we can modify in the queueable operation.
+    pjsip_tx_data *tdata;
+    pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
+
+    session->enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, target_sip_uri, session, mSessionRouter));
 }
 
 pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
@@ -854,7 +928,7 @@ pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
             break;
         }
     default:
-	pjsip_endpt_respond_stateless(mEndpoint, rdata, 405, NULL, NULL, NULL);
+        pjsip_endpt_respond_stateless(mEndpoint, rdata, 405, NULL, NULL, NULL);
 	break;
     }
 
@@ -1318,6 +1392,20 @@ void PJSipSessionModuleThreadPoolListener::queueEmptied(const PoolPtr& pool)
     pool->setSize(0);
 }
 
+class SipSessionSuspendableWorkListener : public SuspendableWorkListener
+{
+public:
+    SipSessionSuspendableWorkListener(const QueueListenerPtr& queueListener)
+        : mQueueListener(queueListener) { }
+
+    void workResumable()
+    {
+        mQueueListener->workResumable();
+    }
+
+    QueueListenerPtr mQueueListener;
+};
+
 SessionWork::SessionWork(const QueuePtr& queue)
     : mThreadPoolQueue(queue),
     mInternalQueue(new SuspendableWorkQueue(this)) { }
@@ -1343,7 +1431,8 @@ void SessionWork::emptied()
 
 void SessionWork::execute()
 {
-    while(mInternalQueue->executeWork());
+    SuspendableWorkListenerPtr listener(new SipSessionSuspendableWorkListener(this));
+    while(mInternalQueue->executeWork(listener));
 }
 
 void SessionWork::enqueueWork(const SuspendableWorkPtr& work)
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 75706e3..dbbd95a 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -26,6 +26,7 @@
 #include <AsteriskSCF/SmartProxy.h>
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
 #include <AsteriskSCF/System/ThreadPool/ThreadPoolIf.h>
+#include <AsteriskSCF/System/WorkQueue/WorkQueueIf.h>
 
 #include "SipStateReplicator.h"
 #include "SipSession.h"
@@ -124,5 +125,28 @@ private:
     AsteriskSCF::System::ThreadPool::V1::PoolListenerPtr mPoolListener;
 };
 
+template <class T>
+class SipAMICallback : public IceUtil::Shared
+{
+public:
+    SipAMICallback(
+            const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr& listener,
+            const T& operation)
+        : mListener(listener), mOperation(operation)
+    {
+    }
+
+    void callback(const Ice::AsyncResultPtr &r)
+    {
+        mOperation->mAsyncResult = r;
+        mOperation->changeState();
+        mListener->workResumable();
+    }
+
+private:
+    AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr& mListener;
+    T& mOperation;
+};
+
 }; //end namespace SipSessionManager
 }; //end namespace AsteriskSCF

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list