[asterisk-scf-commits] asterisk-scf/release/sip.git branch "master" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Thu Aug 18 12:33:17 CDT 2011


branch "master" has been updated
       via  50a077ec425116275dfcc9bc5032fecd1fb62bdb (commit)
       via  5fe54b87788a322dd00bddc396b24500b8d13bdc (commit)
      from  ccec5ae8cb8bc658387d41ed309c134b35f2038e (commit)

Summary of changes:
 .../SipSessionManager/SipStateReplicationIf.ice    |   35 +-
 .../SipSessionManager/SipSessionCookiesIf.ice      |   50 ++
 src/CMakeLists.txt                                 |    3 +
 src/Component.cpp                                  |    6 +-
 src/PJSipSessionModule.cpp                         |  312 +--------
 src/SipEndpoint.cpp                                |   71 ++-
 src/SipEndpoint.h                                  |    7 +-
 src/SipSession.cpp                                 |  140 +++-
 src/SipSession.h                                   |   43 +-
 src/SipSessionManagerApp.cpp                       |  709 ++++++++++++++++++++
 src/SipStateReplicator.h                           |    8 +-
 src/SipStateReplicatorListener.cpp                 |  101 +++-
 src/SipTransfer.cpp                                |  632 +++++++++++++++++
 src/SipTransfer.h                                  |  365 ++++++++++
 14 files changed, 2133 insertions(+), 349 deletions(-)
 create mode 100644 slice/AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.ice
 create mode 100644 src/SipSessionManagerApp.cpp
 create mode 100644 src/SipTransfer.cpp
 create mode 100644 src/SipTransfer.h


- Log -----------------------------------------------------------------
commit 50a077ec425116275dfcc9bc5032fecd1fb62bdb
Merge: 5fe54b8 ccec5ae
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Aug 18 12:34:24 2011 -0500

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


commit 5fe54b87788a322dd00bddc396b24500b8d13bdc
Author: Mark Michelson <mmichelson at digium.com>
Date:   Thu Aug 18 12:33:23 2011 -0500

    Hey, I'm merging the transfer-improvements branch.

diff --git a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
index b6fabde..09e4af4 100644
--- a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
@@ -139,8 +139,6 @@ module V1
 	  bool isClient;
    };
 
-   sequence<AsteriskSCF::SessionCommunications::V1::SessionListener*> SessionListenerSeq;
-
    sequence<AsteriskSCF::Media::RTP::V1::RTPSession*> RTPMediaSessionSeq;
 
    class SipSessionStateItem extends SipStateItem
@@ -155,7 +153,7 @@ module V1
       AsteriskSCF::Media::V1::StreamSinkSeq sinks;
       AsteriskSCF::Media::V1::StreamInformationDict streams;
       RTPMediaSessionSeq rtpMediaSessions;
-      SessionListenerSeq listeners;
+      AsteriskSCF::SessionCommunications::V1::SessionListenerSeq listeners;
       AsteriskSCF::SessionCommunications::V1::Bridge *bridge;
       AsteriskSCF::SessionCommunications::V1::SessionCookieDict cookies;
    };
@@ -187,6 +185,37 @@ module V1
       bool newBindings;
    };
 
+   /**
+    * The only real state we replicate here is the existence or
+    * nonexistence of this item. So we need to have enough
+    * information to be able to construct this item.
+    */
+   class TransferSessionCreationHookStateItem extends SipStateItem
+   {
+        int referCSeq;
+        string referredBy;
+        //We need enough information to find the REFER dialog.
+        string callId;
+        string localTag;
+        string remoteTag;
+        Ice::Identity objectId;
+   };
+
+   /**
+    * The state we replicate here is the existence or nonexistence
+    * of the item. We need enough information to be able to construct
+    * the item.
+    */
+    class TransferSessionListenerStateItem extends SipStateItem
+    {
+        int referCSeq;
+        //We need enough information to find the REFER dialog.
+        string callId;
+        string localTag;
+        string remoteTag;
+        Ice::Identity objectId;
+    };
+
 }; /* module V1 */
 
 }; /* module SipSessionManager */
diff --git a/slice/AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.ice b/slice/AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.ice
new file mode 100644
index 0000000..e3263e6
--- /dev/null
+++ b/slice/AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.ice
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.ice>
+
+module AsteriskSCF
+{
+
+module SessionCookies
+{
+
+module SipSessionManager
+{
+
+["suppress"]
+module V1
+{
+
+/**
+ * When creating an outbound session, if this cookie is present,
+ * then this value should be included in a Referred-By header
+ * on the outbound INVITE.
+ */
+unsliceable class ReferredByCookie extends AsteriskSCF::SessionCommunications::V1::SessionCookie
+{
+    /**
+     * The value of the Referred-By header from a REFER
+     */
+    string value;
+};
+
+}; //end module V1
+}; //end module SipSessionManager
+}; //end module SessionCookies
+}; //end module AsteriskSCF
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index db983f0..b8ca334 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,6 +28,8 @@ astscf_component_add_files(SipSessionManager PJSipManager.cpp)
 astscf_component_add_files(SipSessionManager PJSipManager.h)
 astscf_component_add_files(SipSessionManager PJSipModule.cpp)
 astscf_component_add_files(SipSessionManager PJSipModule.h)
+astscf_component_add_files(SipSessionManager SipTransfer.cpp)
+astscf_component_add_files(SipSessionManager SipTransfer.h)
 astscf_component_add_files(SipSessionManager PJSipSessionModule.cpp)
 astscf_component_add_files(SipSessionManager PJSipSessionModuleConstruction.cpp)
 astscf_component_add_files(SipSessionManager PJSipSessionModule.h)
@@ -66,6 +68,7 @@ astscf_component_add_files(SipSessionManager SipRegistrarListener.h)
 astscf_component_add_slices(SipSessionManager PROJECT SipIf.ice)
 astscf_component_add_slices(SipSessionManager PROJECT AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice)
 astscf_component_add_slices(SipSessionManager PROJECT AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice)
+astscf_component_add_slices(SipSessionManager PROJECT AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.ice)
 astscf_component_add_ice_libraries(SipSessionManager IceStorm)
 astscf_component_add_boost_libraries(SipSessionManager core)
 astscf_component_add_slice_collection_libraries(SipSessionManager ASTSCF)
diff --git a/src/Component.cpp b/src/Component.cpp
index dea42f9..75bacbe 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -583,7 +583,11 @@ void Component::createReplicationStateListeners()
     try
     {
        // Create and publish our state replicator listener interface.
-        mReplicatorListener = new SipStateReplicatorListenerI(mEndpointFactory, mPJSipManager);
+        mReplicatorListener = new SipStateReplicatorListenerI(mEndpointFactory,
+                mPJSipManager,
+                getServiceAdapter(),
+                boost::static_pointer_cast<SipReplicationContext>(getReplicationContext()));
+
         SipStateReplicatorListenerPrx replicatorListener = SipStateReplicatorListenerPrx::uncheckedCast(
              getBackplaneAdapter()->addWithUUID(mReplicatorListener));
         mReplicatorListenerProxy = SipStateReplicatorListenerPrx::uncheckedCast(replicatorListener->ice_oneway());
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 9f8de91..61aada4 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "PJSipSessionModule.h"
+#include "SipTransfer.h"
 #include "SipEndpoint.h"
 #include "SipEndpointFactory.h"
 #include "SipSession.h"
@@ -26,8 +27,6 @@
 #include <IceUtil/UUID.h>
 #include <boost/lexical_cast.hpp>
 
-#include <boost/lexical_cast.hpp>
-
 #include <AsteriskSCF/Core/Endpoint/EndpointIf.h>
 #include <AsteriskSCF/Core/Routing/RoutingIf.h>
 #include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
@@ -483,7 +482,7 @@ protected:
                 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);
+                mSessionRouter->begin_routeSession(operationId, mSession->getSessionProxy(), mDestination, 0, d);
             }
         }
         catch (const Ice::CommunicatorDestroyedException &)
@@ -690,272 +689,6 @@ void PJSipSessionModule::handleNewInvite(pjsip_rx_data *rdata)
     sessionWork->enqueueWork(new SessionCreationOperation(this, caller, mSessionRouter, inv_session, tdata, replaced_dlg, destination));
 }
 
-class HandleReferOperation : public SipQueueableOperation 
-{
-public:
-    HandleReferOperation(
-            pjsip_inv_session *inv,
-            pjsip_transaction *tsx,
-            pjsip_tx_data *tdata,
-            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), 
-        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:
-    /**
-     * 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 initial(const SuspendableWorkListenerPtr& workListener)
-    {
-        // Determine if this is a blind transfer or an attended transfer
-
-        if (mReplacesParam)
-        {
-            pjsip_dialog *other_dlg = NULL;
-
-            if (mToTagParam && mFromTagParam)
-            {
-                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(&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=");
-
-                if (from_tag_pos == std::string::npos || to_tag_pos == std::string::npos)
-                {
-                    lg(Debug) << "handleRefer() sending 400 due to From or To missing. ";
-                    pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
-                    pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                    return Complete;
-                }
-
-                std::string to_tag_value = replaces_value_tmp.substr(to_tag_pos + 8, from_tag_pos - to_tag_pos - 8);
-                std::string from_tag_value = replaces_value_tmp.substr(from_tag_pos + 10);
-                std::string replaces_value = replaces_value_tmp.substr(0, to_tag_pos);
-
-                pj_str_t to_tag_str = pj_str((char*)to_tag_value.c_str());
-                pj_str_t from_tag_str = pj_str((char*)from_tag_value.c_str());
-                pj_str_t replaces_tag_str = pj_str((char*)replaces_value.c_str());
-
-                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_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                return Complete;
-            }
-
-            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_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. ";
-
-                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;
-            }
-
-            if (other_inv->state <= PJSIP_INV_STATE_EARLY && other_inv->role != PJSIP_ROLE_UAC)
-            {
-                lg(Debug) << "handleRefer() sending PJSIP_SC_CALL_TSX_DOES_NOT_EXIST due to other_inv->state < PJSIP_INV_STATE_EARLY and role not UAC. ";
-
-                pjsip_dlg_modify_response(mInv->dlg, mTdata, PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL);
-                pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-                pjsip_dlg_dec_lock(other_dlg);
-                return Complete;
-            }
-
-            PJSipSessionModInfo *other_session_mod_info = (PJSipSessionModInfo*)other_inv->mod_data[mModuleId];
-            SipSessionPtr other_session = other_session_mod_info->getSessionPtr();
-
-            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(). ";
-                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;
-            }
-        }
-        else
-        {
-            // 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(). ";
-                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;
-            }
-            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;
-            }
-        }
-    };
-
-    /**
-     * Once the routing service has allowed for work to be resumed,
-     * this is where the final work is done
-     */
-    SuspendableWorkResult calledBack(const Ice::AsyncResultPtr& asyncResult)
-    {
-        SessionRouterPrx router = SessionRouterPrx::uncheckedCast(asyncResult->getProxy());
-        try
-        {
-            if (mWasWithDestination)
-            {
-                router->end_connectBridgedSessionsWithDestination(asyncResult);
-            }
-            else
-            {
-                router->end_connectBridgedSessions(asyncResult);
-            }
-        }
-        catch (const AsteriskSCF::Core::Routing::V1::DestinationNotFoundException &)
-        {
-            lg(Debug) << "ConnectBridgedSessionsWithDestination sending 404 due to destination not found.";
-
-            pjsip_dlg_modify_response(mInv->dlg, mTdata, 404, NULL);
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-            return Complete;
-        }
-        catch (const std::exception &e)
-        {
-            lg(Debug) << "ConnectBridgedSessionsCallback sending 400 due to exception:  " << e.what();
-            pjsip_dlg_modify_response(mInv->dlg, mTdata, 400, NULL);
-            pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
-            return Complete;
-        }
-        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;
-    }
-
-private:
-    /**
-     * 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 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_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
-     */
-    SipSessionPtr mSession;
-    /**
-     * Session router...nothing more to say really
-     */
-    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;
-};
-
 void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdata)
 {
     //rdata structures are not safe to shallow copy to a queuable operation. Get
@@ -974,9 +707,27 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
         return;
     }
 
-    // TODO: Add support for subscription
+    pj_str_t referredBy;
+    pj_cstr(&referredBy, "Referred-By");
+    pjsip_generic_string_hdr *referredByHdr =
+        static_cast<pjsip_generic_string_hdr*>(pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &referredBy, NULL));
 
-    // TODO: Provide method to send back suitable response
+    std::string referredByVal;
+    if (referredByHdr)
+    {
+        referredByVal.assign(pj_strbuf(&referredByHdr->hvalue), pj_strlen(&referredByHdr->hvalue));
+    }
+
+    // TODO: Add support for subscription
+    //
+    // Currently, we send a NOTIFY as we are supposed to, but we don't actually
+    // have a full-blown subscription in use. This is for 2 reasons:
+    //
+    // 1. We don't have A subscription API defined yet.
+    // 2. REFERs are sort of fake subscriptions anyway.
+    //
+    // So with what we have here, this will work 99.99% of the time. If someone
+    // tries to do something like refresh a subscription though, that will fail.
 
     // 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));
@@ -984,7 +735,6 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     // 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;
@@ -1010,7 +760,7 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     }
     else
     {
-        target = std::string(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
+        target.assign(pj_strbuf(&target_sip_uri->user), pj_strlen(&target_sip_uri->user));
     }
 
     PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*) inv->mod_data[mModule.id];
@@ -1018,10 +768,18 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
 
     //Create our initial response that we can modify in the queueable operation.
     pjsip_tx_data *tdata = 0;
-    pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
+    pj_status_t status = pjsip_dlg_create_response(inv->dlg, rdata, 202, NULL, &tdata);
+
+    if (status != PJ_SUCCESS)
+    {
+        //Hm, we couldn't create a response. Let's hope this actually works...
+        lg(Error) << "Unable to create 202 Accepted response in response to REFER (Out of memory?)";
+        pjsip_dlg_respond(inv->dlg, rdata, 500, NULL, NULL, NULL);
+        return;
+    }
 
     lg(Debug) << "Queuing a HandleReferOperation";
-    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, target, session, mSessionRouter, mModule.id), inv);
+    enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, referredByVal, target, session, mSessionRouter, mAdapter, mReplicationContext, mModule.id), inv);
 }
 
 class HandleInfoDTMFOperation : public SipQueueableOperation
@@ -1402,9 +1160,9 @@ protected:
         {
             listener->end_indicated(asyncResult);
         }
-        catch (const Ice::Exception&)
+        catch (const Ice::Exception& ex)
         {
-            lg(Error) << "Ice exception when attempting to indicate something or other";
+            lg(Error) << "Ice exception when attempting to indicate something or other: " << ex.what();
         }
 
         return Complete;
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index b9a58b1..21e53df 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -376,8 +376,11 @@ std::string SipEndpoint::getId(const Ice::Current&)
     return mImplPriv->mEndpointProxy->ice_getIdentity().name;
 }
 
-AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(const std::string& destination,
-        const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current&)
+AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(
+        const std::string& destination,
+        const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
+        const Ice::Current&)
 {
 
     std::cout << "Got call over Ice to create a session for endpoint " << mImplPriv->mName << std::endl;
@@ -397,11 +400,22 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
 
     SessionCookies defaultCookies = mImplPriv->mDefaultSessionCookies->getAll();
 
-    SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, listeners, defaultCookies, mImplPriv->mManager,
-        mImplPriv->mServiceLocator, mImplPriv->mReplicationContext, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, 
-	true, mImplPriv->mConfig, NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
-        mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
-        mImplPriv->mConfig.transportConfig.enableNAT));
+    SipSessionPtr session = new SipSession(
+            mImplPriv->mAdapter,
+            this,
+            destination,
+            listeners,
+            defaultCookies,
+            mImplPriv->mManager,
+            mImplPriv->mServiceLocator,
+            mImplPriv->mReplicationContext,
+            oneShotHook,
+            mImplPriv->mConfig.sessionConfig.rtpOverIPv6,
+            true,
+            mImplPriv->mConfig,
+            NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
+                mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+                mImplPriv->mConfig.transportConfig.enableNAT));
 
     mImplPriv->mSessions.push_back(session);
     std::cout << "And now we're returing a session proxy..." << std::endl;
@@ -413,12 +427,22 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
     vector<SessionListenerPrx> defaultListeners = mImplPriv->mDefaultListeners->getAll();
     SessionCookies defaultCookies = mImplPriv->mDefaultSessionCookies->getAll();
 
-    SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, defaultListeners, defaultCookies, mImplPriv->mManager,
-        mImplPriv->mServiceLocator, mImplPriv->mReplicationContext, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, false, 
-	mImplPriv->mConfig, 
-	NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
-            mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
-            mImplPriv->mConfig.transportConfig.enableNAT)
+    SipSessionPtr session = new SipSession(
+            mImplPriv->mAdapter,
+            this,
+            destination,
+            defaultListeners,
+            defaultCookies,
+            mImplPriv->mManager,
+            mImplPriv->mServiceLocator,
+            mImplPriv->mReplicationContext,
+            0,
+            mImplPriv->mConfig.sessionConfig.rtpOverIPv6,
+            false,
+            mImplPriv->mConfig, 
+            NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, 
+                mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+                mImplPriv->mConfig.transportConfig.enableNAT)
         );
 
     mImplPriv->mSessions.push_back(session);
@@ -437,9 +461,24 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
                                                                          const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
                                                                          const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
 {
-    SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, controllerid, mediaid, mediasessions,
-            sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplicationContext, false, mImplPriv->mConfig,
-            NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+    SipSessionPtr session = new SipSession(
+            mImplPriv->mAdapter,
+            this,
+            destination,
+            sessionid,
+            controllerid,
+            mediaid,
+            mediasessions,
+            sources,
+            sinks,
+            mImplPriv->mManager,
+            mImplPriv->mServiceLocator,
+            mImplPriv->mReplicationContext,
+            0,
+            false,
+            mImplPriv->mConfig,
+            NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE,
+                mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
                 mImplPriv->mConfig.transportConfig.enableNAT));
     mImplPriv->mSessions.push_back(session);
     return session;
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 3480fba..80b9e2e 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -280,8 +280,11 @@ public:
      * Interface implementation.
      */
     std::string getId(const Ice::Current&);
-    AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(const std::string&,
-            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const Ice::Current&);
+    AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(
+            const std::string&,
+            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&,
+            const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+            const Ice::Current&);
     AsteriskSCF::SessionCommunications::V1::SessionSeq getSessions(const Ice::Current&);
     void addDefaultSessionListener(
         const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, 
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 0279d67..f550ce9 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -35,6 +35,7 @@
 #include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
 #include <AsteriskSCF/Media/SDP/MediaSDPIf.h>
 #include <AsteriskSCF/Media/RTP/MediaRTCPIf.h>
+#include <AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.h>
 #include "NATOptions.h"
 
 using namespace AsteriskSCF::System::Logging;
@@ -729,10 +730,8 @@ void SipSession::initializePJSIPStructs()
 
 void SipSession::activateIceObjects(const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq& hooks)
 {
-    mImplPriv->mSessionProxy = 
-        AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(mImplPriv->mAdapter->addWithUUID(this));
-
-    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookDataPtr initial(new AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookData(mImplPriv->mSessionProxy, mImplPriv->mListeners));
+    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookDataPtr initial(
+            new AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookData(mImplPriv->mSessionProxy, mImplPriv->mListeners, getCookies()));
 
     AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookDataPtr in = initial;
 
@@ -758,6 +757,11 @@ void SipSession::activateIceObjects(const AsteriskSCF::SessionCommunications::Ex
             mImplPriv->mPublicSessionProxy = out->session;
             mImplPriv->mListeners.clear();
             mImplPriv->mListeners = out->listeners;
+            // Note this is the setCookies method
+            // typically called from a queued operation.
+            // It's safe to do here since the session is
+            // in the process of being created.
+            setCookies(out->cookies);
             in = out;
         }
     }
@@ -783,10 +787,11 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
         const SipEndpointPtr& endpoint,
         const std::string& destination, 
         const vector<SessionListenerPrx>& listeners,
-        const SessionCookies& cookies,
+        const AsteriskSCF::SessionCommunications::V1::SessionCookies& cookies, 
         const PJSipManagerPtr& manager, 
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const SipReplicationContextPtr& replicationContext, 
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
         bool /* ipv6 */, 
         bool isUAC, 
         const SipEndpointConfig &config,
@@ -795,12 +800,13 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
 {
     mImplPriv->mListeners.insert(mImplPriv->mListeners.end(), listeners.begin(), listeners.end());
 
-    for(SessionCookies::const_iterator i = cookies.begin(); i != cookies.end(); ++i)
+    for (AsteriskSCF::SessionCommunications::V1::SessionCookies::const_iterator i = cookies.begin(); i != cookies.end(); ++i)
     {
         mImplPriv->mSessionCookies[(*i)->ice_id()] = (*i);
     }
 
-    activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
+    mImplPriv->mSessionProxy = 
+        AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(mImplPriv->mAdapter->addWithUUID(this));
 
     mImplPriv->mMediaSession = new SipMediaSession(this);
     mImplPriv->mMediaSessionProxy =
@@ -816,23 +822,39 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
         initializePJSIPStructs();
         setTelephonyEventSourcesAndSinks(config);
     }
+
+    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
+        mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
+    if (oneShotHook)
+    {
+        hooks.push_back(oneShotHook);
+    }
+    activateIceObjects(hooks);
 }
 
 /**
  * Replica constructor.
  */
-SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
+SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
+                       const SipEndpointPtr& endpoint,
                        const std::string& destination, 
                        const Ice::Identity& /* sessionid */,
                        const Ice::Identity& controllerid,
-                       const Ice::Identity& mediaid, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
-                       const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
-                       const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
-                       const SipReplicationContextPtr& replicationContext, bool isUAC, const SipEndpointConfig &config,
+                       const Ice::Identity& mediaid,
+                       const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
+                       const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
+                       const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
+                       const PJSipManagerPtr& manager,
+                       const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+                       const SipReplicationContextPtr& replicationContext,
+                       const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
+                       bool isUAC,
+                       const SipEndpointConfig &config,
                        const NATEndpointOptions& natOptions)
     : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replicationContext, natOptions))
 {
-    activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
+    mImplPriv->mSessionProxy = 
+        AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(mImplPriv->mAdapter->addWithUUID(this));
 
     mImplPriv->mMediaSession = new SipMediaSession(this);
     mImplPriv->mMediaSessionProxy =
@@ -851,6 +873,14 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
         initializePJSIPStructs();
         setTelephonyEventSourcesAndSinks(config);
     }
+
+    AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
+        mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
+    if (oneShotHook)
+    {
+        hooks.push_back(oneShotHook);
+    }
+    activateIceObjects(hooks);
 }
 
 class AddListenerOperation : public SuspendableWork
@@ -1374,12 +1404,49 @@ public:
             return Complete;
         }
 
+        addReferredBy(packet);
+
         // Boom! Houston, we have transmission.
         pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
         return Complete;
     }
 
 private:
+    /**
+     * If this session is being started as the result of
+     * a transfer, there may be a Referred-By header to
+     * include.
+     */
+    void addReferredBy(pjsip_tx_data *packet)
+    {
+        AsteriskSCF::SessionCommunications::V1::SessionCookieDict::const_iterator iter =
+            mImplPriv->mSessionCookies.find(AsteriskSCF::SessionCookies::SipSessionManager::V1::ReferredByCookie::ice_staticId());
+
+        if (iter == mImplPriv->mSessionCookies.end())
+        {
+            lg(Debug) << "No ReferredBy cookie present";
+            return;
+        }
+
+        AsteriskSCF::SessionCookies::SipSessionManager::V1::ReferredByCookiePtr referredBy = 
+            AsteriskSCF::SessionCookies::SipSessionManager::V1::ReferredByCookiePtr::dynamicCast(iter->second);
+
+        if (referredBy->value.empty())
+        {
+            lg(Debug) << "Referred-By is empty.";
+            return;
+        }
+
+        pj_str_t referredByHdrStr;
+        pj_cstr(&referredByHdrStr, "Referred-By");
+        pj_str_t referredByValStr;
+        pj_cstr(&referredByValStr, referredBy->value.c_str());
+
+        pjsip_generic_string_hdr *hdr =
+            pjsip_generic_string_hdr_create(packet->pool, &referredByHdrStr, &referredByValStr);
+
+        pjsip_msg_add_hdr(packet->msg, (pjsip_hdr*) hdr);
+    }
     SipSessionPtr mSession;
     boost::shared_ptr<SipSessionPriv> mImplPriv;
 };
@@ -1444,32 +1511,18 @@ class SetCookiesOperation : public SuspendableWork
 {
 public:
     SetCookiesOperation(const AsteriskSCF::SessionCommunications::V1::SessionCookies& cookies,
-                        const boost::shared_ptr<SipSessionPriv>& sessionPriv)
-        : mCookies(cookies), mImplPriv(sessionPriv) { }
+                        const SipSessionPtr& session)
+        : mCookies(cookies), mSession(session) { }
 
     SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
     {
-        for (AsteriskSCF::SessionCommunications::V1::SessionCookies::const_iterator i = mCookies.begin();
-             i != mCookies.end();
-             ++i)
-        {
-            mImplPriv->mSessionCookies.erase((*i)->ice_id());
-            mImplPriv->mSessionCookies.insert(make_pair((*i)->ice_id(), (*i)));
-        }
-
-        if (mImplPriv->mInviteSession)
-        {
-            PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo*>(mImplPriv->mInviteSession->mod_data[mImplPriv->mManager->getSessionModule()->getModule().id]);
-            session_mod_info->updateSessionState(mImplPriv->mInviteSession);
-            mImplPriv->mManager->getSessionModule()->replicateState(NULL, NULL, session_mod_info);
-        }
-
+        mSession->setCookies(mCookies);
         return Complete;
     }
 
 private:
     AsteriskSCF::SessionCommunications::V1::SessionCookies mCookies;
-    boost::shared_ptr<SipSessionPriv> mImplPriv;
+    SipSessionPtr mSession;
 };
 
 /**
@@ -1479,7 +1532,28 @@ private:
 void SipSession::setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies& cookies, const Ice::Current&)
 {
     lg(Debug) << "queuing a setCookies operation";
-    enqueueSessionWork(new SetCookiesOperation(cookies, mImplPriv));
+    enqueueSessionWork(new SetCookiesOperation(cookies, this));
+}
+
+/**
+ * Typically called from queued operations
+ */
+void SipSession::setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies& cookies)
+{
+   for (AsteriskSCF::SessionCommunications::V1::SessionCookies::const_iterator i = cookies.begin();
+        i != cookies.end();
+        ++i)
+   {
+       mImplPriv->mSessionCookies.erase((*i)->ice_id());
+       mImplPriv->mSessionCookies.insert(make_pair((*i)->ice_id(), (*i)));
+   }
+
+   if (mImplPriv->mInviteSession)
+   {
+       PJSipSessionModInfo *session_mod_info = static_cast<PJSipSessionModInfo*>(mImplPriv->mInviteSession->mod_data[mImplPriv->mManager->getSessionModule()->getModule().id]);
+       session_mod_info->updateSessionState(mImplPriv->mInviteSession);
+       mImplPriv->mManager->getSessionModule()->replicateState(NULL, NULL, session_mod_info);
+   }
 }
 
 /**
@@ -2692,7 +2766,7 @@ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& SipSession::getSes
 /**
  * Internal function which sets the listeners explicitly.
  */
-void SipSession::setListeners(const SessionListenerSeq& listeners)
+void SipSession::setListeners(const AsteriskSCF::SessionCommunications::V1::SessionListenerSeq& listeners)
 {
     mImplPriv->mListeners = listeners;
 }
diff --git a/src/SipSession.h b/src/SipSession.h
index e3ebff1..8da0248 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -110,20 +110,36 @@ class SipEndpointConfig;
 class SipSession : public AsteriskSCF::SessionCommunications::V1::TelephonySession
 {
 public:
-    SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&,
+    SipSession(const Ice::ObjectAdapterPtr&,
+        const SipEndpointPtr&,
+        const std::string&,
         const std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>&,         
         const AsteriskSCF::SessionCommunications::V1::SessionCookies&, 
         const PJSipManagerPtr& manager,
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const SipReplicationContextPtr& replicationContext,
-        bool ipv6, bool isUAC, const SipEndpointConfig& config, const NATEndpointOptions& natOptions);
-
-    SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&, const Ice::Identity&,
-        const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq&,
-        const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
-        const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        bool ipv6,
+        bool isUAC,
+        const SipEndpointConfig& config,
+        const NATEndpointOptions& natOptions);
+
+    SipSession(const Ice::ObjectAdapterPtr&,
+        const SipEndpointPtr&,
+        const std::string&,
+        const Ice::Identity&,
+        const Ice::Identity&,
+        const Ice::Identity&,
+        const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq&,
+        const AsteriskSCF::Media::V1::StreamSourceSeq&,
+        const AsteriskSCF::Media::V1::StreamSinkSeq&,
+        const PJSipManagerPtr& manager,
+        const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
         const SipReplicationContextPtr& replicationContext,
-        bool isUAC, const SipEndpointConfig& config, const NATEndpointOptions& natOptions);
+        const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx&,
+        bool isUAC,
+        const SipEndpointConfig& config,
+        const NATEndpointOptions& natOptions);
 
     bool operator==(const SipSession &other) const;
 
@@ -183,6 +199,15 @@ public:
     void stop(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr&, const Ice::Current&);
     void unhold(const Ice::Current&);
     void setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&);
+    /**
+     * Typically called from queued operations to set cookies.
+     * Also used during session creation when modifications hooks have changed
+     * the cookies
+     */
+    void setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&);
+    /**
+     * Used during replication
+     */
     void setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookieDict&);
     void removeCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&);
     AsteriskSCF::SessionCommunications::V1::SessionCookies getCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&);
@@ -280,7 +305,7 @@ public:
 
     AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& getSessionControllerProxy();
 
-    void setListeners(const AsteriskSCF::Replication::SipSessionManager::V1::SessionListenerSeq&);
+    void setListeners(const AsteriskSCF::SessionCommunications::V1::SessionListenerSeq&);
 
     void setStreams(const AsteriskSCF::Media::V1::StreamInformationDict& streams);
 
diff --git a/src/SipSessionManagerApp.cpp b/src/SipSessionManagerApp.cpp
new file mode 100644
index 0000000..39f9b74
--- /dev/null
+++ b/src/SipSessionManagerApp.cpp
@@ -0,0 +1,709 @@
+/*
+ * 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 <pjlib.h>
+
+#include <Ice/Ice.h>
+#include <IceStorm/IceStorm.h>
+#include <IceBox/IceBox.h>
+#include <IceUtil/UUID.h>
+
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <AsteriskSCF/Core/Routing/RoutingIf.h>
+#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
+#include <AsteriskSCF/System/Component/ComponentServiceIf.h>
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include <AsteriskSCF/System/Component/ReplicaIf.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
+#include <AsteriskSCF/System/Component/ConfigurationIf.h>
+
+#include <AsteriskSCF/Logger/IceLogger.h>
+#include <AsteriskSCF/logger.h>
+
+#include "SipSessionManagerEventPublisher.h"
+#include "SipSessionManagerEndpointLocator.h"
+#include "SipEndpointFactory.h"
+#include "PJSipSessionModule.h"
+#include "PJSipManager.h"
+#include "SipSession.h"
+#include "SipStateReplicator.h"
+#include "SipConfiguration.h"
+#include "SipRegistrarListener.h"
+
+using namespace std;
+using namespace AsteriskSCF::SipSessionManager;
+using namespace AsteriskSCF::Configuration::SipSessionManager::V1;
+using namespace AsteriskSCF::Core;
+using namespace AsteriskSCF::Core::Routing::V1;
+using namespace AsteriskSCF::Core::Discovery::V1;
+using namespace AsteriskSCF::System::Component::V1;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::Hook::V1;
+using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::SIP::ExtensionPoint::V1;
+using namespace AsteriskSCF::System::Configuration::V1;
+using namespace AsteriskSCF::SIP::Registration::V1;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.SipSessionManager");
+}
+
+namespace AsteriskSCF
+{
+namespace SipSessionManager
+{
+
+class SipAuthExtensionPoint : public AuthExtensionPoint
+{
+public:
+    SipAuthExtensionPoint(const PJSipManagerPtr& manager)
+        : mPJSipManager(manager)
+    {
+    }
+    
+    void addAuthHook(
+            const AuthHookPrx &hook,
+            int priority,
+            const RequestTypeSeq &requestTypes,
+            const Ice::Current&)
+    {
+        mPJSipManager->addAuthHook(hook, priority, requestTypes);
+    }
+    
+    void removeAuthHook(const AuthHookPrx &hook, const Ice::Current&)
+    {
+        mPJSipManager->removeAuthHook(hook);
+    }
+    
+    void clearAuthHooks(const Ice::Current&)
+    {
+        mPJSipManager->clearAuthHooks();
+    }
+private:
+    PJSipManagerPtr mPJSipManager;
+};
+
+typedef IceUtil::Handle<SipAuthExtensionPoint> SipAuthExtensionPointPtr;
+
+/**
+ * This private class initializes the startup and controls the shutdown of the component.
+ */
+class SipSessionManager : public IceBox::Service
+{
+public:
+    SipSessionManager() : mDone(false) {}
+    ~SipSessionManager() { }
+
+public:
+    // Overloads of IceBox::Service
+    virtual void start(const string& name, const Ice::CommunicatorPtr& ic, const Ice::StringSeq& args);
+    virtual void stop();
+
+private:
+    void initialize(const string& appName, const Ice::CommunicatorPtr& ic);
+    void registerWithServiceLocator();
+    void deregisterFromServiceLocator();
+    void setCategory(const ServiceManagementPrx& serviceManagement, const string &category);
+    void locateRoutingService();
+    void locateSessionRouter();
+    void locateStateReplicator();
+    void registerWithStateReplicator();
+    void registerWithRoutingService();
+    void deregisterFromRoutingService();
+    void registerPJSipModules();
+    void deregisterFromStateReplicator();
+
+    bool mDone;
+    std::string mAppName;
+    Ice::CommunicatorPtr mCommunicator;
+
+    std::string mRoutingId;
+
+    // The global object adapter is for shared services that could be replicated from another server
+    Ice::ObjectAdapterPtr mGlobalAdapter;
+
+    // The local object adapter is for services unique to this instance of the service
+    Ice::ObjectAdapterPtr mLocalAdapter;
+
+    ServiceLocatorManagementPrx mServiceLocatorManagement;
+
+    ServiceManagementPrx mComponentServiceManagement;
+    ServiceManagementPrx mConfigurationManagement;
+    ServiceManagementPrx mAuthServiceManagement;
+    std::string mConfigCompareGuid;
+    ReplicaPtr mReplicaService;
+    ComponentServicePtr mComponentService;
+    ConfigurationServicePtr mConfigurationService;
+    ConfigurationServicePrx mConfigurationServiceProxy;
+    PJSipManagerPtr mPJSipManager;
+    SipStateReplicatorListenerPtr mReplicatorListener;
+    SipStateReplicatorListenerPrx mReplicatorListenerProxy;
+    boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
+    ServiceLocatorPrx mServiceLocator;
+    AsteriskSCF::Discovery::SmartProxy<SipStateReplicatorPrx> mStateReplicator;
+    AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> mSessionRouter;
+    AsteriskSCF::Discovery::SmartProxy<LocatorRegistryPrx> mRoutingServiceLocatorRegistry;
+    boost::shared_ptr<SipSessionManagerEventPublisher> mEventPublisher;
+    Routing::V1::EndpointLocatorPtr mEndpointLocator;
+    SipAuthExtensionPointPtr mAuthService;
+    RegistrarListenerPtr mRegistrarListener;
+};
+
+static const string ComponentServiceId("SipChannelComponent");
+static const string EndpointLocatorObjectId("SipChannelEndpointLocator");
+static const string ReplicaServiceId("SipChannelReplica");
+static const string AuthServiceId("SipAuthExtensionPoint");
+static const string RegistrarListenerId("SipRegistrarListener");
+
+/**
+ * This class provides implementation for the ComponentService interface, which
+ * every Asterisk SCF component is expected to publish.
+ */
+class ComponentServiceImpl : public ComponentService
+{
+public:
+    ComponentServiceImpl(SipSessionManager &service) : mService(service) {}
+
+public: // Overrides of the ComponentService interface.
+    virtual void suspend(const ::Ice::Current& = ::Ice::Current())
+    {
+        // TBD
+    }
+
+    virtual void resume(const ::Ice::Current& = ::Ice::Current())
+    {
+        // TBD
+    }
+
+    virtual void shutdown(const ::Ice::Current& = ::Ice::Current())
+    {
+        // TBD
+    }
+
+private:
+    SipSessionManager& mService; // TODO reference?
+};
+
+/**
+ * This class provides implementation for the Replica interface.
+ */
+class ReplicaImpl : public Replica
+{
+public:
+    ReplicaImpl(const Ice::ObjectAdapterPtr& adapter) : mAdapter(adapter), mPaused(false), mActive(true) { }
+
+    bool isActive(const Ice::Current&)
+    {
+        return mActive;
+    }
+
+    bool activate(const Ice::Current&)
+    {
+        mActive = true;
+
+        for (vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx>::const_iterator listener =
+                 mListeners.begin(); listener != mListeners.end(); ++listener)
+        {
+            (*listener)->activated(ReplicaPrx::uncheckedCast(
+                        mAdapter->createDirectProxy(mAdapter->getCommunicator()->stringToIdentity(ReplicaServiceId))));
+        }
+
+        return true;
+    }
+
+    void standby(const Ice::Current&)
+    {
+        mActive = false;
+
+        for (vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx>::const_iterator listener =
+                 mListeners.begin(); listener != mListeners.end(); ++listener)
+        {
+            (*listener)->onStandby(ReplicaPrx::uncheckedCast(
+                        mAdapter->createDirectProxy(mAdapter->getCommunicator()->stringToIdentity(ReplicaServiceId))));
+        }
+    }
+
+    void addListener(const AsteriskSCF::System::Component::V1::ReplicaListenerPrx& listener, const Ice::Current&)
+    {
+        mListeners.push_back(listener);
+    }
+
+    void removeListener(const AsteriskSCF::System::Component::V1::ReplicaListenerPrx& listener, const Ice::Current&)
+    {
+        mListeners.erase(std::remove(mListeners.begin(), mListeners.end(), listener), mListeners.end());
+    }
+
+private:
+    /**
+     * Pointer to the object adapter we exist on.
+     */
+    Ice::ObjectAdapterPtr mAdapter;
+
+    /**
+     * Listeners that we need to push state change notifications out to.
+     */
+    vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx> mListeners;
+
+    bool mPaused;
+
+    bool mActive;
+};
+
+/**
+ * Comparator implementation for name based configuration service locating
+ */
+class SipConfigurationCompare : public ServiceLocatorParamsCompare
+{
+public:
+    SipConfigurationCompare(const string& name) : mName(name) {}
+    bool isSupported(const ServiceLocatorParamsPtr &params, const Ice::Current &)
+    {
+        SipConfigurationParamsPtr configParams = SipConfigurationParamsPtr::dynamicCast(params);
+        if (configParams->name == mName)
+        {
+            return true;
+        }
+        return false;
+    }
+private:
+    string mName;
+};
+
+typedef IceUtil::Handle<SipConfigurationCompare> SipConfigurationComparePtr;
+
+/**
+ * Helper function to add some parameters to one of our registered interfaces in the ServiceLocator, so that
+ * other components can look up our interfaces.
+ */
+void SipSessionManager::setCategory(const ServiceManagementPrx& serviceManagement, const string &category)
+{
+    // Add category as a parameter to enable other components look this component up.
+    ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
+    genericparams->category = category;
+    serviceManagement->addLocatorParams(genericparams, "");
+}
+
+/**
+ * Register this component's primary public interfaces with the Service Locator.
+ * This enables other Asterisk SCF components to locate our interfaces.
+ */
+void SipSessionManager::registerWithServiceLocator()
+{
+    try
+    {
+        // Get a proxy to the management interface for the Service Locator, so we can add ourselves into the system
+        // discovery mechanisms.
+        mServiceLocatorManagement = ServiceLocatorManagementPrx::checkedCast(
+            mCommunicator->propertyToProxy("LocatorServiceManagement.Proxy"));
+
+        if (mServiceLocatorManagement == 0)
+        {
+            lg(Error) << "Unable to obtain proxy to ServiceLocatorManagement interface. Check config file. This component can't be found until this is corrected.";
+            return;
+        }
+
+        // Get a proxy to our ComponentService interface and add it to the Service Locator.
+        Ice::ObjectPrx componentServiceObjectPrx =
+            mLocalAdapter->createDirectProxy(mCommunicator->stringToIdentity(ComponentServiceId));
+        ComponentServicePrx componentServicePrx = ComponentServicePrx::checkedCast(componentServiceObjectPrx);
+
+        // The GUID passed in to add service needs to be unique for reporting.
+        string componentServiceGuid("SipSessionManager");
+        mComponentServiceManagement = ServiceManagementPrx::uncheckedCast(
+            mServiceLocatorManagement->addService(componentServicePrx, componentServiceGuid));
+
+        setCategory(mComponentServiceManagement, AsteriskSCF::SIP::V1::ComponentServiceDiscoveryCategory);
+
+        // Hey look we have an Auth extension point to publish!
+        Ice::ObjectPrx authObjPrx = mLocalAdapter->createDirectProxy(mCommunicator->stringToIdentity(AuthServiceId));
+        AuthExtensionPointPrx authPrx = AuthExtensionPointPrx::checkedCast(authObjPrx);
+
+        std::string authServiceGuid("SipAuthExtensionPoint");
+        mAuthServiceManagement = ServiceManagementPrx::uncheckedCast(mServiceLocatorManagement->addService(authPrx, authServiceGuid));
+        setCategory(mAuthServiceManagement, AsteriskSCF::SIP::V1::AuthExtensionPointCategory);
+        if (mCommunicator->getProperties()->getPropertyWithDefault("Sip.Standalone", "false") == "true")
+        {
+            // Publish the configuration service IceStorm topic so everybody gets configuration
+            mConfigurationManagement = ServiceManagementPrx::uncheckedCast(
+        	mServiceLocatorManagement->addService(mConfigurationServiceProxy, ""));
+        
+            // Populate the configuration parameters with details so we can be found
+            SipConfigurationParamsPtr configurationParams = new SipConfigurationParams();
+            configurationParams->category = ConfigurationDiscoveryCategory;
+            configurationParams->name = mCommunicator->getProperties()->getPropertyWithDefault("SipConfiguration.Name", "");
+        
+            // Add our custom comparator so we can support multiple simultaneous configuration sinks
+            SipConfigurationComparePtr configNameCompare = new SipConfigurationCompare(configurationParams->name);
+            ServiceLocatorParamsComparePrx configCompareProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
+        	mLocalAdapter->addWithUUID(configNameCompare));
+        
+            mConfigCompareGuid = IceUtil::generateUUID();
+            mServiceLocatorManagement->addCompare(mConfigCompareGuid, configCompareProxy);
+            mConfigurationManagement->addLocatorParams(configurationParams, mConfigCompareGuid);
+        }
+
+        // TBD... We may have other interfaces to publish to the Service Locator.
+    }
+    catch(...)
+    {
+        lg(Error) << "Exception in " << mAppName << " registerWithServiceLocator()";
+    }
+}
+
+/**
+ * Register our own Endpoint Locator with the Routing Service so that
+ * the endpoints that this channel manages can be accessed from any
+ * Session Manager in the Asterisk SCF system.
+ */
+void SipSessionManager::registerWithRoutingService()
+{
+    RegExSeq destinations;
+
+    mEndpointFactory->generateRoutingDestinations(destinations);
+
+    EndpointLocatorPrx locator = EndpointLocatorPrx::uncheckedCast(
+        mGlobalAdapter->createDirectProxy(mCommunicator->stringToIdentity(EndpointLocatorObjectId)));
+    mRoutingServiceLocatorRegistry->addEndpointLocator(mRoutingId, destinations, locator);
+}
+
+/**
+ * Deregister our own Endpoint Locator from the Routing SErvice.
+ */
+void SipSessionManager::deregisterFromRoutingService()
+{
+    mRoutingServiceLocatorRegistry->removeEndpointLocator(mRoutingId);
+}
+
+/**
+ * Get a reference to the Routing Service interface that we care about, and cache it in the Data Model.
+ * This will allow us to lookup endpoints anywhere in the Asterisk SCF system.
+ */
+void SipSessionManager::locateRoutingService()
+{
+    if (mServiceLocator == 0)
+    {
+        mServiceLocator = ServiceLocatorPrx::checkedCast(mCommunicator->propertyToProxy("LocatorService.Proxy"));
+    }
+
+    ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
+    genericparams->category = Routing::V1::RoutingServiceLocatorRegistryDiscoveryCategory;
+
+    AsteriskSCF::Discovery::SmartProxy<LocatorRegistryPrx> pw(mServiceLocator, genericparams, lg);
+    mRoutingServiceLocatorRegistry = pw;
+
+    // This exists here since it may need to be known before actually contacting the routing service
+    mRoutingId = mCommunicator->getProperties()->getPropertyWithDefault("Sip.RoutingId", "pjsip");
+}
+
+void SipSessionManager::locateStateReplicator()
+{
+    if (mServiceLocator == 0)
+    {
+        mServiceLocator = ServiceLocatorPrx::checkedCast(mCommunicator->propertyToProxy("LocatorService.Proxy"));
+    }
+
+    SipStateReplicatorParamsPtr replicatorParams = new SipStateReplicatorParams();
+    replicatorParams->category = StateReplicatorDiscoveryCategory;
+    replicatorParams->mName =
+        mCommunicator->getProperties()->getPropertyWithDefault("Sip.StateReplicatorName", "default");
+
+    try
+    {
+        AsteriskSCF::Discovery::SmartProxy<SipStateReplicatorPrx> pw(mServiceLocator, replicatorParams, lg);
+        mStateReplicator = pw;
+    }
+    catch (...)
+    {
+        lg(Error) << "State replicator could not be found, operating without.";
+    }
+}
+
+void SipSessionManager::registerWithStateReplicator()
+{
+    if (mStateReplicator == 0)
+    {
+        return;
+    }
+
+    if (mCommunicator->getProperties()->getPropertyWithDefault("Sip.Standalone", "false") == "false")
+    {
+	ConfigurationReplicatorPrx configurationReplicator = ConfigurationReplicatorPrx::checkedCast(
+	    mStateReplicator.initialize(), ReplicatorFacet);
+	configurationReplicator->registerConfigurationService(mConfigurationServiceProxy);
+    }
+
+    if (mCommunicator->getProperties()->getPropertyWithDefault("Sip.StateReplicatorListener", "no") == "yes")
+    {
+        mStateReplicator->addListener(mReplicatorListenerProxy);
+        mReplicaService->standby();
+    }
+}
+
+/**
+ * Get a reference to the Session Routing Service interface that we care about, and cache it in the Data Model.
+ * This will allow us to route sessions.
+ */
+void SipSessionManager::locateSessionRouter()
+{
+    if (mServiceLocator == 0)
+    {
+        mServiceLocator = ServiceLocatorPrx::checkedCast(mCommunicator->propertyToProxy("LocatorService.Proxy"));
+    }
+
+    ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
+    genericparams->category = Routing::V1::SessionRouterDiscoveryCategory;
+
+    AsteriskSCF::Discovery::SmartProxy<SessionRouterPrx> pw(mServiceLocator, genericparams, lg);
+    mSessionRouter = pw;
+}
+
+/**
+ * Deregister this component's primary public interfaces from the Service Locator.
+ * This is done at shutdown, and whenever we want to keep other services from locating
+ * our interfaces.
+ */
+void SipSessionManager::deregisterFromServiceLocator()
+{
+    try
+    {
+        mComponentServiceManagement->unregister();
+	if (mConfigurationManagement)
+	{
+	    mConfigurationManagement->unregister();
+	}
+    }
+    catch(...)
+    {
+        lg(Error) << "Had trouble in deregisterFromServiceLocator().";
+    }
+}
+
+void SipSessionManager::registerPJSipModules()
+{
+    Ice::PropertiesPtr props = mCommunicator->getProperties();
+    Ice::StringSeq moduleNames = props->getPropertyAsList("Sip.Modules");
+    for (Ice::StringSeq::iterator i = moduleNames.begin();
+         i != moduleNames.end();
+         ++i)
+    {
+        //We should probably delegate the responsibility of mapping
+        //module names to modules to the PJSIP session manager instead.
+        //Since there's only a single configurable module at the moment,
+        //we'll just do it here instead.
+        if (*i == "Session")
+        {
+            mPJSipManager->registerSessionModule(mEndpointFactory,
+                mSessionRouter, mServiceLocator, mStateReplicator, mReplicaService, mGlobalAdapter, mServiceLocatorManagement);
+        }
+        else if (*i == "Logging" || *i == "Logger")
+        {
+            mPJSipManager->registerLoggingModule();
+        }
+        else if (*i == "Registrar")
+        {
+            RegistrarListenerPrx defaultListener = RegistrarListenerPrx::uncheckedCast(
+                    mGlobalAdapter->createDirectProxy(mGlobalAdapter->getCommunicator()->stringToIdentity(RegistrarListenerId)));
+            if (defaultListener == 0)
+            {
+                lg(Warning) << "Adding NULL RegistrarListener as default listener????" << std::endl;
+            }
+            mPJSipManager->registerRegistrarModule(defaultListener, mStateReplicator, mGlobalAdapter);
+        }
+    }
+    lg(Debug) << "Registered PJSIP modules";
+}
+
+void SipSessionManager::deregisterFromStateReplicator()
+{
+    if (!mConfigCompareGuid.empty())
+    {
+        mServiceLocatorManagement->removeCompare(mConfigCompareGuid);
+    }
+
+    if (mConfigurationManagement)
+    {
+	mConfigurationManagement->unregister();
+    }
+
+    if (mReplicaService->isActive() == true)
+    {
+        return;
+    }
+
+    mStateReplicator->removeListener(mReplicatorListenerProxy);
+}
+
+/**
+ * Create the primary functional objects of this component.
+ *   @param appName Name of the application or component.
+ */
+void SipSessionManager::initialize(const string& appName, const Ice::CommunicatorPtr& ic)
+{
+    try
+    {
+        mAppName = appName;
+
+        // Initialize PJSIP
+        mPJSipManager = PJSipManager::create(ic->getProperties());
+        lg(Debug) << "Created PJSIP manager";
+
+        //As nice as it is of IceBox to provide us with a communicator,
+        //we're going to create our own so that we can provide it with a threadhook.
+        //Yes, this could be done via a plugin, but this is easier. Go away.
+        Ice::InitializationData id;
+        id.threadHook = new pjlibHook();
+        id.properties = ic->getProperties();
+
+        mCommunicator = Ice::initialize(id);
+
+        // Create the global adapter.
+        mGlobalAdapter = mCommunicator->createObjectAdapter("SipSessionManagerAdapter");
+        lg(Debug) << "Created global object adapter";
+
+        // Create the local adapter.
+        mLocalAdapter = mCommunicator->createObjectAdapter("SipSessionManagerLocalAdapter");
+        lg(Debug) << "Created local object adapter";
+
+        mEventPublisher.reset(new SipSessionManagerEventPublisher(mLocalAdapter));
+        lg(Debug) << "Created SIP Session Manager event publisher";
+
+        // We're not actually registering with the service locator at this point, but
+        // several components we create could really use the proxy, so we create
+        // it now.
+        mServiceLocator = ServiceLocatorPrx::checkedCast(mCommunicator->propertyToProxy("LocatorService.Proxy"));
+
+        // Create and publish our Replica interface support.
+        mReplicaService = new ReplicaImpl(mLocalAdapter);
+        mLocalAdapter->add(mReplicaService, mCommunicator->stringToIdentity(ReplicaServiceId));
+        lg(Debug) << "Created SIP Replica Implementation";
+
+        mEndpointFactory.reset(new SipEndpointFactory(mGlobalAdapter, mPJSipManager, mServiceLocator, mReplicaService));
+        lg(Debug) << "Created SIP endpoint factory";
+
+        mRegistrarListener = new SipDefaultRegistrarListener(mEndpointFactory);
+        mGlobalAdapter->add(mRegistrarListener, mCommunicator->stringToIdentity(RegistrarListenerId));
+        lg(Debug) << "Added default registrar listener to object adapter";
+
+	// Locate the Routing Service so that we can do routing. This is done here so it can be passed to the configuration service.
+	locateRoutingService();
+
+        // Create and publish our Configuration interface support.
+        mConfigurationService = createConfigurationServant(mPJSipManager, mEndpointFactory, mRoutingId, mRoutingServiceLocatorRegistry);
+        mConfigurationServiceProxy = ConfigurationServicePrx::uncheckedCast(mLocalAdapter->addWithUUID(
+		mConfigurationService));
+        lg(Debug) << "Created SIP Configuration Implementation";
+
+        // Create and configure our Endpoint Locator.
+        mEndpointLocator = new SipSessionManagerEndpointLocator(mEndpointFactory);
+        mGlobalAdapter->add(mEndpointLocator, mCommunicator->stringToIdentity(EndpointLocatorObjectId));
+        lg(Debug) << "Got proxy to endpoint locator";
+
+        // Create and publish our ComponentService interface support.
+        mComponentService = new ComponentServiceImpl(*this);
+        mLocalAdapter->add(mComponentService, mCommunicator->stringToIdentity(ComponentServiceId));
+        lg(Debug) << "Added component service to object adapter";
+
+        // Create and publish our AuthExtensionPoint
+        mAuthService = new SipAuthExtensionPoint(mPJSipManager);
+        mLocalAdapter->add(mAuthService, mCommunicator->stringToIdentity(AuthServiceId));
+        lg(Debug) << "Added Auth extension point to object adapter";
+
+        // Create and publish our state replicator listener interface.
+        mReplicatorListener = new SipStateReplicatorListenerI(mEndpointFactory, mPJSipManager, mGlobalAdapter, mStateReplicator);
+        mReplicatorListenerProxy =
+            SipStateReplicatorListenerPrx::uncheckedCast(mLocalAdapter->addWithUUID(mReplicatorListener));
+        lg(Debug) << "Got proxy to SIP state replicator";
+
+        mGlobalAdapter->activate();
+        mLocalAdapter->activate();
+        lg(Debug) << "Activated object adapters";
+    } 
+    catch (const std::exception& ex)
+    {
+        lg(Critical) << "Major problems in " << mAppName << " initialization(): " << ex.what();
+    }
+    catch(...)
+    {
+        lg(Critical) << "Major problems in " << mAppName << " initialization()";
+    }
+}
+
+/**
+ * Overload of the IceBox::Service::start method.
+ */
+void SipSessionManager::start(const string& name, const Ice::CommunicatorPtr& ic, const Ice::StringSeq&)
+{
+    // Initialize this component.
+    initialize(name, ic);
+
+    // Plug into the Asterisk SCF discovery system so that the interfaces we provide
+    // can be located.
+    registerWithServiceLocator();
+
+    // Locate the Session Router so we can REALLY do routing.
+    locateSessionRouter();
+
+    // Locate the State Replicator so we can fail over!
+    locateStateReplicator();
+
+    registerPJSipModules();
+
+    // Register with the state replicator if we are a listener
+    registerWithStateReplicator();
+
+    // Register our Endpoint Locator so that we can provide endpoints to the
+    // Routing Service for the endpoints we manage.
+    if (mCommunicator->getProperties()->getPropertyWithDefault("Sip.StateReplicatorListener", "no") != "yes")
+    {
+        //Only register with the routing service if we're the primary SIP instance.
+        registerWithRoutingService();
+    }
+}
+
+/**
+ * Overload of the IceBox::Service::stop method.
+ */
+void SipSessionManager::stop()
+{
+    // Remove our interfaces from the service locator.
+    deregisterFromServiceLocator();
+
+    // Remove our endpoint locator from the routing service.
+    deregisterFromRoutingService();
+
+    // Remove our state listener
+    deregisterFromStateReplicator();
+
+    //
+    // TODO: This is probably a mistake. Many things access the PJSipManager instance and will continue
+    // to do so until all of the threads have completed. It really should be reference counted.
+    //
+    mCommunicator->destroy();
+}
+
+extern "C"
+{
+ASTSCF_DLL_EXPORT IceBox::Service* create(Ice::CommunicatorPtr)
+{
+    return new SipSessionManager;
+}
+}
+
+}; // end SipSessionManager
+}; // end AsteriskSCF
diff --git a/src/SipStateReplicator.h b/src/SipStateReplicator.h
index d53bc81..0032aff 100644
--- a/src/SipStateReplicator.h
+++ b/src/SipStateReplicator.h
@@ -19,6 +19,8 @@
 #include "SipEndpointFactory.h"
 #include <Ice/Ice.h>
 #include <AsteriskSCF/Replication/StateReplicator.h>
+#include <AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
 #include <SipStateReplicationIf.h>
 
 #include <boost/shared_ptr.hpp>
@@ -42,7 +44,11 @@ struct SipStateReplicatorListenerImpl;
 class SipStateReplicatorListenerI : public AsteriskSCF::Replication::SipSessionManager::V1::SipStateReplicatorListener
 {
 public:
-    SipStateReplicatorListenerI(const boost::shared_ptr<SipEndpointFactory>& factory, const PJSipManagerPtr& manager);
+    SipStateReplicatorListenerI(
+            const boost::shared_ptr<SipEndpointFactory>& factory,
+            const PJSipManagerPtr& manager,
+            const Ice::ObjectAdapterPtr& globalAdapter,
+            const SipReplicationContextPtr& replicationContext);
     void stateRemoved(const Ice::StringSeq&, const Ice::Current&);
     void stateRemovedForItems(const AsteriskSCF::Replication::SipSessionManager::V1::SipStateItemSeq&, const Ice::Current&);
     void stateSet(const AsteriskSCF::Replication::SipSessionManager::V1::SipStateItemSeq&, const Ice::Current&);
diff --git a/src/SipStateReplicatorListener.cpp b/src/SipStateReplicatorListener.cpp
index 1b57ef1..168b25d 100644
--- a/src/SipStateReplicatorListener.cpp
+++ b/src/SipStateReplicatorListener.cpp
@@ -20,6 +20,7 @@
 #include "SipEndpointFactory.h"
 #include "SipSession.h"
 #include "PJSipManager.h"
+#include "SipTransfer.h"
 #include <pjlib.h>
 
 #include <IceUtil/UUID.h>
@@ -62,8 +63,14 @@ private:
 struct SipStateReplicatorListenerImpl
 {
 public:
-    SipStateReplicatorListenerImpl(const boost::shared_ptr<SipEndpointFactory>& factory, const PJSipManagerPtr& manager)
-        : mId(IceUtil::generateUUID()), mEndpointFactory(factory), mManager(manager) {}
+    SipStateReplicatorListenerImpl(
+            const boost::shared_ptr<SipEndpointFactory>& factory,
+            const PJSipManagerPtr& manager,
+            const Ice::ObjectAdapterPtr& globalAdapter,
+            const SipReplicationContextPtr& replicationContext)
+        : mId(IceUtil::generateUUID()), mEndpointFactory(factory),
+          mManager(manager), mGlobalAdapter(globalAdapter),
+          mReplicationContext(replicationContext) {}
     
     void removeStateNoticeImpl(const Ice::StringSeq& itemKeys)
     {
@@ -139,6 +146,8 @@ public:
             SipRegistrarStateItemPtr regItem;
             DefaultSessionListenerItemPtr defaultListenerItem;
             DefaultSessionCookieItemPtr defaultCookieItem;
+            TransferSessionCreationHookStateItemPtr transferHook;
+            TransferSessionListenerStateItemPtr transferListener;
 
             if ((regItem = SipRegistrarStateItemPtr::dynamicCast((*iter))))
             {
@@ -164,6 +173,19 @@ public:
 
                 endpoint->removeDefaultSessionListener(defaultListenerItem->listener);
             }
+            else if ((transferHook = TransferSessionCreationHookStateItemPtr::dynamicCast(*iter)))
+            {
+                std::map<TransferSessionCreationHookStateItemPtr, TransferSessionCreationHookPtr>::iterator
+                    hook = transferHooks.find(transferHook);
+
+                if (hook == transferHooks.end())
+                {
+                    continue;
+                }
+
+                hook->second->shutdown();
+                transferHooks.erase(hook);
+            }
             else if(defaultCookieItem = DefaultSessionCookieItemPtr::dynamicCast((*iter)))
             {
                 SipEndpointPtr endpoint = mEndpointFactory->findByName(defaultCookieItem->endpointName);
@@ -173,9 +195,20 @@ public:
                 {
                     continue;
                 }
-
                 endpoint->removeDefaultSessionCookie(defaultCookieItem->cookie);
             }
+            else if ((transferListener = TransferSessionListenerStateItemPtr::dynamicCast(*iter)))
+            {
+                std::map<TransferSessionListenerStateItemPtr, TransferListenerPtr>::iterator
+                    listener = transferListeners.find(transferListener);
+
+                if (listener == transferListeners.end())
+                {
+                    continue;
+                }
+                listener->second->shutdown();
+                transferListeners.erase(listener);
+            }
         }
     }
 
@@ -265,6 +298,8 @@ public:
             SipInviteSessionStateItemPtr invitesession;
             SipTransactionStateItemPtr transaction;
             SipRegistrarStateItemPtr regItem;
+            TransferSessionCreationHookStateItemPtr transferHook;
+            TransferSessionListenerStateItemPtr transferListener;
             boost::shared_ptr<SipStateReplicatorItem> localitem;
             DefaultSessionListenerItemPtr defaultListenerItem;
             DefaultSessionCookieItemPtr defaultCookieItem;
@@ -482,20 +517,72 @@ public:
                 {
                     continue;
                 }
-
                 endpoint->addDefaultSessionCookie(defaultCookieItem->cookie);
             }
+            else if ((transferListener = TransferSessionListenerStateItemPtr::dynamicCast(*item)))
+            {
+                pj_int32_t referCSeq = transferListener->referCSeq;
+                pj_str_t callId;
+                pj_cstr(&callId, transferListener->callId.c_str());
+                pj_str_t localTag;
+                pj_cstr(&localTag, transferListener->localTag.c_str());
+                pj_str_t remoteTag;
+                pj_cstr(&remoteTag, transferListener->remoteTag.c_str());
+
+                pjsip_dialog *referDialog = pjsip_ua_find_dialog(&callId, &localTag, &remoteTag, PJ_TRUE);
+
+                if (!referDialog)
+                {
+                    continue;
+                }
+                
+                TransferListenerPtr listener(new TransferListener(mGlobalAdapter, referDialog, referCSeq, mReplicationContext, transferListener->objectId));
+                transferListeners[transferListener] = listener;
+            }
+            else if ((transferHook = TransferSessionCreationHookStateItemPtr::dynamicCast(*item)))
+            {
+                pj_int32_t referCSeq = transferHook->referCSeq;
+                pj_str_t callId;
+                pj_cstr(&callId, transferHook->callId.c_str());
+                pj_str_t localTag;
+                pj_cstr(&localTag, transferHook->localTag.c_str());
+                pj_str_t remoteTag;
+                pj_cstr(&remoteTag, transferHook->remoteTag.c_str());
+
+                pjsip_dialog *referDialog = pjsip_ua_find_dialog(&callId, &localTag, &remoteTag, PJ_TRUE);
+
+                if (!referDialog)
+                {
+                    continue;
+                }
+
+                TransferSessionCreationHookPtr hook(new TransferSessionCreationHook(mGlobalAdapter, referDialog, referCSeq, transferHook->referredBy, mReplicationContext, transferHook->objectId));
+                transferHooks[transferHook] = hook;
+            }
         }
     }
     std::string mId;
     std::map<std::string, boost::shared_ptr<SipStateReplicatorItem> > mStateItems;
     boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
+    std::map<TransferSessionCreationHookStateItemPtr, TransferSessionCreationHookPtr> transferHooks;
+    std::map<TransferSessionListenerStateItemPtr, TransferListenerPtr> transferListeners;
     PJSipManagerPtr mManager;
+    /**
+     * Note this is *not* the replication adapter.
+     * This is the "global" adapter that sessions and other
+     * items are added to. Some replicated items need this in
+     * order to be constructed.
+     */
+    Ice::ObjectAdapterPtr mGlobalAdapter;
+    SipReplicationContextPtr mReplicationContext;
 };
 
-SipStateReplicatorListenerI::SipStateReplicatorListenerI(const boost::shared_ptr<SipEndpointFactory>& factory,
-        const PJSipManagerPtr& manager)
-    : mImpl(new SipStateReplicatorListenerImpl(factory, manager)) 
+SipStateReplicatorListenerI::SipStateReplicatorListenerI(
+        const boost::shared_ptr<SipEndpointFactory>& factory,
+        const PJSipManagerPtr& manager,
+        const Ice::ObjectAdapterPtr& globalAdapter,
+        const SipReplicationContextPtr& replicationContext)
+    : mImpl(new SipStateReplicatorListenerImpl(factory, manager, globalAdapter, replicationContext)) 
 {
 }
 
diff --git a/src/SipTransfer.cpp b/src/SipTransfer.cpp
new file mode 100644
index 0000000..117ea79
--- /dev/null
+++ b/src/SipTransfer.cpp
@@ -0,0 +1,632 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, 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 "SipTransfer.h"
+
+#include <boost/algorithm/string.hpp>
+#include <IceUtil/UUID.h>
+
+#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.h>
+
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.SipSessionManager");
+
+pjsip_tx_data* createNotify(pjsip_dialog *dlg, pj_int32_t cseq, bool active)
+{
+    pjsip_tx_data *tdata;
+    pjsip_dlg_create_request(dlg, pjsip_get_notify_method(), -1, &tdata);
+
+    pjsip_event_hdr *event = pjsip_event_hdr_create(tdata->pool);
+    pj_strdup2(tdata->pool, &event->event_type, "refer");
+    char idbuf[20];
+    pj_ansi_snprintf(idbuf, sizeof(idbuf), "%d", cseq);
+    pj_strdup2(tdata->pool, &event->id_param, idbuf);
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) event);
+
+    pjsip_sub_state_hdr *subState = pjsip_sub_state_hdr_create(tdata->pool);
+    if (active)
+    {
+        pj_strdup2(tdata->pool, &subState->sub_state, "active");
+    }
+    else
+    {
+        pj_strdup2(tdata->pool, &subState->sub_state, "terminated");
+        pj_strdup2(tdata->pool, &subState->reason_param, "noresource");
+    }
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) subState);
+
+    return tdata;
+}
+
+void addNotifyBody(pjsip_tx_data *tdata, const char *bodyText)
+{
+    pj_str_t type;
+    pj_cstr(&type, "message");
... 944 lines suppressed ...


-- 
asterisk-scf/release/sip.git



More information about the asterisk-scf-commits mailing list