[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 ¶ms, 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