[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "queue-shutdown" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Jun 6 16:50:43 CDT 2011


branch "queue-shutdown" has been created
        at  c75f3b9b6d21058d881faf51736b4221522cc7d3 (commit)

- Log -----------------------------------------------------------------
commit c75f3b9b6d21058d881faf51736b4221522cc7d3
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jun 6 16:49:56 2011 -0500

    Adding appropriate parameters to QueueListeners.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 429f0bb..aeb6d24 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -1598,7 +1598,7 @@ public:
 
     void workResumable()
     {
-        mQueueListener->workResumable();
+        mQueueListener->workResumable(0);
     }
 
 private:
@@ -1609,7 +1609,7 @@ SessionWork::SessionWork(const QueuePtr& queue)
     : mThreadPoolQueue(queue),
     mInternalQueue(new SuspendableWorkQueue(this)) { }
 
-void SessionWork::workAdded(Ice::Long, bool wasEmpty)
+void SessionWork::workAdded(const QueueBasePtr&, Ice::Long, bool wasEmpty)
 {
     if (wasEmpty)
     {
@@ -1624,7 +1624,7 @@ void SessionWork::workAdded(Ice::Long, bool wasEmpty)
     }
 }
 
-void SessionWork::workResumable()
+void SessionWork::workResumable(const QueueBasePtr&)
 {
     try
     {
@@ -1636,13 +1636,13 @@ void SessionWork::workResumable()
     }
 }
 
-void SessionWork::emptied()
+void SessionWork::emptied(const QueueBasePtr&)
 {
     //Empty on purpose. Nothing special
     //to do here.
 }
 
-void SessionWork::shuttingDown()
+void SessionWork::shuttingDown(const QueueBasePtr&)
 {
 }
 
diff --git a/src/PJSipSessionModule.cpp.orig b/src/PJSipSessionModule.cpp.orig
new file mode 100644
index 0000000..32ed923
--- /dev/null
+++ b/src/PJSipSessionModule.cpp.orig
@@ -0,0 +1,1355 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+#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.h>
+#include <AsteriskSCF/SuspendableWorkQueue.h>
+
+#include "PJSipSessionModule.h"
+#include "SipEndpoint.h"
+#include "SipEndpointFactory.h"
+#include "SipSession.h"
+#include "PJSipManager.h"
+#include "SipStateReplicator.h"
+
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.SipSessionManager");
+//Constants used for AMI callback class construction when calling
+//SessionListenerPrx methods.
+const std::string RingingCallbackName("ringing");
+const std::string ProgressingCallbackName("progressing");
+const std::string ConnectedCallbackName("connected");
+}
+
+namespace AsteriskSCF
+{
+
+namespace SipSessionManager
+{
+
+using namespace AsteriskSCF::Core::Routing::V1;
+using namespace AsteriskSCF::Core::Endpoint::V1;
+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;
+
+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;
+
+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
+{
+public:
+    ConnectBridgedSessionsWithDestinationCallback(pjsip_inv_session *inv_session, 
+                                                  pjsip_tx_data *tdata, 
+                                                  pjsip_transaction *tsx,
+                                                  SipSessionPtr session, 
+                                                  const std::string& target,
+                                                  const std::string& operationId)
+        : mInvSession(inv_session), 
+          mTData(tdata), 
+          mTsx(tsx),
+          mSession(session), 
+          mTarget(target),
+          mOperationId(operationId)
+    { 
+    }
+
+    void callback(const Ice::AsyncResultPtr &r)
+    {
+        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(r->getProxy());
+        try
+        {
+            router->end_connectBridgedSessions(r);
+        }
+        catch (const AsteriskSCF::Core::Routing::V1::DestinationNotFoundException &)
+        {
+            lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found for target: "
+                      << mTarget;
+
+            pjsip_dlg_modify_response(mInvSession->dlg, mTData, 400, NULL);
+            pjsip_dlg_send_response(mInvSession->dlg, mTsx, mTData);
+            return;
+        }
+        catch (const std::exception &e)
+        {
+            lg(Debug) << "ConnectBridgedSessionsWithDestination 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) << "ConnectBridgedSessionsWithDestination calling session->stop(). ";
+        mSession->stop(new ResponseCode(16), current);
+    }
+private:
+    pjsip_inv_session *mInvSession;
+    pjsip_tx_data *mTData;
+    pjsip_transaction *mTsx;
+    SipSessionPtr mSession;
+    std::string mTarget;
+    std::string mOperationId;
+};
+
+typedef IceUtil::Handle<ConnectBridgedSessionsWithDestinationCallback> ConnectBridgedSessionsWithDestinationCallbackPtr;
+
+class ListenerCallback : public IceUtil::Shared
+{
+public:
+    ListenerCallback(const std::string& name) : mCallbackName(name) {}
+    void failure(const Ice::Exception& ex)
+    {
+        lg(Error) << "Ice exception when attempting to relate " << mCallbackName << " state: " << ex.what();
+    }
+private:
+    const std::string mCallbackName;
+};
+
+typedef IceUtil::Handle<ListenerCallback> ListenerCallbackPtr;
+
+PJSipSessionModInfo::PJSipSessionModInfo(pjsip_inv_session *inv_session,
+    const SipSessionPtr& session) :
+    mSessionState(new SipSessionStateItem),
+    mInviteState(new SipInviteSessionStateItem),
+    mNeedsReplication(true),
+    mNeedsRemoval(false),
+    mSession(session)
+{
+    mSessionState->key = IceUtil::generateUUID();
+    mInviteState->key = IceUtil::generateUUID();
+    mSessionState->mSessionId = mSessionState->key;
+    mInviteState->mSessionId = mSessionState->key;
+    updateSessionState(inv_session);
+}
+
+PJSipSessionModInfo::~PJSipSessionModInfo()
+{
+    if (mSession)
+    {
+        mSession->destroy();
+        mSession = 0;
+    }
+}
+
+void PJSipSessionModInfo::updateSessionState(pjsip_inv_session *inv_session)
+{
+    boost::unique_lock<boost::shared_mutex> lock(mLock);
+    if (mSession)
+    {
+        mSessionState->mEndpointName = mSession->getEndpoint()->getName();
+        mSessionState->mSessionObjectId = mSession->getSessionProxy()->ice_getIdentity();
+        mSessionState->mMediaSessionObjectId = mSession->getMediaSessionProxy()->ice_getIdentity();
+        mSessionState->mSources = mSession->getSources();
+        mSessionState->mSinks = mSession->getSinks();
+        mSessionState->mMediaSession = mSession->getHiddenMediaSession();
+        mSessionState->mListeners = mSession->getListeners();
+        try
+        {
+            mSessionState->mBridge = mSession->getBridge();
+        }
+        catch (...)
+        {
+            mSessionState->mBridge = 0;
+        }
+    }
+
+    //Now we get stuff from the inv_session itself.
+    mInviteState->mCancelling = inv_session->cancelling == PJ_TRUE ? true : false;
+    mInviteState->mPendingCancel = inv_session->pending_cancel == PJ_TRUE ? true : false;
+    mInviteState->mCause = inv_session->cause;
+    mInviteState->mCauseText = std::string(pj_strbuf(&inv_session->cause_text), pj_strlen(&inv_session->cause_text));
+    mInviteState->mNotify = inv_session->notify == PJ_TRUE ? true : false;
+    mInviteState->mLastAckCseq = inv_session->last_ack_cseq;
+    mInviteState->mCurrentState = inviteStateTranslate(inv_session->state);
+    mNeedsReplication = true;
+}
+
+SipSessionPtr PJSipSessionModInfo::getSessionPtr()
+{
+    return mSession;
+}
+
+void PJSipSessionModInfo::setSessionPtr(const SipSessionPtr& sessionPtr)
+{
+    mSession = sessionPtr;
+}
+
+InviteSessionState PJSipSessionModInfo::inviteStateTranslate(pjsip_inv_state state)
+{
+    InviteSessionState retState;
+    switch (state)
+    {
+    case PJSIP_INV_STATE_NULL:
+        retState = InviteSessionStateNull;
+        break;
+    case PJSIP_INV_STATE_CALLING:
+        retState = InviteSessionStateCalling;
+        break;
+    case PJSIP_INV_STATE_INCOMING:
+        retState = InviteSessionStateIncoming;
+        break;
+    case PJSIP_INV_STATE_EARLY:
+        retState = InviteSessionStateEarly;
+        break;
+    case PJSIP_INV_STATE_CONNECTING:
+        retState = InviteSessionStateConnecting;
+        break;
+    case PJSIP_INV_STATE_CONFIRMED:
+        retState = InviteSessionStateConfirmed;
+        break;
+    case PJSIP_INV_STATE_DISCONNECTED:
+        retState = InviteSessionStateDisconnected;
+        break;
+    default:
+        lg(Warning) << "Unknwon PJSIP INVITE state encountered: " << state;
+        retState = InviteSessionStateNull;
+        break;
+    }
+    return retState;
+}
+
+void PJSipSessionModule::replicateState(PJSipDialogModInfo *dlgInfo, PJSipTransactionModInfo *tsxInfo,
+    PJSipSessionModInfo *sessionInfo)
+{
+    SipStateItemSeq setItems;
+    Ice::StringSeq removeItems;
+
+    lg(Debug) << "========== Begin State Replication Dump ==========";
+
+    if (dlgInfo)
+    {
+        lg(Debug) << "--- Begin Dialog " << dlgInfo->mDialogState->key;
+        lg(Debug) << "Callid: " << dlgInfo->mDialogState->mCallId;
+        lg(Debug) << "Is Dialog Established: " << dlgInfo->mDialogState->mIsDialogEstablished;
+        lg(Debug) << "Is Secure: " << dlgInfo->mDialogState->mIsSecure;
+        lg(Debug) << "Local CSeq: " << dlgInfo->mDialogState->mLocalCSeq;
+        lg(Debug) << "Local URI: " << dlgInfo->mDialogState->mLocalUri;
+        lg(Debug) << "Remote CSeq: " << dlgInfo->mDialogState->mRemoteCSeq;
+        lg(Debug) << "Remote URI: " << dlgInfo->mDialogState->mRemoteUri;
+        lg(Debug) << "Transport: " << dlgInfo->mDialogState->mTransport;
+        lg(Debug) << "UAC Has 2xx: " << dlgInfo->mDialogState->mUacHas2xx;
+        lg(Debug) << "Is Uac: " << dlgInfo->mDialogState->mIsUac;
+        if (dlgInfo->mNeedsRemoval == true)
+        {
+            lg(Debug) << "Removing dialog";
+            removeItems.push_back(dlgInfo->mDialogState->key);
+        }
+        else if (dlgInfo->mNeedsReplication == true)
+        {
+            lg(Debug) << "Replicating dialog";
+            setItems.push_back(dlgInfo->mDialogState);
+            dlgInfo->mNeedsReplication = false;
+        }
+        lg(Debug) << "--- End Dialog " << dlgInfo->mDialogState->key;
+    }
+    if (sessionInfo)
+    {
+        boost::shared_lock<boost::shared_mutex> lock(sessionInfo->mLock);
+        lg(Debug) << "--- Begin Session " << sessionInfo->mSessionState->key;
+        lg(Debug) << "Endpoint name: " << sessionInfo->mSessionState->mEndpointName;
+        lg(Debug) << "Session object identity: " << sessionInfo->mSessionState->mSessionObjectId.name;
+        lg(Debug) << "Media session object identity: " << sessionInfo->mSessionState->mMediaSessionObjectId.name;
+        lg(Debug) << "Media session: " << sessionInfo->mSessionState->mMediaSession;
+        lg(Debug) << "Bridge: " << sessionInfo->mSessionState->mBridge;
+        lg(Debug) << "--- Begin Invite Session " << sessionInfo->mInviteState->key;
+        lg(Debug) << "Current state: " << sessionInfo->mInviteState->mCurrentState;
+        lg(Debug) << "Cancelling: " << sessionInfo->mInviteState->mCancelling;
+        lg(Debug) << "Pending cancel: " << sessionInfo->mInviteState->mPendingCancel;
+        lg(Debug) << "Cause: " << sessionInfo->mInviteState->mCause;
+        lg(Debug) << "Cause text: " << sessionInfo->mInviteState->mCauseText;
+        lg(Debug) << "Notify: " << sessionInfo->mInviteState->mNotify;
+        lg(Debug) << "Last Ack CSeq: " << sessionInfo->mInviteState->mLastAckCseq;
+        if (sessionInfo->mNeedsRemoval == true)
+        {
+            removeItems.push_back(sessionInfo->mInviteState->key);
+            removeItems.push_back(sessionInfo->mSessionState->key);
+            lg(Debug) << "Removing session and invite session";
+        }
+        else if (sessionInfo->mNeedsReplication == true)
+        {
+            setItems.push_back(sessionInfo->mInviteState);
+            setItems.insert(setItems.begin(), sessionInfo->mSessionState);
+            sessionInfo->mNeedsReplication = false;
+            lg(Debug) << "Replicating session and invite session";
+        }
+        lg(Debug) << "--- End Session and Invite Session";
+    }
+    if (tsxInfo)
+    {
+        if (tsxInfo->mNeedsRemoval == true)
+        {
+            removeItems.push_back(tsxInfo->mTransactionState->key);
+        }
+        else if (tsxInfo->mNeedsReplication == true)
+        {
+            setItems.push_back(tsxInfo->mTransactionState);
+            tsxInfo->mNeedsReplication = false;
+        }
+    }
+    lg(Debug) << "========== End State Replication Dump ==========";
+    if (mReplica->isActive() == true)
+    {
+        if (setItems.size() != 0 && mStateReplicator)
+        {
+            Ice::ObjectPrx oneway;
+            try
+            {
+                oneway = mStateReplicator->ice_oneway();
+            }
+            catch (const Ice::NoEndpointException&)
+            {
+                lg(Error) << "No endpoint for oneway invocation of setState() for state replication.";
+            }
+
+            AsteriskSCF::SIP::V1::SipStateReplicatorPrx oneWayStateReplicator = 
+                AsteriskSCF::SIP::V1::SipStateReplicatorPrx::uncheckedCast(oneway);
+
+            try
+            {
+                oneWayStateReplicator->setState(setItems);
+            }
+            catch (const Ice::TwowayOnlyException&)
+            {
+                lg(Error) << "setState() is not oneway.";
+            }
+        }
+
+        if (removeItems.size() != 0 && mStateReplicator)
+        {
+            Ice::ObjectPrx oneway;
+            try
+            {
+                oneway = mStateReplicator->ice_oneway();
+            }
+            catch (const Ice::NoEndpointException&)
+            {
+                lg(Error) << "No endpoint for oneway invocation of removeState() for state replication.";
+            }
+
+            AsteriskSCF::SIP::V1::SipStateReplicatorPrx oneWayStateReplicator =
+                AsteriskSCF::SIP::V1::SipStateReplicatorPrx::uncheckedCast(oneway);
+
+            try
+            {
+                oneWayStateReplicator->removeState(removeItems);
+            }
+            catch (const Ice::TwowayOnlyException&)
+            {
+                lg(Error) << "removeState() is not oneway.";
+            }
+        }
+    }
+}
+
+pj_status_t PJSipSessionModule::load(pjsip_endpoint*)
+{
+    return PJ_SUCCESS;
+}
+
+pj_status_t PJSipSessionModule::start()
+{
+    return PJ_SUCCESS;
+}
+
+pj_status_t PJSipSessionModule::stop()
+{
+    return PJ_SUCCESS;
+}
+
+pj_status_t PJSipSessionModule::unload()
+{
+    return PJ_SUCCESS;
+}
+
+void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
+{
+    //What do we do here?
+    //
+    //First we need to identify who this is coming from.
+    //If it's someone we recognize, then we can figure
+    //out whether we need to send a 401/407 request.
+    //For now, we don't have any sort of configured users,
+    //so we skip this step. Instead, we'll skip ahead to
+    //creating an endpoint, creating the invite session,
+    //sending a 100 trying, finding the remote endpoint
+    //to call, and placing a call to it.
+
+    //XXX Put caller identification code in here!
+
+    pjsip_tx_data *tdata = NULL;
+    unsigned options = PJSIP_INV_SUPPORT_100REL;
+
+    // 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;
+    }
+
+    pjsip_dialog *dlg, *replaced_dlg;
+
+    // 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);
+	}
+        return;
+    }
+
+    //XXX The NULL parameter should be replaced with
+    //An appropriate Contact header. Leaving it NULL makes
+    //PJSIP create the contact header for responses based
+    //on the To header of the incoming Invite.
+    if (pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dlg) != PJ_SUCCESS)
+    {
+        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;
+
+    //XXX The sdp argument is NULL for now, but can be changed if we
+    //know what has been configured for this particular caller.
+    pjsip_inv_session *inv_session;
+    if (pjsip_inv_create_uas(dlg, rdata, NULL, 0, &inv_session) != PJ_SUCCESS)
+    {
+        lg(Warning) << "Unable to create INVITE session";
+        //Since the inv_session was not created, we need to access the base dialog
+        //directly instead. Other failure cases will use pjsip_inv_terminate instead.
+        pjsip_dlg_terminate(dlg);
+        return;
+    }
+
+    // Add our own module as a dialog usage
+    pjsip_dlg_add_usage(dlg, &mModule, NULL);
+
+    pjsip_timer_setting session_timer_settings;
+    pjsip_timer_setting_default(&session_timer_settings);
+    pjsip_timer_init_session(inv_session, &session_timer_settings);
+
+    if (pjsip_inv_initial_answer(inv_session, rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS)
+    {
+        lg(Warning) << "Failed to create 100 Trying response";
+        pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+        return;
+    }
+
+    if (pjsip_inv_send_msg(inv_session, tdata) != PJ_SUCCESS)
+    {
+        lg(Warning) << "Failed to send 100 Trying response";
+        pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+    }
+
+    pjsip_uri *from = rdata->msg_info.from->uri;
+    std::string callerName("");
+    if (PJSIP_URI_SCHEME_IS_SIP(from) || PJSIP_URI_SCHEME_IS_SIPS(from))
+    {
+        pjsip_sip_uri *sipFrom = (pjsip_sip_uri *)pjsip_uri_get_uri(from);
+        callerName = std::string(pj_strbuf(&sipFrom->user), pj_strlen(&sipFrom->user));
+        lg(Debug) << "Got caller name " << callerName;
+    }
+    SipEndpointPtr caller = mEndpointFactory->findByName(callerName);
+    if (caller == 0)
+    {
+        lg(Warning) << "Unknown calling endpoint " << callerName;
+        pjsip_inv_end_session(inv_session, 403, NULL, &tdata);
+        pjsip_inv_send_msg(inv_session, tdata);
+        return;
+    }
+    SipEndpointConfig &config = caller->getConfig();
+    if (config.sessionConfig.callDirection != BOTH && config.sessionConfig.callDirection != INBOUND)
+    {
+        lg(Warning) << "Caller " << callerName << " does not have permission to make inbound calls.";
+        pjsip_inv_end_session(inv_session, 403, NULL, &tdata);
+        pjsip_inv_send_msg(inv_session, tdata);
+        return;
+    }
+
+    //We've created our calling endpoint. Now we need to look up the destination.
+    pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
+    std::string destination("");
+    if (PJSIP_URI_SCHEME_IS_SIP(ruri) || PJSIP_URI_SCHEME_IS_SIPS(ruri))
+    {
+        pjsip_sip_uri *sipRuri = (pjsip_sip_uri *)pjsip_uri_get_uri(ruri);
+        //For now, we only know about destination "100" so we'll
+        //grab that from the URI to pass to the locator.
+        destination = std::string(pj_strbuf(&sipRuri->user), pj_strlen(&sipRuri->user));
+        lg(Debug) << "Call is destined for " << 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;
+    }
+}
+
+void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+{
+    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)
+    {
+        // 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
+    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);
+
+    // 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)
+    {
+        replaces_param = pjsip_param_find(&target_sip_uri->header_param, &replaces);
+    }
+
+    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;
+
+        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_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
+                return;
+            }
+
+            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());
+
+            other_dlg = pjsip_ua_find_dialog(&replaces_tag_str, &to_tag_str, &from_tag_str, PJ_TRUE);
+        }
+
+        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_inv_session *other_inv = pjsip_dlg_get_inv_session(other_dlg);
+
+        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;
+        }
+
+        if (other_inv->state >= PJSIP_INV_STATE_DISCONNECTED)
+        {
+            lg(Debug) << "handleRefer() sending PJSIP_SC_DECLINE due to state > PJSIP_INV_STATE_DISCONNECTED. ";
+
+            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_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_respond(inv->dlg, rdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
+            pjsip_dlg_dec_lock(other_dlg);
+            return;
+        }
+
+        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();
+
+        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);
+
+            lg(Debug) << "handleRefer() calling router connectBridgedSessions(). ";
+            mSessionRouter->begin_connectBridgedSessions(operationId, session->getSessionProxy(), other_session->getSessionProxy(), 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;
+        }
+        pjsip_dlg_dec_lock(other_dlg);
+    }
+    else
+    {
+        std::string target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->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*)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;
+        }
+    }
+}
+
+pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)
+{
+    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+    switch (rdata->msg_info.msg->line.req.method.id)
+    {
+    case PJSIP_ACK_METHOD:
+	return PJ_FALSE;
+    case PJSIP_INVITE_METHOD:
+        if (dlg == NULL)
+        {
+            handleNewInvite(rdata);
+        }
+        else
+        {
+            lg(Warning) << "on_rx_request called back in mid-dialog?";
+        }
+        break;
+    case PJSIP_OTHER_METHOD:
+        if (dlg && !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method()))
+        {
+            // We are essentially stopping the pjsip code from sending a 500 here, but this will actually be handled
+            // within the transaction code
+            break;
+        }
+    default:
+	pjsip_endpt_respond_stateless(mEndpoint, rdata, 405, NULL, NULL, NULL);
+	break;
+    }
+
+    return PJ_TRUE;
+}
+
+/* The following four member functions are all stubbed out because they
+ * are either unused at the moment or will never be called due to the use
+ * of PJSIP's INVITE session module.
+ *
+ * Linking errors abound if these member functions are not defined, though.
+ */
+pj_bool_t PJSipSessionModule::on_rx_response(pjsip_rx_data*)
+{
+    return PJ_FALSE;
+}
+pj_status_t PJSipSessionModule::on_tx_request(pjsip_tx_data*)
+{
+    return PJ_SUCCESS;
+}
+pj_status_t PJSipSessionModule::on_tx_response(pjsip_tx_data*)
+{
+    return PJ_SUCCESS;
+}
+void PJSipSessionModule::on_tsx_state(pjsip_transaction*, pjsip_event*)
+{
+    return;
+}
+
+void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
+    pjsip_rx_data* rdata, pjsip_dialog*)
+{
+    int respCode = rdata->msg_info.msg->line.status.code;
+    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
+    SipSessionPtr session = session_mod_info->getSessionPtr();
+    //Commented because they are currently unused. They
+    //will be once the individual cases are mapped out.
+    //pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+    //pjsip_module *module = pjsip_ua_instance();
+    //
+    //XXX There are a BUNCH of response codes we need
+    //to add code to handle.
+
+    //Treat all 1XX messages we don't recognize the same as a 180
+    if (respCode > 100 && respCode < 200 && respCode != 183)
+    {
+        respCode = 180;
+    }
+    if (respCode == 100)
+    {
+        //Not sure if PJSIP even bothers passing these up
+        lg(Debug) << "Got 100 response";
+    }
+    else if (respCode == 180)
+    {
+        lg(Debug) << "Got 180 response";
+        std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> listeners = session->getListeners();
+        std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+        lg(Debug) << "Relating ringing state to " << listeners.size() << " listeners";
+        for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+        {
+            try
+            {
+                ListenerCallbackPtr cb(new ListenerCallback(RingingCallbackName));
+                Callback_SessionListener_indicatedPtr ringingCB =
+                    newCallback_SessionListener_indicated(cb, &ListenerCallback::failure);
+                (*listener)->begin_indicated(session->getSessionProxy(), new RingingIndication(), ringingCB);
+            }
+            catch (const Ice::Exception &ex)
+            {
+                lg(Error) << "Ice exception when attempting to relate ringing state: " << ex.what();
+            }
+        }
+    }
+    else if (respCode == 183)
+    {
+        lg(Debug) << "Got 183 response";
+        AsteriskSCF::SessionCommunications::V1::ResponseCodePtr response = new AsteriskSCF::SessionCommunications::V1::ResponseCode();
+        response->isdnCode = 42;
+        std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> listeners = session->getListeners();
+        std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+        lg(Debug) << "Relating progressing state to " << listeners.size() << " listeners";
+        for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+        {
+            try
+            {
+                ListenerCallbackPtr cb(new ListenerCallback(ProgressingCallbackName));
+                Callback_SessionListener_indicatedPtr progressingCB =
+                    newCallback_SessionListener_indicated(cb, &ListenerCallback::failure);
+		ProgressingIndicationPtr progressing(new ProgressingIndication());
+		progressing->response = response;
+                (*listener)->begin_indicated(session->getSessionProxy(), progressing, progressingCB);
+            }
+            catch (const Ice::Exception &ex)
+            {
+                lg(Error) << "Ice exception when attempting to relate progressing state: " << ex.what();
+            }
+        }
+    }
+    else if (respCode == 200)
+    {
+        lg(Debug) << "Got 200 response";
+        if (inv->state != PJSIP_INV_STATE_DISCONNECTED)
+        {
+            std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> listeners = session->getListeners();
+            std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator listener;
+            lg(Debug) << "Relating connected state to " << listeners.size() << " listeners";
+            for (listener = listeners.begin(); listener != listeners.end(); ++listener)
+            {
+                try
+                {
+                    ListenerCallbackPtr cb(new ListenerCallback(ConnectedCallbackName));
+                    Callback_SessionListener_indicatedPtr connectedCB =
+                        newCallback_SessionListener_indicated(cb, &ListenerCallback::failure);
+                    (*listener)->begin_indicated(session->getSessionProxy(), new ConnectedIndication(), connectedCB);
+                }
+                catch (const Ice::Exception &ex)
+                {
+                    lg(Error) << "Ice exception when attempting to relate connected state: " << ex.what();
+                }
+            }
+        }
+    }
+}
+
+void PJSipSessionModule::invOnStateChanged(pjsip_inv_session *inv, pjsip_event *event)
+{
+    if ((inv->state == PJSIP_INV_STATE_EARLY || inv->state == PJSIP_INV_STATE_CONNECTING) &&
+        event->type == PJSIP_EVENT_TSX_STATE &&
+        inv->role == PJSIP_ROLE_UAC)
+    {
+        //Received a 1XX or 2XX message in response to our initial outgoing INVITE.
+        handleInviteResponse(inv, event->body.tsx_state.src.rdata, inv->dlg);
+    }
+    if (inv->state == PJSIP_INV_STATE_DISCONNECTED)
+    {
+        PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
+        if (session_mod_info == 0)
+        {
+            return;
+        }
+        SipSessionPtr session = session_mod_info->getSessionPtr();
+        AsteriskSCF::SessionCommunications::V1::ResponseCodePtr response =
+            new AsteriskSCF::SessionCommunications::V1::ResponseCode();
+        if (inv->cause == 486)
+        {
+            response->isdnCode = 17;
+        }
+        else if (PJSIP_IS_STATUS_IN_CLASS(inv->cause, 500))
+        {
+            response->isdnCode = 34;
+        }
+        else
+        {
+            // TODO: See what cause is on a normal call completion
+            response->isdnCode = 0;
+        }
+        std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> listeners = session->getListeners();
+        lg(Debug) << "Relating stopped state to " << listeners.size() << " listeners";
+	AsteriskSCF::SessionCommunications::V1::StoppedIndicationPtr stopped(new AsteriskSCF::SessionCommunications::V1::StoppedIndication());
+	stopped->response = response;
+        for (std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::iterator listener =
+                 listeners.begin();
+             listener != listeners.end();
+             ++listener)
+        {
+            try
+            {
+                (*listener)->indicated(session->getSessionProxy(), stopped);
+            }
+            catch (const Ice::Exception &ex)
+            {
+                lg(Error) << "Ice exception when attempting to relate stopped state: " << ex.what();
+            }
+        }
+        session_mod_info->mNeedsRemoval = true;
+        pjsip_dialog *dlg = inv->dlg;
+        PJSipDialogModInfo *dlg_mod_info = (PJSipDialogModInfo*) dlg->mod_data[mModule.id];
+	if (dlg_mod_info)
+	{
+	    dlg_mod_info->mNeedsRemoval = true;
+	}
+        lg(Debug) << "Replicating state on DISCONNECTED inv_state.";
+        replicateState(dlg_mod_info, NULL, session_mod_info);
+        delete session_mod_info;
+	inv->mod_data[mModule.id] = 0;
+	if (dlg_mod_info)
+	{
+	    delete dlg_mod_info;
+	    dlg->mod_data[mModule.id] = 0;
+	}
+    }
+    if (event->type == PJSIP_EVENT_RX_MSG && inv->state == PJSIP_INV_STATE_CONFIRMED)
+    {
+        //We received an ACK for our 2XX response.
+        //See comment in invOnTransactionStateChanged() for explanation of this.
+
+        PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo*>(inv->mod_data[mModule.id]);
+        if (session_mod_info)
+        {
+            session_mod_info->updateSessionState(inv);
+        }
+        replicateState(NULL, NULL, session_mod_info);
+
+        //Compare branches to see if this got handled by the transaction layer.
+        if (inv->invite_tsx &&
+                pj_strcmp(&event->body.rx_msg.rdata->msg_info.via->branch_param, &inv->invite_tsx->branch) != 0)
+        {
+            //Mismatched branch!
+            invOnTsxStateChanged(inv, inv->invite_tsx, event);
+        }
+    }
+    if (event->type == PJSIP_EVENT_TSX_STATE && inv->state == PJSIP_INV_STATE_CALLING && inv->role == PJSIP_ROLE_UAC)
+    {
+        //We have sent an INVITE out. We need to set up the transaction and dialog structures
+        //to have the appropriate mod_data and initiate some state replication here as well.
+        //The inv_session's mod_info was set up in SipSession::start() because we had the SipSession
+        //information there.
+        PJSipDialogModInfo *dlg_mod_info = new PJSipDialogModInfo(inv->dlg);
+        PJSipTransactionModInfo *tsx_mod_info = new PJSipTransactionModInfo(inv->invite_tsx);
+        PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo *>(inv->mod_data[mModule.id]);
+        inv->invite_tsx->mod_data[mModule.id] = (void *) tsx_mod_info;
+        inv->dlg->mod_data[mModule.id] = (void *) dlg_mod_info;
+        dlg_mod_info->mDialogState->mSessionId = session_mod_info->mSessionState->mSessionId;
+        tsx_mod_info->mTransactionState->mSessionId = session_mod_info->mSessionState->mSessionId;
+        lg(Debug) << "Replicating state on new outbound INVITE.";
+        replicateState(dlg_mod_info, tsx_mod_info, session_mod_info);
+    }
+}
+
+void PJSipSessionModule::invOnNewSession(pjsip_inv_session*, pjsip_event*)
+{
+    //stub
+}
+
+void PJSipSessionModule::invOnTsxStateChanged(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
+{
+    if (tsx->role == PJSIP_ROLE_UAS && tsx->state == PJSIP_TSX_STATE_TRYING &&
+            !pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()))
+    {
+        handleRefer(inv, e->body.tsx_state.src.rdata);
+    }
+    //This will be our key point for updating transaction state.  This function will not be called until after a module
+    //has registered itself as the transaction user, so this won't be called on the initial INVITE we receive.
+    //
+    //Having taken a look at the pjsip inv_session code, the transaction state changed callback is called *after* the
+    //inv_state_changed callback. This means that on both reception and transmission of requests, this is called last,
+    //meaning this is the prime spot to do state replication of dialogs, transactions, sessions.
+    //
+    //There is one exception. If we receive an ACK for an INVITE transaction and the ACK has a different Via branch
+    //parameter than the INVITE and its response, then this callback will not be called at all, and we will need to
+    //perform the proper state replication in the invOnStateChanged function. This can be done simply by calling this
+    //function from there.
+
+    PJSipTransactionModInfo *tsx_mod_info = static_cast<PJSipTransactionModInfo *> (tsx->mod_data[mModule.id]);
+    // TODO: Determine if this is perfectly acceptable, since it occurs when the call is going bye bye
+    if (!tsx_mod_info)
+    {
+        return;
+    }
+    if (tsx->state != PJSIP_TSX_STATE_DESTROYED)
+    {
+        tsx_mod_info->updateTransactionState(tsx);
+    }
+    else
+    {
+        tsx_mod_info->mNeedsRemoval = true;
+    }
+    if (e->type == PJSIP_EVENT_TSX_STATE)
+    {
+        pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
+        PJSipDialogModInfo *dlg_mod_info = NULL;
+        if (dlg)
+        {
+            dlg_mod_info = static_cast<PJSipDialogModInfo*>(dlg->mod_data[mModule.id]);
+            if (dlg_mod_info)
+            {
+                dlg_mod_info->updateDialogState(dlg);
+            }
+        }
+        PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo*>(inv->mod_data[mModule.id]);
+        if (session_mod_info)
+        {
+            session_mod_info->updateSessionState(inv);
+        }
+        lg(Debug) << "Replicating state on transaction state change to " << tsx->state;
+        replicateState(dlg_mod_info, tsx_mod_info, session_mod_info);
+    }
+    else if (e->type == PJSIP_EVENT_TIMER)
+    {
+        lg(Debug) << "Replicating state on transaction state change to " << tsx->state;
+        replicateState(NULL, tsx_mod_info, NULL);
+    }
+}
+
+void PJSipSessionModule::invOnRxOffer(pjsip_inv_session* inv, const pjmedia_sdp_session*)
+{
+    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
+    pjsip_inv_set_sdp_answer(inv, session_mod_info->getSessionPtr()->createSDPOffer());
+}
+
+void PJSipSessionModule::invOnCreateOffer(pjsip_inv_session*, pjmedia_sdp_session**)
+{
+    //stub
+}
+
+void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t status)
+{
+    if (status != PJ_SUCCESS)
+    {
+        // We have nothing, zip, nada, kablamo, in common.
+        return;
+    }
+
+    const pjmedia_sdp_session *remote_sdp;
+    if ((status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp)) != PJ_SUCCESS)
+    {
+        // TODO: What happens if we can't get negotiated SDP?
+        return;
+    }
+
+    const pjmedia_sdp_conn *remote_conn = remote_sdp->media[0]->conn ? remote_sdp->media[0]->conn : remote_sdp->conn;
+
+    PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
+    SipSessionPtr session = session_mod_info->getSessionPtr();
+    std::string destination(pj_strbuf(&remote_conn->addr), pj_strlen(&remote_conn->addr));
+    session->setRemoteDetails(destination, remote_sdp->media[0]->desc.port);
+
+    // Each stream has its own set of formats, so go to that granularity
+    for (unsigned int stream = 0; stream < remote_sdp->media_count; stream++)
+    {
+        // We should have the parsing of the connection information here
+
+        // We should have the parsing of the rtcp attribute here
+
+        FormatSeq formats;
+
+        // Next step is to see what formats exist on this stream
+        for (unsigned int format = 0; format < remote_sdp->media[stream]->desc.fmt_count; format++)
+        {
+            FormatDiscoverySDPPtr params = new FormatDiscoverySDP();
+            params->category = "media_format";
+            std::stringstream(pj_strbuf(&remote_sdp->media[stream]->desc.fmt[format])) >> params->payload;
+            params->type = std::string(pj_strbuf(&remote_sdp->media[stream]->desc.media),
+                    pj_strlen(&remote_sdp->media[stream]->desc.media));
+
+            // Some devices rely solely on the payload for known formats (such as PCMU) so the following format
+            // parameters are optional
+            const pjmedia_sdp_attr *attr;
+            if ((attr = pjmedia_sdp_media_find_attr2(remote_sdp->media[stream], "rtpmap",
+                                    &remote_sdp->media[stream]->desc.fmt[format])))
+            {
+                pjmedia_sdp_rtpmap *rtpmap;
+                if ((pjmedia_sdp_attr_to_rtpmap(inv->pool_active, attr, &rtpmap)) == PJ_SUCCESS)
+                {
+                    params->subtype = std::string(pj_strbuf(&rtpmap->enc_name), pj_strlen(&rtpmap->enc_name));
+                    params->samplerate = rtpmap->clock_rate;
+                }
+            }
+
+            // Next we move on to the format specific parameters
+            if ((attr = pjmedia_sdp_media_find_attr2(remote_sdp->media[stream], "fmtp",
+                                    &remote_sdp->media[stream]->desc.fmt[format])))
+            {
+                pjmedia_sdp_fmtp fmtp;
+                if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS)
+                {
+                    std::string parameter = std::string(pj_strbuf(&fmtp.fmt_param), pj_strlen(&fmtp.fmt_param));
+                    params->parameters.push_back(parameter);
+                }
+            }
+
+            // Next up are attributes that are not specific to the format, such as ptime
+            for (unsigned int attribute = 0; attribute < remote_sdp->media[stream]->attr_count; attribute++)
+            {
+                // Attributes we already touch above OR know aren't helpful to the media format component don't need to
+                // be given to it, obviously
+                if (!pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "rtpmap") ||
+                    !pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "fmtp") ||
+                    !pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "rtcp") ||
+                    !pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "sendrecv") ||
+                    !pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "sendonly") ||
+                    !pj_strcmp2(&remote_sdp->media[stream]->attr[attribute]->name, "recvonly"))
+                {
+                    continue;
+                }
+
+                std::string parameter = std::string(pj_strbuf(&remote_sdp->media[stream]->attr[attribute]->name),
+                        pj_strlen(&remote_sdp->media[stream]->attr[attribute]->name)) + ':' +
+                    std::string(pj_strbuf(&remote_sdp->media[stream]->attr[attribute]->value),
+                            pj_strlen(&remote_sdp->media[stream]->attr[attribute]->value));
+                params->parameters.push_back(parameter);
+            }
+
+            try
+            {
+                MediaFormatServicePrx service = MediaFormatServicePrx::uncheckedCast(mServiceLocator->locate(params));
+
+                // It is entirely possible for the service locator to not find a service that knows about this media
+                // format
+                if (service != 0)
+                {
+                    formats.push_back(FormatPtr::dynamicCast(service->getFormat(params)));
+                }
+            }
+            catch (...)
+            {
+                // If we get here the format just isn't supported...
+            }
+        }
+    }
+}
+
+pjsip_redirect_op PJSipSessionModule::invOnRedirected(pjsip_inv_session*, const pjsip_uri*,
+        const pjsip_event*)
+{
+    //stub
+    return PJSIP_REDIRECT_REJECT;
+}
+
+pjsip_dialog *PJSipSessionModule::uaOnDialogForked(pjsip_dialog*, pjsip_rx_data*)
+{
+    //stub
+    return NULL;
+}
+
+QueuePtr PJSipSessionModule::getThreadPoolQueue()
+{
+    return mPoolQueue;
+}
+
+PJSipSessionModuleThreadPoolListener::PJSipSessionModuleThreadPoolListener()
+    : mActiveThreads(0) { }
+
+void PJSipSessionModuleThreadPoolListener::stateChanged(const PoolPtr& pool, Ice::Long active, Ice::Long idle, Ice::Long)
+{
+    //XXX Making this behavior more customizable would be nice
+    //
+    //For now, what we do is kill all idle threads.
+    if (idle > 0)
+    {
+        pool->setSize((int) active);
+    }
+    mActiveThreads = active;
+}
+
+void PJSipSessionModuleThreadPoolListener::queueWorkAdded(const PoolPtr& pool, Ice::Long numNewWork, bool)
+{
+    //XXX Making this behavior more customizable would be nice
+    //
+    //For now, use one thread per work item.
+    int newSize = (int) (mActiveThreads + numNewWork);
+    pool->setSize(newSize);
+}
+
+void PJSipSessionModuleThreadPoolListener::queueEmptied(const PoolPtr& pool)
+{
+    //XXX Making this behavior more customizable would be nice
+    //
+    //For now, kill off everything
+    pool->setSize(0);
+}
+
+SessionWork::SessionWork(const QueuePtr& queue)
+    : mThreadPoolQueue(queue),
+    mInternalQueue(new SuspendableWorkQueue(this)) { }
+
+void SessionWork::workAdded(Ice::Long, bool wasEmpty)
+{
+    if (wasEmpty)
+    {
+        mThreadPoolQueue->enqueueWork(this);
+    }
+}
+
+void SessionWork::workResumable()
+{
+    mThreadPoolQueue->enqueueWork(this);
+}
+
+void SessionWork::emptied()
+{
+    //Empty on purpose. Nothing special
+    //to do here.
+}
+
+void SessionWork::execute()
+{
+    while(mInternalQueue->executeWork());
+}
+
+void SessionWork::enqueueWork(const SuspendableWorkPtr& work)
+{
+    mInternalQueue->enqueueWork(work);
+}
+
+}; //end namespace SipSessionManager
+}; //end namespace AsteriskSCF
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 73fd186..1519f21 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -91,6 +91,7 @@ public:
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SIP::V1::SipStateReplicatorPrx>& stateReplicator,
         const AsteriskSCF::System::Component::V1::ReplicaPtr& replica);
+    ~PJSipSessionModule();
     pj_status_t load(pjsip_endpoint *endpoint);
     pj_status_t start();
     pj_status_t stop();
diff --git a/src/SipSession.h b/src/SipSession.h
index 6e4d682..1249925 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -66,10 +66,10 @@ public:
      * Overrides of QueueListener interface
      */
     SessionWork(const AsteriskSCF::System::WorkQueue::V1::QueuePtr& threadPoolQueue);
-    void workAdded(Ice::Long newWork, bool wasEmpty);
-    void workResumable();
-    void emptied();
-    void shuttingDown();
+    void workAdded(const AsteriskSCF::System::WorkQueue::V1::QueueBasePtr&, Ice::Long newWork, bool wasEmpty);
+    void workResumable(const AsteriskSCF::System::WorkQueue::V1::QueueBasePtr&);
+    void emptied(const AsteriskSCF::System::WorkQueue::V1::QueueBasePtr&);
+    void shuttingDown(const AsteriskSCF::System::WorkQueue::V1::QueueBasePtr&);
 
     /**
      * Override of Work interface

commit d9ad2557af844f4241a8e9c42cdf7da57d63ac98
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Jun 6 15:00:52 2011 -0500

    Make adjustments based on slice changes to Queues.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 74fe6f3..429f0bb 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -731,6 +731,8 @@ protected:
                 Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
 
                 lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
+                lg(Debug) << "Session to replace is with endpoint " << session->getEndpoint()->getName();
+                lg(Debug) << "Destination is " << mTarget;
                 mWasWithDestination = true;
                 mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, d);
                 return Complete;
@@ -1611,13 +1613,27 @@ void SessionWork::workAdded(Ice::Long, bool wasEmpty)
 {
     if (wasEmpty)
     {
-        mThreadPoolQueue->enqueueWork(this);
+        try
+        {
+            mThreadPoolQueue->enqueueWork(this);
+        }
+        catch (ShuttingDown)
+        {
+            lg(Warning) << "Queue has shut down. Not enqueueing task.";
+        }
     }
 }
 
 void SessionWork::workResumable()
 {
-    mThreadPoolQueue->enqueueWork(this);
+    try
+    {
+        mThreadPoolQueue->enqueueWork(this);
+    }
+    catch (ShuttingDown)
+    {
+        lg(Warning) << "Queue has shut down. Not enqueueing task.";
+    }
 }
 
 void SessionWork::emptied()
@@ -1626,16 +1642,34 @@ void SessionWork::emptied()
     //to do here.
 }
 
+void SessionWork::shuttingDown()
+{
+}
+
 void SessionWork::execute()
 {
-    while(mInternalQueue->executeWork()) {
-        // no-op
+    try
+    {
+        while(mInternalQueue->executeWork()) {
+            // no-op
+        }
+    }
+    catch (ShuttingDown)
+    {
+        lg(Warning) << "Queue has shut down. Not enqueueing task.";
     }
 }
 
 void SessionWork::enqueueWork(const SuspendableWorkPtr& work)
 {
-    mInternalQueue->enqueueWork(work);
+    try
+    {
+        mInternalQueue->enqueueWork(work);
+    }
+    catch (ShuttingDown)
+    {
+        lg(Warning) << "Queue has shut down. Not enqueueing task.";
+    }
 }
 
 }; //end namespace SipSessionManager
diff --git a/src/PJSipSessionModuleConstruction.cpp b/src/PJSipSessionModuleConstruction.cpp
index 14e0718..9649b3c 100644
--- a/src/PJSipSessionModuleConstruction.cpp
+++ b/src/PJSipSessionModuleConstruction.cpp
@@ -156,5 +156,10 @@ PJSipSessionModule::PJSipSessionModule(pjsip_endpoint *endpt,
     pjsip_endpt_register_module(endpt, &mModule);
 }
 
+PJSipSessionModule::~PJSipSessionModule()
+{
+    mPoolQueue->shutDown();
+}
+
 }; //end namespace SipSessionManager
 }; //end namespace AsteriskSCF
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 63df653..caf652e 100644
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -283,6 +283,7 @@ void SipSession::initializePJSIPStructs()
             PJ_SUCCESS)
     {
         // What should we do here? Throw an exception?
+        lg(Error) << "Failed to create a UAC dialog!";
         return;
     }
     mImplPriv->mDialog = dialog;
@@ -291,6 +292,7 @@ void SipSession::initializePJSIPStructs()
     pjmedia_sdp_session *sdp = createSDPOffer();
     if ((pjsip_inv_create_uac(dialog, sdp, 0, &inviteSession)) != PJ_SUCCESS)
     {
+        lg(Error) << "Failed to create a UAC INVITE session!";
         pjsip_dlg_terminate(dialog);
         // What should we do here? Throw an exception?
         return;
@@ -334,6 +336,7 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
 
     if (isUAC)
     {
+        lg(Debug) << "New session is UAC, so we're creating the necessary PJSIP structures";
         initializePJSIPStructs();
     }
 }
@@ -426,34 +429,44 @@ public:
 
         if ((Connect = AsteriskSCF::SessionCommunications::V1::ConnectIndicationPtr::dynamicCast(mIndication)))
         {
+            lg(Debug) << "Processing a Connect indication";
             pjmedia_sdp_session *sdp = mSession->createSDPOffer();
             status = pjsip_inv_answer(mImplPriv->mInviteSession, 200, NULL, sdp, &packet);
         }
         else if ((Flash = AsteriskSCF::SessionCommunications::V1::FlashIndicationPtr::dynamicCast(mIndication)))
         {
+            lg(Debug) << "Processing a Flash indication";
             // This is usually transported using INFO or RFC2833, so for now just pretend it does not exist
         }
         else if ((Hold = AsteriskSCF::SessionCommunications::V1::HoldIndicationPtr::dynamicCast(mIndication)))
         {
             // TODO: Update SDP with sendonly attribute and no IP
             // TODO: This is actually passing the hold through, we will need to support local generation
+            lg(Debug) << "Processing a Hold indication";
             status = pjsip_inv_reinvite(mImplPriv->mInviteSession, NULL, NULL, &packet);
         }
         else if ((Progress = AsteriskSCF::SessionCommunications::V1::ProgressIndicationPtr::dynamicCast(mIndication)))
         {
+            lg(Debug) << "Processing a Progress indication";
             pjmedia_sdp_session *sdp = mSession->createSDPOffer();
             status = pjsip_inv_answer(mImplPriv->mInviteSession, 183, NULL, sdp, &packet);
         }
         else if ((Ring = AsteriskSCF::SessionCommunications::V1::RingIndicationPtr::dynamicCast(mIndication)))
         {
+            lg(Debug) << "Processing a Ring indication for session with endpoint " << mSession->getEndpoint()->getName();
             status = pjsip_inv_answer(mImplPriv->mInviteSession, 180, NULL, NULL, &packet);
         }
         else if ((Unhold = AsteriskSCF::SessionCommunications::V1::UnholdIndicationPtr::dynamicCast(mIndication)))
         {
             // TODO: Update SDP with sendrecv and IP
             // TODO: This is actually passing the unhold through, we will need to support local generation
+            lg(Debug) << "Processing a Unhold indication";
             status = pjsip_inv_reinvite(mImplPriv->mInviteSession, NULL, NULL, &packet);
         }
+        else
+        {
+            lg(Error) << "Unknown indication received";
+        }
 
         // If the indication produced a packet send it out
         if (status == PJ_SUCCESS)
@@ -908,6 +921,7 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
 
     std::string address = stream->getLocalAddress();
 
+    lg(Debug) << "                     ADDRESS IS " << address;
     if (address.find(":") != std::string::npos)
     {
 	pj_strdup2(mImplPriv->mDialog->pool, &sdp->origin.addr_type, "IP6");
@@ -1033,6 +1047,11 @@ void SipSession::setInviteSession(pjsip_inv_session *session)
 {
     mImplPriv->mInviteSession = session;
 
+    lg(Debug) << "Set the invite session on the session...";
+    if (!session)
+    {
+        lg(Debug) << "But it's NULL???";
+    }
     if (!mImplPriv->mSessionWork)
     {
         PJSipSessionModInfo *session_mod_info =
@@ -1135,11 +1154,20 @@ void SipSession::enqueueSessionWork(const SuspendableWorkPtr& task)
 
     if (!mImplPriv->mSessionWork)
     {
-	lg(Debug) << "No work queue any longer. Unable to queue operation";
-	return;
+        lg(Debug) << "No work queue any longer. Unable to queue operation";
+        return;
     }
 
-    mImplPriv->mSessionWork->enqueueWork(task);
+    try
+    {
+        mImplPriv->mSessionWork->enqueueWork(task);
+    }
+    catch (ShuttingDown)
+    {
+        //Nothing really to do in this case. We'll just log that the
+        //exception occurred.
+        lg(Warning) << "Queue has already shut down. Not enqueueing task.";
+    }
 }
 }; // end SipSessionManager
 }; // end AsteriskSCF
diff --git a/src/SipSession.h b/src/SipSession.h
index 2a60c76..6e4d682 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -69,6 +69,7 @@ public:
     void workAdded(Ice::Long newWork, bool wasEmpty);
     void workResumable();
     void emptied();
+    void shuttingDown();
 
     /**
      * Override of Work interface

commit 842ac2916a9dacfa0151dd121763d94aba3f23b5
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Fri Jun 3 15:43:32 2011 -0500

    Moved the stack size alteration to config_site.h

diff --git a/src/PJSipManager.cpp b/src/PJSipManager.cpp
index c8b4462..ffd2854 100644
--- a/src/PJSipManager.cpp
+++ b/src/PJSipManager.cpp
@@ -66,13 +66,10 @@ PJSipManager::PJSipManager(const Ice::PropertiesPtr& props)
         lg(Error) << "Failed to create a memory pool";
     }
 
-    //
-    // The stack size calculation is necessary to support x64. Due to the increased size
-    // of many of the structures PJSIP allocates on the thread stacks, the default size simply
-    // isn't big enough.
-    //
+    // The default stack size might be set in config_site.h for
+    // specific platforms. 
     status = pj_thread_create(mMemoryPool, "SIP", (pj_thread_proc *) &monitorThread,
-        mEndpoint, PJ_THREAD_DEFAULT_STACK_SIZE * (sizeof(long*)/sizeof(long)), 0, &mPjThread);
+        mEndpoint, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &mPjThread);
     if (status != PJ_SUCCESS)
     {
         lg(Error) << "Failed to create SIP maintenance thread";

commit c44cbcab1add8308822053fda7ebb73a79cadb1b
Author: Brent Eagles <beagles at digium.com>
Date:   Fri Jun 3 09:45:33 2011 -0230

    Initializing pointers to 0. This would cause crashes on Windows if they weren't
    set.. (and probably release mode builds too).

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 8477fdf..74fe6f3 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -880,8 +880,8 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
 
     pj_str_t replaces = pj_str((char*)"Replaces");
     pjsip_param *replaces_param = pjsip_param_find(&target_sip_uri->other_param, &replaces);
-    pjsip_param *to_tag_param;
-    pjsip_param *from_tag_param;
+    pjsip_param *to_tag_param = 0;
+    pjsip_param *from_tag_param = 0;
     std::string target;
     if (!replaces_param)
     {
@@ -903,7 +903,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     SipSessionPtr session = session_mod_info->getSessionPtr();
 
     //Create our initial response that we can modify in the queueable operation.
-    pjsip_tx_data *tdata;
+    pjsip_tx_data *tdata = 0;
     pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
 
     lg(Debug) << "Queuing a HandleReferOperation";

commit 3405b3d255c963ba920e859580e1d48062dd241b
Author: Kevin P. Fleming <kpfleming at digium.com>
Date:   Wed Jun 1 16:58:22 2011 -0500

    More CMake script cleanup.

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3858895..5aa8e59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,3 @@
-if(NOT logger_dir)
-  message(FATAL_ERROR "The logger directory could not be found ${logger_dir}")
-endif()
-
 # TLS support within pjsip uses OpenSSL, so if found we need to link it in
 find_package(OpenSSL)
 if(OPENSSL_FOUND)
@@ -9,7 +5,7 @@ if(OPENSSL_FOUND)
 endif()
 
 include_directories(${logger_dir}/include)
-include_directories(${utils_dir}/include)
+include_directories(${ice-util-cpp_dir}/include)
 include_directories(${API_INCLUDE_DIR})
 
 asterisk_scf_slice_include_directories(${API_SLICE_DIR})

commit f629cf1b575eb73348d837cd2864a7f76c1a4159
Merge: 9b157bc a41ade0
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Jun 1 16:17:40 2011 -0500

    Merge branch 'master' of git.asterisk.org:asterisk-scf/release/sip


commit 9b157bc4d9957ef74d6cf277035305ea2c39f0bb
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Jun 1 16:15:46 2011 -0500

    Fix object lifetime issue when handling REFER requests.
    
    I had passed a URI to the HandleReferOperation under the impression
    that it was heap-allocated and therefore would not be deleted until
    the dialog it belonged to was destroyed.
    
    However, the dialog's pool was being reset, causing the pointer we
    pass in to point to bogus memory. So now, we make copies of the
    individual parts we require and delete them ourselves when the
    operation completes.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 6d3d980..8056881 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -582,13 +582,26 @@ public:
             pjsip_inv_session *inv,
             pjsip_transaction *tsx,
             pjsip_tx_data *tdata,
-            pjsip_sip_uri *target_sip_uri,
+            pjsip_param *replaces_param,
+            pjsip_param *to_tag_param,
+            pjsip_param *from_tag_param,
+            const std::string& target,
             const SipSessionPtr& session,
             const AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx>& sessionRouter,
             const int moduleId)
         : mInv(inv), mTsx(tsx), mTdata(tdata), 
-        mTargetSipUri(target_sip_uri), mSession(session), mSessionRouter(sessionRouter),
-        mModuleId(moduleId), mWasWithDestination(false) { }
+        mReplacesParam(replaces_param ? new pjsip_param(*replaces_param) : NULL), 
+        mToTagParam(to_tag_param ? new pjsip_param(*to_tag_param) : NULL),
+        mFromTagParam(from_tag_param ? new pjsip_param(*from_tag_param) : NULL), mTarget(target),
+        mSession(session), mSessionRouter(sessionRouter),
+        mModuleId(moduleId), mWasWithDestination(false) {}
+
+    ~HandleReferOperation()
+    {
+        delete mReplacesParam;
+        delete mToTagParam;
+        delete mFromTagParam;
+    }
 
 protected:
     /**
@@ -604,33 +617,22 @@ protected:
     SuspendableWorkResult initial(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);
-
-        if (!replaces_param)
-        {
-            replaces_param = pjsip_param_find(&mTargetSipUri->header_param, &replaces);
-        }
 
-        if (replaces_param)
+        if (mReplacesParam)
         {
-            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)
+            if (mToTagParam && mFromTagParam)
             {
-                other_dlg = pjsip_ua_find_dialog(&replaces_param->value, &to_tag_param->value, &from_tag_param->value,
+                other_dlg = pjsip_ua_find_dialog(&mReplacesParam->value, &mToTagParam->value, &mFromTagParam->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));
+                std::string replaces_value_tmp = std::string(pj_strbuf(&mReplacesParam->value),
+                        pj_strlen(&mReplacesParam->value));
                 size_t from_tag_pos = replaces_value_tmp.find(";from-tag=");
                 size_t to_tag_pos = replaces_value_tmp.find(";to-tag=");
 
@@ -717,8 +719,6 @@ protected:
         }
         else
         {
-            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
             {
@@ -730,7 +730,7 @@ protected:
 
                 lg(Debug) << "handleRefer() calling router connectBridgedSessionsWithDestination(). ";
                 mWasWithDestination = true;
-                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), target, d);
+                mSessionRouter->begin_connectBridgedSessionsWithDestination(operationId, session->getSessionProxy(), mTarget, d);
                 return Complete;
             }
             catch (const Ice::CommunicatorDestroyedException &)
@@ -801,9 +801,25 @@ private:
      */
     pjsip_tx_data *mTdata;
     /**
-     * The SIP URI from the Refer-To header in the REFER request.
+     * The Replaces parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
+     */
+    pjsip_param *mReplacesParam;
+    /**
+     * The to-tag parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
+     */
+    pjsip_param *mToTagParam;
+    /**
+     * The from-tag parameter from the URI in the Refer-To header
+     * of the REFER that triggered this operation.
      */
-    pjsip_sip_uri *mTargetSipUri;
+    pjsip_param *mFromTagParam;
+    /**
+     * The user portion of the URI in the Refer-To header of the
+     * REFER that triggered this operation.
+     */
+    const std::string mTarget;
     /**
      * The SipSession on which this work is executed
      */
@@ -847,9 +863,6 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     // 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
@@ -863,6 +876,27 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
 
     pjsip_sip_uri *target_sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(target_uri);
 
+    pj_str_t replaces = pj_str((char*)"Replaces");
+    pjsip_param *replaces_param = pjsip_param_find(&target_sip_uri->other_param, &replaces);
+    pjsip_param *to_tag_param;
+    pjsip_param *from_tag_param;
+    std::string target;
+    if (!replaces_param)
+    {
+        replaces_param = pjsip_param_find(&target_sip_uri->header_param, &replaces);
+    }
+    if (replaces_param)
+    {
+        pj_str_t to_tag = pj_str((char*)"To-tag");
+        pj_str_t from_tag = pj_str((char*)"From-tag");
+        to_tag_param = pjsip_param_find(&target_sip_uri->other_param, &to_tag);
+        from_tag_param = pjsip_param_find(&target_sip_uri->other_param, &from_tag);
+    }
+    else
+    {
+        target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
+    }
+
     PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*) inv->mod_data[mModule.id];
     SipSessionPtr session = session_mod_info->getSessionPtr();
 
@@ -871,7 +905,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
 
     lg(Debug) << "Queuing a HandleReferOperation";
-    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, target_sip_uri, session, mSessionRouter, mModule.id), inv);
+    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, target, session, mSessionRouter, mModule.id), inv);
 }
 
 pj_bool_t PJSipSessionModule::on_rx_request(pjsip_rx_data *rdata)

commit a41ade002c57ccdd90495a8c0d50ba40dd69e19d
Author: Joshua Colp <jcolp at digium.com>
Date:   Wed Jun 1 15:45:14 2011 -0300

    Don't try to get the dialog from the transaction within the task since by the time it is executed the dialog will have been removed from it.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 6d3d980..ddc112d 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -182,8 +182,10 @@ void PJSipSessionModule::replicateState(PJSipDialogModInfo *dlgInfo, PJSipTransa
         lg(Debug) << "Is Secure: " << dlgInfo->mDialogState->mIsSecure;
         lg(Debug) << "Local CSeq: " << dlgInfo->mDialogState->mLocalCSeq;
         lg(Debug) << "Local URI: " << dlgInfo->mDialogState->mLocalUri;
+	lg(Debug) << "Local tag: " << dlgInfo->mDialogState->mLocalTag;
         lg(Debug) << "Remote CSeq: " << dlgInfo->mDialogState->mRemoteCSeq;
         lg(Debug) << "Remote URI: " << dlgInfo->mDialogState->mRemoteUri;
+	lg(Debug) << "Remote tag: " << dlgInfo->mDialogState->mRemoteTag;
         lg(Debug) << "Transport: " << dlgInfo->mDialogState->mTransport;
         lg(Debug) << "UAC Has 2xx: " << dlgInfo->mDialogState->mUacHas2xx;
         lg(Debug) << "Is Uac: " << dlgInfo->mDialogState->mIsUac;
@@ -1064,9 +1066,14 @@ public:
             const PJSipSessionModulePtr& module,
             pjsip_transaction *tsx,
             pjsip_inv_session *inv,
+	    pjsip_dialog *dlg,
             const int eventType,
             const int tsxState)
-        : mSessionModule(module), mTsx(tsx), mInv(inv), mEventType(eventType), mTsxState(tsxState) { }
+        : mSessionModule(module), mTsx(tsx), mInv(inv), mDlg(dlg), mEventType(eventType), mTsxState(tsxState)
+    { pjsip_dlg_inc_session(dlg, &mSessionModule->getModule()); }
+
+    ~TransactionStateOperation()
+    { pjsip_dlg_dec_session(mDlg, &mSessionModule->getModule()); }
 
 protected:
     SuspendableWorkResult initial(const SuspendableWorkListenerPtr&)
@@ -1087,11 +1094,11 @@ protected:
         }
         if (mEventType == PJSIP_EVENT_TSX_STATE)
         {
... 11819 lines suppressed ...


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list