[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
Tue May 17 19:43:28 CDT 2011


branch "threading" has been updated
       via  57d2734e77552204087bcddeb9fa183255a4d140 (commit)
       via  1580cf9ff932630cb695b181826263c7e293405c (commit)
       via  01e69f75a66763af70bca71aa0783e98169ffd72 (commit)
       via  33d9123112321a9aae36a9f021c1c00fb6b0c425 (commit)
       via  0c327d8e8c59536fda95b1e07f0c54f31b825fdd (commit)
       via  d64b6e6f37ba0048fd66948ae6caf0864af1b3a7 (commit)
       via  847e828ad8e207d2d16cbf6ade1b7004fb2426f2 (commit)
       via  7d0b2a500d2e8867bc3fe8db177e2f968d97a849 (commit)
       via  a4f034dcfb22c527a701dc32eb24df15faf38622 (commit)
       via  81752bfad6b946001b867f04ab47ed1a73203b54 (commit)
       via  9fee5b0a87b2ca58c6c4c4a9fd20dc4773217d2c (commit)
       via  3f83eaaeae44fb9716be7e0932fb52b67dbfb759 (commit)
      from  623654b3e60749219d9fa790649f6833200c708f (commit)

Summary of changes:
 src/CMakeLists.txt                       |    7 +-
 src/PJSipLoggingModule.cpp               |    4 +-
 src/PJSipManager.cpp                     |   15 +-
 src/PJSipManager.h                       |   12 +-
 src/PJSipModule.cpp                      |    5 +-
 src/PJSipSessionModule.cpp               |  271 ++---
 src/PJSipSessionModule.h                 |   29 +-
 src/PJSipSessionModuleConstruction.cpp   |    8 +-
 src/SipConfiguration.cpp                 | 1899 ++++++++++++++++++------------
 src/SipConfiguration.h                   |   32 +-
 src/SipEndpoint.cpp                      |   17 +-
 src/SipEndpoint.h                        |   13 +-
 src/SipEndpointFactory.h                 |    3 +-
 src/SipSession.cpp                       |   53 +-
 src/SipSession.h                         |   24 +-
 src/SipSessionManagerApp.cpp             |   26 +-
 src/SipSessionManagerEndpointLocator.cpp |    6 +-
 src/SipSessionManagerEndpointLocator.h   |    4 +-
 src/SipSessionManagerEventPublisher.cpp  |    4 +-
 src/SipStateReplicator.h                 |   26 +-
 src/SipStateReplicatorApp.cpp            |    4 +-
 src/SipStateReplicatorListener.cpp       |   19 +-
 22 files changed, 1367 insertions(+), 1114 deletions(-)


- Log -----------------------------------------------------------------
commit 57d2734e77552204087bcddeb9fa183255a4d140
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 19:43:08 2011 -0500

    Make sure to initialize the state of the SessionCreationOperation.
    
    Getting lots of segfaults and most are very mysterious at this point.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 45392ad..df2714e 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -330,7 +330,7 @@ public:
             pjsip_tx_data *tdata,
             pjsip_dialog *replacedDialog,
             const std::string destination)
-        : mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination) { }
+        : mState(Initial), mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination) { }
 
     SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
     {

commit 1580cf9ff932630cb695b181826263c7e293405c
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 18:23:56 2011 -0500

    Fix up some annoying indenation probz.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index c301e3a..45392ad 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -468,15 +468,15 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     // Verify we can handle this invite request and respond accordingly if we can not
     if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, mEndpoint, &tdata) != PJ_SUCCESS)
     {
-	if (tdata)
-	{
-	    pjsip_endpt_send_response2(mEndpoint, rdata, tdata, NULL, NULL);
-	}
-	else
-	{
-	    pjsip_endpt_respond_stateless(mEndpoint, rdata, 500, NULL, NULL, NULL);
-	}
-	return;
+        if (tdata)
+        {
+            pjsip_endpt_send_response2(mEndpoint, rdata, tdata, NULL, NULL);
+        }
+        else
+        {
+            pjsip_endpt_respond_stateless(mEndpoint, rdata, 500, NULL, NULL, NULL);
+        }
+        return;
     }
 
     pjsip_dialog *dlg, *replaced_dlg;
@@ -484,14 +484,14 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     // If this is an attended transfer and something is amuck... respond accordingly
     if (pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE, &tdata) != PJ_SUCCESS)
     {
-	if (tdata)
-	{
-	    pjsip_endpt_send_response2(mEndpoint, rdata, tdata, NULL, NULL);
-	}
-	else
-	{
-	    pjsip_endpt_respond_stateless(mEndpoint, rdata, 500, NULL, NULL, NULL);
-	}
+        if (tdata)
+        {
+            pjsip_endpt_send_response2(mEndpoint, rdata, tdata, NULL, NULL);
+        }
+        else
+        {
+            pjsip_endpt_respond_stateless(mEndpoint, rdata, 500, NULL, NULL, NULL);
+        }
         return;
     }
 
@@ -920,7 +920,7 @@ pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
     switch (rdata->msg_info.msg->line.req.method.id)
     {
     case PJSIP_ACK_METHOD:
-	return PJ_FALSE;
+        return PJ_FALSE;
     case PJSIP_INVITE_METHOD:
         if (dlg == NULL)
         {
@@ -940,7 +940,7 @@ pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
         }
     default:
         pjsip_endpt_respond_stateless(mEndpoint, rdata, 405, NULL, NULL, NULL);
-	break;
+        break;
     }
 
     return PJ_TRUE;

commit 01e69f75a66763af70bca71aa0783e98169ffd72
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 18:18:59 2011 -0500

    Fix bug where SessionWork is not created early enough.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index d277ac8..c301e3a 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -537,6 +537,11 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
         pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
         return;
     }
+    
+    SessionWorkPtr sessionWork(new SessionWork(mPoolQueue));
+    SipSessionPtr nullSession(0);
+    PJSipSessionModInfo *session_mod_info(new PJSipSessionModInfo(inv_session, nullSession, sessionWork));
+    inv_session->mod_data[mModule.id] = (void *) session_mod_info;
 
     if (pjsip_inv_send_msg(inv_session, tdata) != PJ_SUCCESS)
     {
@@ -580,12 +585,7 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
         destination = std::string(pj_strbuf(&sipRuri->user), pj_strlen(&sipRuri->user));
         lg(Debug) << "Call is destined for " << destination;
     }
-
-    SessionWorkPtr sessionWork(new SessionWork(mPoolQueue));
-    SipSessionPtr nullSession(0);
-    PJSipSessionModInfo *session_mod_info(new PJSipSessionModInfo(inv_session, nullSession, sessionWork));
-    inv_session->mod_data[mModule.id] = (void *) session_mod_info;
-
+    
     sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
 }
 

commit 33d9123112321a9aae36a9f021c1c00fb6b0c425
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 18:12:37 2011 -0500

    Rewrite the SessionWork to be part of the PJSipSessionModInfo.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 9f1a346..d277ac8 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -60,12 +60,13 @@ using namespace AsteriskSCF::WorkQueue;
 using namespace AsteriskSCF::Core::Discovery::V1;
 
 PJSipSessionModInfo::PJSipSessionModInfo(pjsip_inv_session *inv_session,
-    const SipSessionPtr& session) :
+    const SipSessionPtr& session, const SessionWorkPtr& sessionWork) :
     mSessionState(new SipSessionStateItem),
     mInviteState(new SipInviteSessionStateItem),
     mNeedsReplication(true),
     mNeedsRemoval(false),
-    mSession(session)
+    mSession(session),
+    mSessionWork(sessionWork)
 {
     mSessionState->key = IceUtil::generateUUID();
     mInviteState->key = IceUtil::generateUUID();
@@ -160,6 +161,11 @@ InviteSessionState PJSipSessionModInfo::inviteStateTranslate(pjsip_inv_state sta
     return retState;
 }
 
+SessionWorkPtr PJSipSessionModInfo::getSessionWork()
+{
+    return mSessionWork;
+}
+
 void PJSipSessionModule::replicateState(PJSipDialogModInfo *dlgInfo, PJSipTransactionModInfo *tsxInfo,
     PJSipSessionModInfo *sessionInfo)
 {
@@ -313,7 +319,7 @@ pj_status_t PJSipSessionModule::unload()
     return PJ_SUCCESS;
 }
 
-class SessionCreationOperation : public SipQueueableOperation, public Work
+class SessionCreationOperation : public SipQueueableOperation
 {
 public:
     SessionCreationOperation(
@@ -326,7 +332,21 @@ public:
             const std::string destination)
         : mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination) { }
 
-    void execute()
+    SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+    {
+        switch (mState)
+        {
+            case Initial:
+                return initial();
+            case CalledBack:
+                return calledBack();
+            default:
+                lg(Error) << "We're in a bad state here.";
+                return Complete;
+        }
+    }
+
+    SuspendableWorkResult initial()
     {
         try
         {
@@ -337,17 +357,18 @@ public:
             lg(Error) << "Exception caught while trying to create SIP session\n" << ex.what();
             pjsip_inv_end_session(mInv, 500, NULL, &mTdata);
             pjsip_inv_send_msg(mInv, mTdata);
-            return;
+            return Complete;
         }
         mSession->setInviteSession(mInv);
         mSession->setDialog(mInv->dlg);
-        PJSipSessionModInfo *session_mod_info = new PJSipSessionModInfo(mInv, mSession);
         PJSipDialogModInfo *dlg_mod_info = new PJSipDialogModInfo(mInv->dlg);
         PJSipTransactionModInfo *tsx_mod_info = new PJSipTransactionModInfo(mInv->invite_tsx);
+        PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mSessionModule->getModule().id];
+        // Now we can actually set a for-real non-NULL session on the session module information.
+        session_mod_info->setSessionPtr(mSession);
         dlg_mod_info->mDialogState->mSessionId = session_mod_info->mSessionState->mSessionId;
         tsx_mod_info->mTransactionState->mSessionId = session_mod_info->mSessionState->mSessionId;
     
-        mInv->mod_data[mSessionModule->getModule().id] = (void *)session_mod_info;
         mInv->dlg->mod_data[mSessionModule->getModule().id] = (void *)dlg_mod_info;
     
         lg(Debug) << "Replicating state on reception of new SIP INVITE.";
@@ -366,6 +387,7 @@ public:
                 SuspendableWorkListenerPtr listener = 0;
                 SipAMICallbackPtr cb(new SipAMICallback(listener, mSession, this, false, true));
                 Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+                mState = CalledBack;
                 mSessionRouter->begin_routeSession(operationId, mSession->getSessionProxy(), mDestination, d);
             }
         }
@@ -375,9 +397,10 @@ public:
             pjsip_inv_end_session(mInv, 500, NULL, &mTdata);
             pjsip_inv_send_msg(mInv, mTdata);
         }
+        return Complete;
     }
 
-    SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+    SuspendableWorkResult calledBack()
     {
         SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
         try
@@ -397,6 +420,20 @@ public:
         return Complete;
     }
 
+    enum states
+    {
+        /**
+         * First state.
+         * @see processRefer
+         */
+        Initial,
+        /**
+         * State after routing service completes
+         * @see processRoutingResponse
+         */
+        CalledBack,
+    } mState;
+
     PJSipSessionModulePtr mSessionModule;
     SipEndpointPtr mCaller;
     AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> mSessionRouter;
@@ -544,20 +581,12 @@ 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".
-
-    //We can't do our typical thing of queuing work onto a session here since the session hasn't
-    //yet been created. Instead, we just queue an operation onto the thread pool's queue directly.
+    SessionWorkPtr sessionWork(new SessionWork(mPoolQueue));
+    SipSessionPtr nullSession(0);
+    PJSipSessionModInfo *session_mod_info(new PJSipSessionModInfo(inv_session, nullSession, sessionWork));
+    inv_session->mod_data[mModule.id] = (void *) session_mod_info;
 
-    mPoolQueue->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
+    sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
 }
 
 class HandleReferOperation : public SipQueueableOperation 
@@ -882,7 +911,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     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, mModule.id));
+    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, target_sip_uri, session, mSessionRouter, mModule.id), inv);
 }
 
 pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
@@ -984,6 +1013,7 @@ public:
                 {
                     SipAMICallbackPtr cb(new SipAMICallback(0, mSession, this, false, true));
                     Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+                    mState = CalledBack;
                     (*listener)->begin_indicated(mSession->getSessionProxy(), new RingingIndication(), d);
                 }
                 catch (const Ice::Exception &ex)
@@ -1008,6 +1038,7 @@ public:
                     Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
                     ProgressingIndicationPtr progressing(new ProgressingIndication());
                     progressing->response = response;
+                    mState = CalledBack;
                     (*listener)->begin_indicated(mSession->getSessionProxy(), progressing, d);
                 }
                 catch (const Ice::Exception &ex)
@@ -1030,6 +1061,7 @@ public:
                     {
                         SipAMICallbackPtr cb(new SipAMICallback(0, mSession, this, false, true));
                         Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+                        mState = CalledBack;
                         (*listener)->begin_indicated(mSession->getSessionProxy(), new ConnectedIndication(), d);
                     }
                     catch (const Ice::Exception &ex)
@@ -1090,7 +1122,7 @@ void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
     //XXX There are a BUNCH of response codes we need
     //to add code to handle.
 
-    session->enqueueSessionWork(new HandleInviteResponseOperation(respCode, inv->state, session));
+    enqueueSessionWork(new HandleInviteResponseOperation(respCode, inv->state, session), inv);
 }
 
 class TransactionStateOperation : public SipQueueableOperation
@@ -1235,8 +1267,9 @@ public:
                 //here.
                 if (session_mod_info)
                 {
-                    SipSessionPtr session = session_mod_info->getSessionPtr();
-                    session->enqueueSessionWork(new TransactionStateOperation(mSessionModule, mInv->invite_tsx, mInv, mEventType, mInv->invite_tsx->state));
+                    mSessionModule->enqueueSessionWork(
+                            new TransactionStateOperation(mSessionModule, mInv->invite_tsx, mInv, mEventType, mInv->invite_tsx->state),
+                            mInv);
                 }
             }
         }
@@ -1275,12 +1308,13 @@ void PJSipSessionModule::invOnStateChanged(pjsip_inv_session *inv, pjsip_event *
         //Received a 1XX or 2XX message in response to our initial outgoing INVITE.
         handleInviteResponse(inv, event->body.tsx_state.src.rdata, inv->dlg);
     }
+    std::string branch;
+    if (event->type == PJSIP_EVENT_RX_MSG)
+    {
+        branch = std::string(pj_strbuf(&event->body.rx_msg.rdata->msg_info.via->branch_param), pj_strlen(&event->body.rx_msg.rdata->msg_info.via->branch_param));
+    }
     
-    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
-    SipSessionPtr session = session_mod_info->getSessionPtr();
-
-    std::string branch(pj_strbuf(&event->body.rx_msg.rdata->msg_info.via->branch_param), pj_strlen(&event->body.rx_msg.rdata->msg_info.via->branch_param));
-    session->enqueueSessionWork(new InviteStateOperation(this, inv, event->type, inv->state, branch));
+    enqueueSessionWork(new InviteStateOperation(this, inv, event->type, inv->state, branch), inv);
 }
 
 void PJSipSessionModule::invOnNewSession(pjsip_inv_session*, pjsip_event*)
@@ -1310,7 +1344,7 @@ void PJSipSessionModule::invOnTsxStateChanged(pjsip_inv_session *inv, pjsip_tran
     PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo*>(inv->mod_data[mModule.id]);
     SipSessionPtr session = session_mod_info->getSessionPtr();
 
-    session->enqueueSessionWork(new TransactionStateOperation(this, tsx, inv, e->type, tsx->state));
+    enqueueSessionWork(new TransactionStateOperation(this, tsx, inv, e->type, tsx->state), inv);
 }
 
 /**
@@ -1449,9 +1483,7 @@ void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t st
         return;
     }
 
-    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*) inv->mod_data[mModule.id];
-    SipSessionPtr session = session_mod_info->getSessionPtr();
-    session->enqueueSessionWork(new HandleMediaUpdate(inv, mModule.id, mServiceLocator));
+    enqueueSessionWork(new HandleMediaUpdate(inv, mModule.id, mServiceLocator), inv);
 }
 
 pjsip_redirect_op PJSipSessionModule::invOnRedirected(pjsip_inv_session*, const pjsip_uri*,
@@ -1489,6 +1521,14 @@ QueuePtr PJSipSessionModule::getThreadPoolQueue()
     return mPoolQueue;
 }
 
+void PJSipSessionModule::enqueueSessionWork(const SuspendableWorkPtr& work, pjsip_inv_session *inv)
+{
+    PJSipSessionModInfo *session_mod_info =
+        static_cast<PJSipSessionModInfo*>(inv->mod_data[mModule.id]);
+    SessionWorkPtr sessionWork = session_mod_info->getSessionWork();
+    sessionWork->enqueueWork(work);
+}
+
 PJSipSessionModuleThreadPoolListener::PJSipSessionModuleThreadPoolListener()
     : mActiveThreads(0) { }
 
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 80c13cb..8e8a8e3 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -41,11 +41,12 @@ namespace SipSessionManager
 class PJSipSessionModInfo
 {
 public:
-    PJSipSessionModInfo(pjsip_inv_session *inv_session, const SipSessionPtr&);
+    PJSipSessionModInfo(pjsip_inv_session *inv_session, const SipSessionPtr&, const SessionWorkPtr&);
     ~PJSipSessionModInfo();
     void updateSessionState(pjsip_inv_session *inv_session);
     SipSessionPtr getSessionPtr();
     void setSessionPtr(const SipSessionPtr& sessionPtr);
+    SessionWorkPtr getSessionWork();
     SipSessionStateItemPtr mSessionState;
     SipInviteSessionStateItemPtr mInviteState;
     bool mNeedsReplication;
@@ -105,6 +106,9 @@ public:
     // Missing onsendack for now
     void replicateState(PJSipDialogModInfo *dlgInfo, PJSipTransactionModInfo *tsxInfo,
         PJSipSessionModInfo *sessionInfo);
+    void enqueueSessionWork(
+            const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkPtr&,
+            pjsip_inv_session *);
 
     AsteriskSCF::System::WorkQueue::V1::QueuePtr getThreadPoolQueue();
 private:
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index 3a84759..e066cd4 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -264,18 +264,16 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
         return 0;
     }
 
-    SessionWorkPtr sessionWork(new SessionWork(mImplPriv->mManager->getSessionModule()->getThreadPoolQueue()));
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, listener, mImplPriv->mManager,
-            mImplPriv->mServiceLocator, mImplPriv->mReplica, sessionWork);
+            mImplPriv->mServiceLocator, mImplPriv->mReplica);
     mImplPriv->mSessions.push_back(session);
     return session->getSessionProxy();
 }
 
 AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const std::string& destination)
 {
-    SessionWorkPtr sessionWork(new SessionWork(mImplPriv->mManager->getSessionModule()->getThreadPoolQueue()));
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, 0, mImplPriv->mManager,
-            mImplPriv->mServiceLocator, mImplPriv->mReplica, sessionWork);
+            mImplPriv->mServiceLocator, mImplPriv->mReplica);
     mImplPriv->mSessions.push_back(session);
     return session;
 }
@@ -285,9 +283,8 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
         const AsteriskSCF::Media::V1::SessionPrx& mediasession, const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
         const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
 {
-    SessionWorkPtr sessionWork(new SessionWork(mImplPriv->mManager->getSessionModule()->getThreadPoolQueue()));
     SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, mediaid, mediasession,
-            sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, sessionWork);
+            sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica);
     mImplPriv->mSessions.push_back(session);
     return session;
 }
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 307cb81..1d97045 100644
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -86,10 +86,9 @@ public:
     SipSessionPriv(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
         const std::string& destination, PJSipManager *manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
-        const SessionWorkPtr& sessionWork)
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica)
         : mAdapter(adapter), mDialog(0), mInviteSession(0), mEndpoint(endpoint), mDestination(destination),
-          mManager(manager), mServiceLocator(serviceLocator), mReplica(replica), mSessionWork(sessionWork) { };
+          mManager(manager), mServiceLocator(serviceLocator), mReplica(replica) { };
 
     AsteriskSCF::SessionCommunications::V1::SessionInfoPtr getInfo()
     {
@@ -238,8 +237,6 @@ public:
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
 
     AsteriskSCF::System::Component::V1::ReplicaPtr mReplica;
-
-    SessionWorkPtr mSessionWork;
 };
 
 /**
@@ -248,8 +245,8 @@ public:
 SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
         const std::string& destination,  const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
         PJSipManager *manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, const SessionWorkPtr& sessionWork)
-    : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, sessionWork))
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica)
+    : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica))
 {
     if (listener != 0)
     {
@@ -276,8 +273,8 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
         const Ice::Identity& mediaid, const AsteriskSCF::Media::V1::SessionPrx& mediasession,
         const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
         PJSipManager *manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, const SessionWorkPtr& sessionWork)
-    : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, sessionWork))
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica)
+    : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica))
 {
     mImplPriv->mSessionProxy =
         AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(adapter->add(this, sessionid));
@@ -653,8 +650,8 @@ void SipSession::removeListener(const AsteriskSCF::SessionCommunications::V1::Se
 class StartOperation : public SuspendableWork
 {
 public:
-    StartOperation(const SipSessionPtr& session, const boost::shared_ptr<SipSessionPriv>& sessionPriv)
-        : mSession(session), mImplPriv(sessionPriv) { }
+    StartOperation(const SipSessionPtr& session, const boost::shared_ptr<SipSessionPriv>& sessionPriv, PJSipSessionModInfo *session_mod_info)
+        : mSession(session), mImplPriv(sessionPriv), mSessionModInfo(session_mod_info) { }
 
     SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
     {
@@ -706,8 +703,7 @@ public:
         // Record our session within the dialog so code handling pjsip events can do STUFF
         SipSessionPtr session = new SipSession(*mSession);
 
-        PJSipSessionModInfo *session_mod_info = new PJSipSessionModInfo(inviteSession, session);
-        inviteSession->mod_data[mImplPriv->mManager->getSessionModule()->getModule().id] = (void*)session_mod_info;
+        inviteSession->mod_data[mImplPriv->mManager->getSessionModule()->getModule().id] = (void*)mSessionModInfo;
 
         // Create the actual INVITE packet
         pjsip_tx_data *packet;
@@ -729,6 +725,7 @@ public:
 
     SipSessionPtr mSession;
     boost::shared_ptr<SipSessionPriv> mImplPriv;
+    PJSipSessionModInfo *mSessionModInfo;
 };
 
 /**
@@ -737,7 +734,9 @@ public:
  */
 void SipSession::start(const Ice::Current&)
 {
-    enqueueSessionWork(new StartOperation(this, mImplPriv));
+    SessionWorkPtr sessionWork(new SessionWork(mImplPriv->mManager->getSessionModule()->getThreadPoolQueue()));
+    PJSipSessionModInfo *session_mod_info(new PJSipSessionModInfo(NULL, this, sessionWork));
+    enqueueSessionWork(new StartOperation(this, mImplPriv, session_mod_info));
 }
 
 class StopOperation : public SuspendableWork
@@ -1041,19 +1040,13 @@ bool SipSession::operator==(const SipSession &other) const {
     return (this->mImplPriv->mInviteSession == other.mImplPriv->mInviteSession);
 }
 
-SessionWorkPtr SipSession::getSessionWork()
-{
-    return mImplPriv->mSessionWork;
-}
-
-void SipSession::setSessionWork(const SessionWorkPtr& sessionWork)
-{
-    mImplPriv->mSessionWork = sessionWork;
-}
-
 void SipSession::enqueueSessionWork(const SuspendableWorkPtr& task)
 {
-    SessionWorkPtr sessionWork = getSessionWork();
+    PJSipSessionModInfo *session_mod_info =
+        static_cast<PJSipSessionModInfo*>(
+                mImplPriv->mInviteSession->mod_data[mImplPriv->mManager->getSessionModule()->getModule().id]);
+
+    SessionWorkPtr sessionWork = session_mod_info->getSessionWork();
 
     sessionWork->enqueueWork(task);
 }
diff --git a/src/SipSession.h b/src/SipSession.h
index e590f9f..02527d2 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -96,15 +96,13 @@ public:
     SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&,
         const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, PJSipManager *manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
-        const SessionWorkPtr& sessionWork);
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica);
 
     SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&,
         const Ice::Identity&, const AsteriskSCF::Media::V1::SessionPrx&,
         const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
         PJSipManager *manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
-        const SessionWorkPtr& sessionWork);
+        const AsteriskSCF::System::Component::V1::ReplicaPtr& replica);
 
     bool operator==(const SipSession &other) const;
 
@@ -198,10 +196,6 @@ public:
 
     AsteriskSCF::Media::V1::SessionPrx getHiddenMediaSession();
 
-    SessionWorkPtr getSessionWork();
-
-    void setSessionWork(const SessionWorkPtr& sessionWork);
-
     void enqueueSessionWork(const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkPtr&);
 private:
     void requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats);
diff --git a/src/SipStateReplicatorListener.cpp b/src/SipStateReplicatorListener.cpp
index 5cb7bb5..7774efe 100644
--- a/src/SipStateReplicatorListener.cpp
+++ b/src/SipStateReplicatorListener.cpp
@@ -198,8 +198,9 @@ public:
                     }
                     localInviteSession->role = localDialog->role;
 
+                    SessionWorkPtr sessionWork(new SessionWork(mManager->getSessionModule()->getThreadPoolQueue()));
                     PJSipSessionModInfo *session_mod_info = new PJSipSessionModInfo(localInviteSession,
-                            i->second->getSession());
+                            i->second->getSession(), sessionWork);
                     localInviteSession->mod_data[mManager->getSessionModule()->getModule().id] = session_mod_info;
 
                     i->second->getSession()->setInviteSession(localInviteSession);

commit 0c327d8e8c59536fda95b1e07f0c54f31b825fdd
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 15:24:44 2011 -0500

    Remove another unused class.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 27c97f6..9f1a346 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -59,49 +59,6 @@ using namespace AsteriskSCF::System::WorkQueue::V1;
 using namespace AsteriskSCF::WorkQueue;
 using namespace AsteriskSCF::Core::Discovery::V1;
 
-class RouteSessionCallback : public IceUtil::Shared
-{
-public:
-    RouteSessionCallback(pjsip_inv_session *inv_session, 
-                         pjsip_tx_data *tdata,
-                         const SipSessionPtr& session,
-                         const std::string& destination,
-                         const std::string& operationId)
-        : mInvSession(inv_session), 
-          mTdata(tdata),
-          mSession(session),
-          mDestination(destination),
-          mOperationId(operationId)
-    { 
-    }
-
-    void callback(const Ice::AsyncResultPtr& r)
-    {
-        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(r->getProxy());
-        try
-        {
-            router->end_routeSession(r);
-        }
-        catch (const DestinationNotFoundException &)
-        {
-            pjsip_inv_end_session(mInvSession, 404, NULL, &mTdata);
-            pjsip_inv_send_msg(mInvSession, mTdata);
-        }
-        catch (...)
-        {
-            pjsip_inv_end_session(mInvSession, 500, NULL, &mTdata);
-            pjsip_inv_send_msg(mInvSession, mTdata);
-        }
-    }
-private:
-    pjsip_inv_session *mInvSession;
-    pjsip_tx_data *mTdata;
-    SipSessionPtr mSession;
-    std::string mDestination;
-    std::string mOperationId;
-};
-typedef IceUtil::Handle<RouteSessionCallback> RouteSessionCallbackPtr;
-
 PJSipSessionModInfo::PJSipSessionModInfo(pjsip_inv_session *inv_session,
     const SipSessionPtr& session) :
     mSessionState(new SipSessionStateItem),

commit d64b6e6f37ba0048fd66948ae6caf0864af1b3a7
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 15:06:46 2011 -0500

    Fix up some more minor problems.
    
    The issue now is that I am going to have to redo the allocation
    strategy for the session work because I'm encountering crashes during
    phone calls because I'm trying to queue work onto a non-existent
    session work.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index f01380c..27c97f6 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -356,7 +356,7 @@ pj_status_t PJSipSessionModule::unload()
     return PJ_SUCCESS;
 }
 
-class SessionCreationOperation : public SipQueueableOperation
+class SessionCreationOperation : public SipQueueableOperation, public Work
 {
 public:
     SessionCreationOperation(
@@ -510,9 +510,6 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
         lg(Warning) << "Unable to create UAS dialog on incoming INVITE";
         return;
     }
-
-    PJSipDialogModInfo *dlg_mod_info = new PJSipDialogModInfo(dlg);
-
     pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
     PJSipTransactionModInfo *tsx_mod_info = new PJSipTransactionModInfo(tsx);
     tsx->mod_data[mModule.id] = (void *)tsx_mod_info;
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 11e6ae3..80c13cb 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -129,11 +129,8 @@ typedef IceUtil::Handle<PJSipSessionModule> PJSipSessionModulePtr;
 
 /**
  * Operation that may be queued.
- *
- * This inherits from both Work and Suspendable work so that it may
- * be enqueued in either a WorkQueue or SuspendableWorkQueue.
  */
-class SipQueueableOperation : virtual public AsteriskSCF::System::WorkQueue::V1::Work, virtual public AsteriskSCF::System::WorkQueue::V1::SuspendableWork
+class SipQueueableOperation : virtual public AsteriskSCF::System::WorkQueue::V1::SuspendableWork
 {
 public:
     virtual ~SipQueueableOperation() { };
@@ -146,10 +143,6 @@ public:
      */
     void setAsyncResult(const Ice::AsyncResultPtr& r) {mAsyncResult = r;}
     /**
-     * Override of Work::execute()
-     */
-    virtual void execute() { }
-    /**
      * Override of SuspendableWorkExecute()
      */
     virtual AsteriskSCF::System::WorkQueue::V1::SuspendableWorkResult execute(const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr&)

commit 847e828ad8e207d2d16cbf6ade1b7004fb2426f2
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 13:43:47 2011 -0500

    Make some fixes that were detected while doing some testing.

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 202b875..485b403 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -46,7 +46,7 @@ asterisk_scf_component_add_slice(SipSessionManager ../local-slice/SipConfigurati
 asterisk_scf_component_add_ice_libraries(SipSessionManager IceStorm)
 asterisk_scf_component_add_boost_libraries(SipSessionManager core)
 asterisk_scf_component_build_icebox(SipSessionManager)
-target_link_libraries(SipSessionManager logging-client ${OPENSSL_LIBRARIES})
+target_link_libraries(SipSessionManager logging-client ice-util-cpp ${OPENSSL_LIBRARIES})
 pjproject_link(SipSessionManager pjsip)
 pjproject_link(SipSessionManager pjmedia)
 pjproject_link(SipSessionManager pjlib-util)
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index db70dab..f01380c 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -604,53 +604,6 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     //yet been created. Instead, we just queue an operation onto the thread pool's queue directly.
 
     mPoolQueue->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
-    
-    SipSessionPtr session;
-    try
-    {
-        session = caller->createSession(destination);
-    }
-    catch (const Ice::Exception& ex)
-    {
-        lg(Error) << "Exception caught while trying to create SIP session\n" << ex.what();
-        pjsip_inv_end_session(inv_session, 500, NULL, &tdata);
-        pjsip_inv_send_msg(inv_session, tdata);
-        return;
-    }
-    session->setInviteSession(inv_session);
-    session->setDialog(dlg);
-    PJSipSessionModInfo *session_mod_info = new PJSipSessionModInfo(inv_session, session);
-    dlg_mod_info->mDialogState->mSessionId = session_mod_info->mSessionState->mSessionId;
-    tsx_mod_info->mTransactionState->mSessionId = session_mod_info->mSessionState->mSessionId;
-
-    inv_session->mod_data[mModule.id] = (void *)session_mod_info;
-    dlg->mod_data[mModule.id] = (void *)dlg_mod_info;
-
-    lg(Debug) << "Replicating state on reception of new SIP INVITE.";
-    replicateState(dlg_mod_info, tsx_mod_info, session_mod_info);
-    try
-    {
-        if (replaced_dlg)
-        {
-            // For attended transfers we need to contact the routing service which should then (hopefully) replace the
-            // other session
-        }
-        else
-        {
-            // If this is not an attended transfer we can just route the session as normally
-            std::string operationId = ::IceUtil::generateUUID();
-            RouteSessionCallbackPtr cb = new RouteSessionCallback(inv_session, tdata, session, destination, operationId);
-            Ice::CallbackPtr d = Ice::newCallback(cb, &RouteSessionCallback::callback);
-            mSessionRouter->begin_routeSession(operationId, session->getSessionProxy(), destination, d);
-        }
-    }
-    catch (const Ice::CommunicatorDestroyedException &)
-    {
-        // Everything else doesn't really map so they just become internal server errors
-        pjsip_inv_end_session(inv_session, 500, NULL, &tdata);
-        pjsip_inv_send_msg(inv_session, tdata);
-        return;
-    }
 }
 
 class HandleReferOperation : public SipQueueableOperation 
@@ -1602,6 +1555,8 @@ void PJSipSessionModuleThreadPoolListener::queueWorkAdded(const PoolPtr& pool, I
     //XXX Making this behavior more customizable would be nice
     //
     //For now, use one thread per work item.
+
+    lg(Debug) << "Detected the addition of work to SIP's thread pool";
     int newSize = (int) (mActiveThreads + numNewWork);
     pool->setSize(newSize);
 }
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index b8b5748..11e6ae3 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -136,7 +136,7 @@ typedef IceUtil::Handle<PJSipSessionModule> PJSipSessionModulePtr;
 class SipQueueableOperation : virtual public AsteriskSCF::System::WorkQueue::V1::Work, virtual public AsteriskSCF::System::WorkQueue::V1::SuspendableWork
 {
 public:
-    virtual ~SipQueueableOperation();
+    virtual ~SipQueueableOperation() { };
     /**
      * Queueable operations may call out to AMI methods. AMI callbacks happen
      * in Ice client threads. We want to process the result of the AMI call in one
@@ -158,7 +158,7 @@ public:
     }
 protected:
     Ice::AsyncResultPtr mAsyncResult;
-    SipQueueableOperation();
+    SipQueueableOperation() { }
 };
 
 typedef IceUtil::Handle<SipQueueableOperation> SipQueueableOperationPtr;

commit 7d0b2a500d2e8867bc3fe8db177e2f968d97a849
Merge: 623654b a4f034d
Author: Mark Michelson <mmichelson at digium.com>
Date:   Tue May 17 11:01:50 2011 -0500

    Merge branch 'master' into threading
    
    Conflicts:
    	src/CMakeLists.txt
    	src/PJSipSessionModule.cpp

diff --cc src/PJSipSessionModule.cpp
index e8acc3e,c71e656..db70dab
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@@ -30,6 -21,14 +21,16 @@@
  #include "PJSipManager.h"
  #include "SipStateReplicator.h"
  
+ #include <IceUtil/UUID.h>
+ 
+ #include <AsteriskSCF/Core/Endpoint/EndpointIf.h>
+ #include <AsteriskSCF/Core/Routing/RoutingIf.h>
+ #include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+ #include <AsteriskSCF/Media/MediaIf.h>
+ #include <AsteriskSCF/logger.h>
++#include <AsteriskSCF/WorkQueue/WorkQueue.h>
++#include <AsteriskSCF/WorkQueue/SuspendableWorkQueue.h>
+ 
  using namespace AsteriskSCF::System::Logging;
  
  namespace
@@@ -53,11 -52,6 +54,10 @@@ using namespace AsteriskSCF::Core::Endp
  using namespace AsteriskSCF::SessionCommunications::V1;
  using namespace AsteriskSCF::Media::V1;
  using namespace AsteriskSCF::SIP::V1;
 +using namespace AsteriskSCF::System::ThreadPool::V1;
 +using namespace AsteriskSCF::System::WorkQueue::V1;
 +using namespace AsteriskSCF::WorkQueue;
- using namespace AsteriskSCF::SmartProxy;
 +using namespace AsteriskSCF::Core::Discovery::V1;
  
  class RouteSessionCallback : public IceUtil::Shared
  {
@@@ -356,100 -473,6 +356,100 @@@ pj_status_t PJSipSessionModule::unload(
      return PJ_SUCCESS;
  }
  
 +class SessionCreationOperation : public SipQueueableOperation
 +{
 +public:
 +    SessionCreationOperation(
 +            const PJSipSessionModulePtr& module,
 +            const SipEndpointPtr& caller,
-             const AsteriskSCF::SmartProxy::SmartProxy<SessionRouterPrx>& router,
++            const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& router,
 +            pjsip_inv_session *inv,
 +            pjsip_tx_data *tdata,
 +            pjsip_dialog *replacedDialog,
 +            const std::string destination)
 +        : mSessionModule(module), mCaller(caller), mSessionRouter(router), mInv(inv), mTdata(tdata), mReplacedDialog(replacedDialog), mDestination(destination) { }
 +
 +    void execute()
 +    {
 +        try
 +        {
 +            mSession = mCaller->createSession(mDestination);
 +        }
 +        catch (const Ice::Exception& ex)
 +        {
 +            lg(Error) << "Exception caught while trying to create SIP session\n" << ex.what();
 +            pjsip_inv_end_session(mInv, 500, NULL, &mTdata);
 +            pjsip_inv_send_msg(mInv, mTdata);
 +            return;
 +        }
 +        mSession->setInviteSession(mInv);
 +        mSession->setDialog(mInv->dlg);
 +        PJSipSessionModInfo *session_mod_info = new PJSipSessionModInfo(mInv, mSession);
 +        PJSipDialogModInfo *dlg_mod_info = new PJSipDialogModInfo(mInv->dlg);
 +        PJSipTransactionModInfo *tsx_mod_info = new PJSipTransactionModInfo(mInv->invite_tsx);
 +        dlg_mod_info->mDialogState->mSessionId = session_mod_info->mSessionState->mSessionId;
 +        tsx_mod_info->mTransactionState->mSessionId = session_mod_info->mSessionState->mSessionId;
 +    
 +        mInv->mod_data[mSessionModule->getModule().id] = (void *)session_mod_info;
 +        mInv->dlg->mod_data[mSessionModule->getModule().id] = (void *)dlg_mod_info;
 +    
 +        lg(Debug) << "Replicating state on reception of new SIP INVITE.";
 +        mSessionModule->replicateState(dlg_mod_info, tsx_mod_info, session_mod_info);
 +        try
 +        {
 +            if (mReplacedDialog)
 +            {
 +                // For attended transfers we need to contact the routing service which should then (hopefully) replace the
 +                // other session
 +            }
 +            else
 +            {
 +                // If this is not an attended transfer we can just route the session as normally
 +                std::string operationId = ::IceUtil::generateUUID();
 +                SuspendableWorkListenerPtr listener = 0;
 +                SipAMICallbackPtr cb(new SipAMICallback(listener, mSession, this, false, true));
 +                Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
 +                mSessionRouter->begin_routeSession(operationId, mSession->getSessionProxy(), mDestination, d);
 +            }
 +        }
 +        catch (const Ice::CommunicatorDestroyedException &)
 +        {
 +            // Everything else doesn't really map so they just become internal server errors
 +            pjsip_inv_end_session(mInv, 500, NULL, &mTdata);
 +            pjsip_inv_send_msg(mInv, mTdata);
 +        }
 +    }
 +
 +    SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
 +    {
 +        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
 +        try
 +        {
 +            router->end_routeSession(mAsyncResult);
 +        }
 +        catch (const DestinationNotFoundException &)
 +        {
 +            pjsip_inv_end_session(mInv, 404, NULL, &mTdata);
 +            pjsip_inv_send_msg(mInv, mTdata);
 +        }
 +        catch (...)
 +        {
 +            pjsip_inv_end_session(mInv, 500, NULL, &mTdata);
 +            pjsip_inv_send_msg(mInv, mTdata);
 +        }
 +        return Complete;
 +    }
 +
 +    PJSipSessionModulePtr mSessionModule;
 +    SipEndpointPtr mCaller;
-     AsteriskSCF::SmartProxy::SmartProxy<SessionRouterPrx> mSessionRouter;
++    AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> mSessionRouter;
 +    pjsip_inv_session *mInv;
 +    pjsip_tx_data *mTdata;
 +    pjsip_dialog *mReplacedDialog;
 +    const std::string mDestination;
 +    SipSessionPtr mSession;
 +};
 +
  void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
  {
      //What do we do here?
@@@ -653,329 -654,176 +653,329 @@@
      }
  }
  
 -void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 +class HandleReferOperation : public SipQueueableOperation 
  {
 -    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 AsteriskSCF::SmartProxy::SmartProxy<SessionRouterPrx>& sessionRouter,
++            const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& sessionRouter,
 +            const int moduleId)
 +        : mState(Initial), mInv(inv), mTsx(tsx), mTdata(tdata), 
 +        mTargetSipUri(target_sip_uri), mSession(session), mSessionRouter(sessionRouter),
 +        mModuleId(moduleId), mWasWithDestination(false) { }
 +
 +    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...";
 +            return Complete;
 +        }
      }
  
 -    // TODO: Add support for subscription
 -
 -    // TODO: Provide method to send back suitable response
 +    /**
 +     * This is what is initially called when the operation is queued.
 +     *
 +     * In this portion, we grab some essential data out of the target URI and use
 +     * it to call out to the routing service, either ConnectBridgedSessions or
 +     * ConnectBridgedSessionWithDestination.
 +     *
 +     * When this operation is successful, it will result in work for this session
 +     * being suspended until the routing service returns.
 +     */
 +    SuspendableWorkResult processRefer(const SuspendableWorkListenerPtr& workListener)
 +    {
 +        // 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);
  
 -    // 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));
 +        if (!replaces_param)
 +        {
 +            replaces_param = pjsip_param_find(&mTargetSipUri->header_param, &replaces);
 +        }
  
 -    // 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;
 -    }
 +        if (replaces_param)
 +        {
 +            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;
  
 -    pjsip_sip_uri *target_sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(target_uri);
 +            if (to_tag_param && from_tag_param)
 +            {
 +                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;
 +                }
  
 -    // 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);
 +                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);
  
 -    if (!replaces_param)
 -    {
 -        replaces_param = pjsip_param_find(&target_sip_uri->header_param, &replaces);
 -    }
 +                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 (replaces_param)
 -    {
 -        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;
 +                other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
 +            }
  
 -        if (to_tag_param && from_tag_param)
 -        {
 -            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)
 +            if (!other_dlg)
              {
 -                lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
 -                pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
 -                return;
 +                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;
              }
  
 -            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);
 +            pjsip_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
  
 -            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_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;
 +            }
  
 -            other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
 -        }
 +            if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
 +            {
 +                lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
  
 -        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;
 -        }
 +                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_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
 +            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. ";
  
 -        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_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;
 +            }
  
 -        if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
 -        {
 -            lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
 +            PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModuleId];
 +            SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
  
 -            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_DECLINE, NULL, NULL, NULL);
 -            pjsip_dlg_dec_lock(other_dlg);
 -            return;
 +            try
 +            {
 +                std::string operationId = ::IceUtil::generateUUID();
 +                SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
 +                Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
 +
 +                lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
 +                mState = CalledBack;
 +                mSessionRouter->begin_connectBridgedSessions(operationId, mSession->getSessionProxy(), other_session->getSessionProxy(), d);
 +                pjsip_dlg_dec_lock(other_dlg);
 +                return Complete;
 +            }
 +            catch (const Ice::CommunicatorDestroyedException &)
 +            {
 +                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
 +                pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
 +                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
 +                pjsip_dlg_dec_lock(other_dlg);
 +                return Complete;
 +            }
          }
 -
 -        if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
 +        else
          {
 -            lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
 +            std::string target = std::string(pj_strbuf(&mTargetSipUri->user), pj_strlen(&mTargetSipUri->user));
  
 -            pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
 -            pjsip_dlg_dec_lock(other_dlg);
 -            return;
 +            // 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[mModuleId];
 +                SipSessionPtr session = session_mod_info->getSessionPtr();
 +                SipAMICallbackPtr cb(new SipAMICallback(workListener, mSession, this, false, true));
 +                Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
 +
 +                lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
 +                mWasWithDestination = true;
 +                mState = CalledBack;
 +                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), target, d);
 +                return Complete;
 +            }
 +            catch (const Ice::CommunicatorDestroyedException &)
 +            {
 +                lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
 +                pjsip_dlg_modify_response(mInv->dlg, mTdata, 503, NULL);
 +                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
 +                return Complete;
 +            }
          }
 +    };
  
 -        PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
 -        SipSessionPtr session = session_mod_info->getSessionPtr();
 -
 -        PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModule.id];
 -        SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
 -
 +    /**
 +     * Once the routing service has allowed for work to be resumed,
 +     * this is where the final work is done
 +     */
 +    SuspendableWorkResult processRoutingResponse(const SuspendableWorkListenerPtr&)
 +    {
 +        assert(mAsyncResult);
 +        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(mAsyncResult->getProxy());
          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);
 +            if (mWasWithDestination)
 +            {
 +                router->end_connectBridgedSessionsWithDestination(mAsyncResult);
 +            }
 +            else
 +            {
 +                router->end_connectBridgedSessions(mAsyncResult);
 +            }
 +        }
 +        catch (const AsteriskSCF::Core::Routing::V1::DestinationNotFoundException &)
 +        {
 +            lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
  
 -            lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
 -            mSessionRouter->begin_connectBridgedSessions(operationId, session->getSessionProxy(), other_session->getSessionProxy(), d);
 +            pjsip_dlg_modify_response(mInv->dlg, mTdata, 404, NULL);
 +            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
 +            return Complete;
          }
 -        catch (const Ice::CommunicatorDestroyedException &)
 +        catch (const std::exception &e)
          {
 -            lg(Debug) << "handleRefer() sending 503 due to communicator destruction";
 -            pjsip_dlg_respond(inv->dlg, rdata, 503, NULL, NULL, NULL);
 -            return;
 +            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 Complete;
          }
 -        pjsip_dlg_dec_lock(other_dlg);
 +        pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
 +        
 +        Ice::Current current;
 +        lg(Debug) << "ConnectBridgedSessionsCallback calling session->stop(). ";
 +        mSession->stop(new ResponseCode(16), current);
 +        return Complete;
      }
 -    else
 +
 +    enum states
      {
 -        std::string target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
 +        /**
 +         * First state.
 +         * @see processRefer
 +         */
 +        Initial,
 +        /**
 +         * State after routing service completes
 +         * @see processRoutingResponse
 +         */
 +        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
 +     */
-     AsteriskSCF::SmartProxy::SmartProxy<SessionRouterPrx> mSessionRouter;
++    AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> mSessionRouter;
 +    /**
 +     * The identifier of the PJSipSessionModule. Used for retrieving module data from mInv
 +     */
 +    const int mModuleId;
 +    /**
 +     * Helps determine which end_* method to call on the session router when AMI completes.
 +     * XXX It may be more elegant to handle this by sending a cookie to the AMI method
 +     * instead.
 +     */
 +    bool mWasWithDestination;
 +};
  
 -        // 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, mModule.id));
  }
  
  pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
diff --cc src/PJSipSessionModule.h
index b2be3be,32a0e6e..b8b5748
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@@ -23,10 -23,8 +23,10 @@@
  #include <boost/thread.hpp>
  #include <boost/thread/shared_mutex.hpp>
  
- #include <AsteriskSCF/SmartProxy.h>
+ #include <AsteriskSCF/Discovery/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"
@@@ -115,114 -91,12 +115,114 @@@ private
      pjsip_ua_init_param mUaParam;
      const std::string mName;
      boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
-     AsteriskSCF::SmartProxy::SmartProxy<AsteriskSCF::SessionCommunications::V1::SessionRouterPrx> mSessionRouter;
+     AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SessionCommunications::V1::SessionRouterPrx> mSessionRouter;
      AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
-     AsteriskSCF::SmartProxy::SmartProxy<AsteriskSCF::SIP::V1::SipStateReplicatorPrx> mStateReplicator;
+     AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SIP::V1::SipStateReplicatorPrx> mStateReplicator;
      AsteriskSCF::System::Component::V1::ReplicaPtr mReplica;
      pjsip_endpoint *mEndpoint;
 +    AsteriskSCF::System::ThreadPool::V1::PoolPtr mPool;
 +    AsteriskSCF::System::WorkQueue::V1::QueuePtr mPoolQueue;
 +    AsteriskSCF::System::ThreadPool::V1::PoolListenerPtr mPoolListener;
 +};
 +
 +typedef IceUtil::Handle<PJSipSessionModule> PJSipSessionModulePtr;
 +
 +/**
 + * Operation that may be queued.
 + *
 + * This inherits from both Work and Suspendable work so that it may
 + * be enqueued in either a WorkQueue or SuspendableWorkQueue.
 + */
 +class SipQueueableOperation : virtual public AsteriskSCF::System::WorkQueue::V1::Work, virtual public AsteriskSCF::System::WorkQueue::V1::SuspendableWork
 +{
 +public:
 +    virtual ~SipQueueableOperation();
 +    /**
 +     * Queueable operations may call out to AMI methods. AMI callbacks happen
 +     * in Ice client threads. We want to process the result of the AMI call in one
 +     * of our thread pool's threads, though. The AMI callback can set the operation's
 +     * AsyncResult so that the operation will be able to actually do something with
 +     * the AMI call's result.
 +     */
 +    void setAsyncResult(const Ice::AsyncResultPtr& r) {mAsyncResult = r;}
 +    /**
 +     * Override of Work::execute()
 +     */
 +    virtual void execute() { }
 +    /**
 +     * Override of SuspendableWorkExecute()
 +     */
 +    virtual AsteriskSCF::System::WorkQueue::V1::SuspendableWorkResult execute(const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr&)
 +    {
 +        return AsteriskSCF::System::WorkQueue::V1::Complete;
 +    }
 +protected:
 +    Ice::AsyncResultPtr mAsyncResult;
 +    SipQueueableOperation();
  };
  
 +typedef IceUtil::Handle<SipQueueableOperation> SipQueueableOperationPtr;
 +
 +class SipAMICallback : public IceUtil::Shared
 +{
 +public:
 +    SipAMICallback(
 +            const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr& listener,
 +            const SipSessionPtr& session,
 +            const SipQueueableOperationPtr& operation,
 +            bool isSuspended,
 +            bool needsRequeuing)
 +        : mListener(listener), mSession(session), mOperation(operation),
 +        mIsSuspended(isSuspended), mNeedsRequeuing(needsRequeuing)
 +    {
 +    }
 +
 +    void callback(const Ice::AsyncResultPtr &r)
 +    {
 +        mOperation->setAsyncResult(r);
 +        if (mIsSuspended)
 +        {
 +            mListener->workResumable();
 +        }
 +        else if (mNeedsRequeuing)
 +        {
 +            mSession->enqueueSessionWork(mOperation);
 +        }
 +    }
 +
 +private:
 +    /**
 +     * In some cases, when an AMI RPC is made, operation on a SIP session is
 +     * suspended pending the AMI's return. The AMI callback uses the listener
 +     * to notify that work may be resumed.
 +     */
 +    AsteriskSCF::System::WorkQueue::V1::SuspendableWorkListenerPtr mListener;
 +    /**
 +     * In other cases, when an AMI RPC is made, the operation on the SIP
 +     * session is not marked as "Suspended" since it's perfectly fine
 +     * for other operations to intervene as necessary. However, the operation
 +     * has multiple parts and thus needs to be requeued once the AMI RPC
 +     * returns. The AMI callback uses the session in order to enqueue the
 +     * operation again.
 +     */
 +    SipSessionPtr mSession;
 +    /**
 +     * The queued operation that made an AMI call
 +     */
 +    SipQueueableOperationPtr mOperation;
 +    /**
 +     * Use this to determine if we need to notify the listener that
 +     * work may be resumed.
 +     */
 +    bool mIsSuspended;
 +    /**
 +     * Use this to determine if we need to requeue the operation. This
 +     * and mIsSuspended should never both be true.
 +     */
 +    bool mNeedsRequeuing;
 +};
 +
 +typedef IceUtil::Handle<SipAMICallback> SipAMICallbackPtr;
 +
  }; //end namespace SipSessionManager
  }; //end namespace AsteriskSCF
diff --cc src/PJSipSessionModuleConstruction.cpp
index fb6d6b2,b6aace3..14e0718
--- a/src/PJSipSessionModuleConstruction.cpp
+++ b/src/PJSipSessionModuleConstruction.cpp
@@@ -14,9 -14,6 +14,9 @@@
   * at the top of the source tree.
   */
  
- #include <AsteriskSCF/WorkQueue.h>
- #include <AsteriskSCF/ThreadPool.h>
++#include <AsteriskSCF/WorkQueue/WorkQueue.h>
++#include <AsteriskSCF/ThreadPool/ThreadPool.h>
 +
  #include "PJSipSessionModule.h"
  
  namespace AsteriskSCF
diff --cc src/SipSession.cpp
index eb7a450,2b36d1f..307cb81
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@@ -20,14 -25,8 +25,9 @@@
  #include <boost/thread.hpp>
  #include <boost/thread/shared_mutex.hpp>
  
 +#include <AsteriskSCF/System/WorkQueue/WorkQueueIf.h>
  #include <AsteriskSCF/logger.h>
  
- #include "PJSipManager.h"
- #include "SipEndpointFactory.h"
- #include "SipEndpoint.h"
- #include "SipSession.h"
- 
  using namespace AsteriskSCF::System::Logging;
  
  namespace

commit a4f034dcfb22c527a701dc32eb24df15faf38622
Author: Joshua Colp <jcolp at digium.com>
Date:   Tue May 17 11:21:31 2011 -0300

    Do not bind to 0.0.0.0 port 5060 by default if nothing is specified in the Ice config.

diff --git a/src/PJSipManager.cpp b/src/PJSipManager.cpp
index 35a5c12..f87a9cd 100644
--- a/src/PJSipManager.cpp
+++ b/src/PJSipManager.cpp
@@ -106,7 +106,13 @@ bool PJSipManager::setTransports(pjsip_endpoint *endpoint, const Ice::Properties
     //addresses to be specified.
     pj_sockaddr udpAddr;
     pj_status_t status;
-    std::string udpBindAddr = props->getPropertyWithDefault("Sip.Transport.UdpBindAddr", "0.0.0.0:5060");
+    std::string udpBindAddr = props->getProperty("Sip.Transport.UdpBindAddr");
+
+    if (udpBindAddr.empty())
+    {
+	return true;
+    }
+
     pj_str_t udpString;
     pj_cstr(&udpString, udpBindAddr.c_str());
     //UNSPEC family means "you figure out the address family, pjlib!"

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


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list