[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "modular-transport-refactor" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Fri Jun 24 09:21:12 CDT 2011
branch "modular-transport-refactor" has been updated
via 929e1ffe1b4cd13a204adf33328c1fea1ca4da21 (commit)
from 35293a3236ddc7df141b1854f643b63023667d01 (commit)
Summary of changes:
src/CMakeLists.txt | 1 +
src/{PJUtil.h => NATOptions.h} | 22 ++--
src/PJSipManager.cpp | 54 ++++++-
src/PJSipManager.h | 12 +-
src/STUNTransport.cpp | 55 ++++++-
src/STUNTransportConfig.cpp | 130 ++++++++++++++++
src/{TLSTransport.h => STUNTransportConfig.h} | 33 +++--
src/SipConfiguration.cpp | 12 ++
src/SipEndpoint.cpp | 14 ++-
src/SipEndpoint.h | 8 +
src/SipSession.cpp | 205 +++++++++++++++++++++++--
src/SipSession.h | 6 +-
src/TCPTransport.cpp | 32 +++-
src/TLSTransport.cpp | 32 +++-
src/Transports.cpp | 46 +++++-
src/Transports.h | 35 ++++-
src/UDPTransport.cpp | 33 +++-
17 files changed, 640 insertions(+), 90 deletions(-)
copy src/{PJUtil.h => NATOptions.h} (69%)
create mode 100644 src/STUNTransportConfig.cpp
copy src/{TLSTransport.h => STUNTransportConfig.h} (56%)
- Log -----------------------------------------------------------------
commit 929e1ffe1b4cd13a204adf33328c1fea1ca4da21
Author: Brent Eagles <beagles at digium.com>
Date: Fri Jun 24 11:46:11 2011 -0230
- Add STUN configuration handler, which will in turn allocate the
STUN transport.
- Add transport collection (albeit temporarily... most likely) to PJSipManager. Transports
are now added to the transport map, but will also be reaped after they are destroyed. ie.
the transports do not need to tell the manager that they are dead, it'll ask later
on and release the reference.
- For STUN enabled endpoints only (for the time being):
- enable explicit transport selection for the setting up dialog
- Other transports can initialize the transport selection structure, but it's not used
at the moment.
- Enable SDP generation for candidates.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 78f74ff..ba47e6c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -41,6 +41,7 @@ asterisk_scf_component_add_file(SipSessionManager STUNTransport.cpp)
asterisk_scf_component_add_file(SipSessionManager STUNTransport.h)
asterisk_scf_component_add_file(SipSessionManager STUNTransportConfig.cpp)
asterisk_scf_component_add_file(SipSessionManager STUNTransportConfig.h)
+asterisk_scf_component_add_file(SipSessionManager NATOptions.h)
asterisk_scf_component_add_file(SipSessionManager PJSipModule.cpp)
asterisk_scf_component_add_file(SipSessionManager PJSipModule.h)
asterisk_scf_component_add_file(SipSessionManager PJSipSessionModule.cpp)
diff --git a/src/Transports.h b/src/NATOptions.h
similarity index 58%
copy from src/Transports.h
copy to src/NATOptions.h
index 0e8a288..2319c50 100644
--- a/src/Transports.h
+++ b/src/NATOptions.h
@@ -1,7 +1,7 @@
/*
* Asterisk SCF -- An open-source communications framework.
*
- * Copyright (C) 2011, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
*
* See http://www.asterisk.org for more information about
* the Asterisk SCF project. Please do not directly contact
@@ -16,31 +16,22 @@
#pragma once
-#include <string>
-#include <vector>
#include <boost/shared_ptr.hpp>
-#include <AsteriskSCF/Helpers/Network.h>
namespace AsteriskSCF
{
namespace SipSessionManager
{
-
-class Transport
+struct NATEndpointOptions
{
-public:
- virtual ~Transport() {}
-
- virtual void destroy() = 0;
-
- void setAddress(const AsteriskSCF::Helpers::AddressPtr& address);
- AsteriskSCF::Helpers::AddressPtr getAddress() const;
-
-private:
- AsteriskSCF::Helpers::AddressPtr mAddress;
+ bool enableICE;
+ bool enableTURN;
+ bool enableSIPSTUN;
+
+ NATEndpointOptions(bool ice, bool turn, bool sip) :
+ enableICE(ice), enableTURN(turn), enableSIPSTUN(sip)
+ {
+ }
};
-typedef boost::shared_ptr<Transport> TransportPtr;
-typedef std::vector<TransportPtr> TransportSeq;
-
} /* End of namespace SipSessionManager */
} /* End of namespace AsteriskSCF */
diff --git a/src/PJSipManager.cpp b/src/PJSipManager.cpp
index 8532863..bceeb22 100644
--- a/src/PJSipManager.cpp
+++ b/src/PJSipManager.cpp
@@ -122,9 +122,14 @@ PJSipManager::~PJSipManager()
i->second->destroy();
i->second.reset();
}
- for (TransportSeq::const_iterator i = mTransports.begin(); i != mTransports.end(); ++i)
+ //
+ // It's pretty important that the transports don't take a reference to the PJSipManager,
+ // otherwise we'd never get here.
+ //
+ for (map<string, TransportPtr>::iterator i = mTransports.begin(); i != mTransports.end(); ++i)
{
- (*i)->destroy();
+ i->second->destroy();
+ i->second.reset();
}
}
@@ -150,10 +155,48 @@ void PJSipManager::registerLoggingModule()
mLoggingModule = new PJSipLoggingModule(mEndpoint);
}
-void PJSipManager::addTransport(const TransportPtr& transport)
+void PJSipManager::addTransport(const string& id, const TransportPtr& transport)
+{
+ //
+ // Reap destroyed transports and add the new one.
+ //
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ map<string, TransportPtr>::iterator i = mTransports.begin();
+ while (i != mTransports.end())
+ {
+ if (i->second->isDestroyed())
+ {
+ mTransports.erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ mTransports.insert(make_pair(id, transport));
+}
+
+TransportPtr PJSipManager::getTransport(const string& id)
{
boost::unique_lock<boost::shared_mutex> lock(mLock);
- mTransports.push_back(transport);
+ map<string, TransportPtr>::iterator i = mTransports.begin();
+ while (i != mTransports.end())
+ {
+ if (i->second->isDestroyed())
+ {
+ mTransports.erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ i = mTransports.find(id);
+ if (i != mTransports.end())
+ {
+ return i->second;
+ }
+ return TransportPtr();
}
SipModulePtr PJSipManager::getModule(const string& moduleName)
@@ -209,7 +252,8 @@ void PJSipManager::initializeDefaultTransports(const Ice::PropertiesPtr& propert
{
addressPart = bindAddress;
}
- mTransports.push_back(createUDPTransport(shared_from_this(), addressPart, portPart));
+ TransportPtr defaultUDPTransport = createUDPTransport(shared_from_this(), addressPart, portPart);
+ mTransports.insert(make_pair(defaultUDPTransport->id(), defaultUDPTransport));
}
}; //End namespace SipSessionManager
diff --git a/src/PJSipManager.h b/src/PJSipManager.h
index 23bf0ad..dd4a644 100644
--- a/src/PJSipManager.h
+++ b/src/PJSipManager.h
@@ -89,10 +89,16 @@ public:
*/
void registerLoggingModule();
+ //
+ // TODO: move this transport collection stuff to a transport manager or something.
+ // PJSipManager does not need it.
+ //
+
/**
- * Add a transport the module. TODO: does PJSipManager need this? That is, does the PJSipManager care?
+ * Add a transport the module.
**/
- void addTransport(const TransportPtr& transport);
+ void addTransport(const std::string& id, const TransportPtr& transport);
+ TransportPtr getTransport(const std::string& id);
SipModulePtr getModule(const std::string& moduleName);
@@ -108,7 +114,7 @@ private:
boost::shared_mutex mLock;
SipModuleMap mModules;
- TransportSeq mTransports;
+ std::map<std::string, TransportPtr> mTransports;
void initializeDefaultTransports(const Ice::PropertiesPtr& properties);
};
diff --git a/src/STUNTransport.cpp b/src/STUNTransport.cpp
index fba972b..d7a2102 100644
--- a/src/STUNTransport.cpp
+++ b/src/STUNTransport.cpp
@@ -26,6 +26,10 @@
#include "DebugUtil.h"
#include "PJUtil.h"
+#include <boost/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <pjsip.h>
+
using namespace AsteriskSCF::System::Logging;
using namespace AsteriskSCF::System::V1;
using namespace std;
@@ -113,11 +117,12 @@ private:
public:
STUNTransport(pjsip_endpoint* endpoint, const AsteriskSCF::Helpers::AddressPtr& stunServer,
- const AsteriskSCF::Helpers::AddressPtr& address, const STUNModulePtr& stun) :
- mDestroyed(false),
- mEndpoint(endpoint),
- mModule(stun),
- mSocket(0)
+ const AsteriskSCF::Helpers::AddressPtr& address, const STUNModulePtr& stun) :
+ Transport(address->address(), address->port()),
+ mDestroyed(false),
+ mEndpoint(endpoint),
+ mModule(stun),
+ mSocket(0)
{
assert(stun);
logger(Debug) << FUNLOG << " : initializing STUN transport";
@@ -189,16 +194,39 @@ public:
}
};
+ AsteriskSCF::Helpers::AddressPtr getAddress() const
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ return mMappedAddress;
+ }
+
+ string id()
+ {
+ AsteriskSCF::Helpers::AddressPtr localAddr = Transport::getAddress();
+ ostringstream os;
+ os << idPrefix() << ':' << localAddr->address() << ':' << localAddr->port();
+ return os.str();
+ }
+
+ bool initSelector(pjsip_tpselector& selector)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ selector.type = PJSIP_TPSELECTOR_TRANSPORT;
+ selector.u.transport = mTransport.get();
+ return true;
+ }
+
private:
- boost::shared_mutex mLock;
+ mutable boost::shared_mutex mLock;
bool mDestroyed;
pjsip_endpoint* mEndpoint;
STUNModulePtr mModule;
pj_stun_sock* mSocket;
boost::shared_ptr<pjsip_transport> mTransport;
+ AsteriskSCF::Helpers::AddressPtr mMappedAddress;
- void destroy()
+ void destroyImpl()
{
bool doDestroy = false;
{
@@ -304,6 +332,10 @@ private:
pj_strdup2(mModule->getPool(), &transport->local_name.host,
pj_sockaddr_print(&socketInfo.mapped_addr, buf, sizeof buf, 0));
transport->local_name.port = pj_sockaddr_get_port(&socketInfo.mapped_addr);
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ mMappedAddress.reset(new AsteriskSCF::Helpers::Address(buf, transport->local_name.port));
+ }
memcpy(&transport->local_addr, &socketInfo.bound_addr, sizeof &transport->local_addr);
transport->addr_len = sizeof transport->local_addr;
}
@@ -343,13 +375,20 @@ private:
static_cast<pj_uint16_t>(data->buf.cur - data->buf.start), 0,
remoteAddress, remoteAddressLength);
}
+
+ string idPrefix()
+ {
+ return "stun";
+ }
};
TransportPtr createSTUNTransport(const PJSipManagerPtr& sipManager, const AsteriskSCF::Helpers::AddressPtr& stunServer,
const AsteriskSCF::Helpers::AddressPtr& host)
{
- return TransportPtr(new STUNTransport(sipManager->getEndpoint(), stunServer, host,
+ TransportPtr result(new STUNTransport(sipManager->getEndpoint(), stunServer, host,
boost::dynamic_pointer_cast<STUNModule>(sipManager->getModule("STUN"))));
+ sipManager->addTransport(result->id(), result);
+ return result;
}
}
diff --git a/src/STUNTransportConfig.cpp b/src/STUNTransportConfig.cpp
new file mode 100644
index 0000000..b4d189d
--- /dev/null
+++ b/src/STUNTransportConfig.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "STUNTransportConfig.h"
+#include "STUNTransport.h"
+#include "PJSipManager.h"
+
+using namespace AsteriskSCF::SipSessionManager;
+
+namespace
+{
+
+ //
+ // Forward declarations.
+ //
+ class STUNTransportConfigImpl;
+ AsteriskSCF::SIP::V1::SipConfigurationItemVisitorPtr visitorFactory(const IceUtil::Handle<STUNTransportConfigImpl>& config);
+
+ class STUNTransportConfigImpl : public STUNTransportConfig
+ {
+ public:
+ STUNTransportConfigImpl(const PJSipManagerPtr& sipManager) :
+ mSipManager(sipManager),
+ mGroup(new AsteriskSCF::SIP::V1::SipSTUNTransportGroup)
+ {
+ }
+
+ AsteriskSCF::SIP::V1::SipConfigurationItemVisitorPtr getVisitor()
+ {
+ return visitorFactory(this);
+ }
+
+ AsteriskSCF::SIP::V1::SipSTUNTransportGroupPtr getTypedGroup()
+ {
+ return mGroup;
+ }
+
+ void update(const AsteriskSCF::Helpers::AddressPtr& stunServer, const AsteriskSCF::Helpers::AddressPtr& host)
+ {
+ if (stunServer || host)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ if (mTransport)
+ {
+ mTransport->destroy();
+ }
+ if (stunServer)
+ {
+ mSTUNServer = stunServer;
+ }
+ if (host)
+ {
+ mBindAddress = host;
+ }
+
+ if (mSTUNServer)
+ {
+ //
+ // We currently don't support creating a stun transport
+ // without a configured stun server.
+ //
+ mTransport = createSTUNTransport(mSipManager, mSTUNServer, mBindAddress);
+ }
+ }
+ }
+ private:
+
+ boost::shared_mutex mLock;
+ PJSipManagerPtr mSipManager;
+ AsteriskSCF::Helpers::AddressPtr mSTUNServer;
+ AsteriskSCF::Helpers::AddressPtr mBindAddress;
+ bool mUpdated;
+ TransportPtr mTransport;
+ AsteriskSCF::SIP::V1::SipSTUNTransportGroupPtr mGroup;
+ };
+
+ class STUNConfigurationVisitor : public AsteriskSCF::SIP::V1::SipConfigurationItemVisitor
+ {
+ public:
+ STUNConfigurationVisitor(const IceUtil::Handle<STUNTransportConfigImpl>& config) :
+ mConfig(config)
+ {
+ }
+
+ ~STUNConfigurationVisitor()
+ {
+ mConfig->update(mSTUNServer, mBindAddress);
+ }
+
+ void visitSipSignalingSTUNHostItem(const SipSignalingSTUNHostItemPtr& item)
+ {
+ mSTUNServer = AsteriskSCF::Helpers::AddressPtr(new AsteriskSCF::Helpers::Address(item->address, item->port));
+ }
+
+ void visitSipHostItem(const SipHostItemPtr& item)
+ {
+ mBindAddress = AsteriskSCF::Helpers::AddressPtr(new AsteriskSCF::Helpers::Address(item->host, item->port));
+ }
+ private:
+ IceUtil::Handle<STUNTransportConfigImpl> mConfig;
+
+ AsteriskSCF::Helpers::AddressPtr mSTUNServer;
+ AsteriskSCF::Helpers::AddressPtr mBindAddress;
+ };
+
+ AsteriskSCF::SIP::V1::SipConfigurationItemVisitorPtr visitorFactory(const IceUtil::Handle<STUNTransportConfigImpl>& config)
+ {
+ return new STUNConfigurationVisitor(config);
+ }
+}
+
+
+IceUtil::Handle<STUNTransportConfig>
+AsteriskSCF::SipSessionManager::STUNTransportConfig::create(const PJSipManagerPtr& sipManager)
+{
+ return new STUNTransportConfigImpl(sipManager);
+}
diff --git a/src/STUNTransportConfig.h b/src/STUNTransportConfig.h
new file mode 100644
index 0000000..5e0df8e
--- /dev/null
+++ b/src/STUNTransportConfig.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "SipConfigurationIf.h"
+
+#include <IceUtil/Shared.h>
+#include <boost/shared_ptr.hpp>
+
+namespace AsteriskSCF
+{
+namespace SipSessionManager
+{
+//
+// Forward declarations.
+//
+class PJSipManager;
+typedef boost::shared_ptr<PJSipManager> PJSipManagerPtr;
+
+//
+// Note: STUN is an additional "feature" of the UDP transport.
+//
+
+class STUNTransportConfig : public IceUtil::Shared
+{
+public:
+
+ virtual AsteriskSCF::SIP::V1::SipConfigurationItemVisitorPtr getVisitor() = 0;
+
+ virtual AsteriskSCF::SIP::V1::SipSTUNTransportGroupPtr getTypedGroup() = 0;
+
+ static IceUtil::Handle<STUNTransportConfig> create(const PJSipManagerPtr& sipManager);
+};
+
+typedef IceUtil::Handle<STUNTransportConfig> STUNTransportConfigPtr;
+
+} // End of namespace SipSessionManager
+} // End of namespace AsteriskSCF
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index 23b56f6..2e3a163 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -409,6 +409,10 @@ public:
{
mAddress = hostItem->host;
mPort = hostItem->port;
+ if (mTransport)
+ {
+ mTransport->destroy();
+ }
mTransport = createUDPTransport(mManager, mAddress, mPort);
}
}
@@ -497,6 +501,10 @@ public:
{
mAddress = hostItem->host;
mPort = hostItem->port;
+ if (mTransport)
+ {
+ mTransport->destroy();
+ }
mTransport = createTCPTransport(mManager, mAddress, mPort);
}
}
@@ -682,6 +690,10 @@ public:
if (mNeedsUpdating)
{
mNeedsUpdating = false;
+ if (mTransportFactory)
+ {
+ mTransportFactory->destroy();
+ }
mTransportFactory = createTLSTransport(mManager, mAddress, mPort, &mTLSSettings);
}
}
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index 9186605..cffd2c1 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -21,6 +21,7 @@
#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
#include <AsteriskSCF/logger.h>
+#include "NATOptions.h"
using namespace AsteriskSCF::System::Logging;
@@ -203,7 +204,9 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
}
SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, listener, mImplPriv->mManager,
- mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, true);
+ mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, true,
+ 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;
return session->getSessionProxy();
@@ -212,7 +215,10 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const std::string& destination)
{
SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, 0, mImplPriv->mManager,
- mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, false);
+ mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, false,
+ NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+ mImplPriv->mConfig.transportConfig.enableNAT)
+ );
mImplPriv->mSessions.push_back(session);
return session;
}
@@ -223,7 +229,9 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
{
SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, mediaid, mediasession,
- sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, false);
+ sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, false,
+ 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 4401750..fb13061 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -40,6 +40,10 @@ namespace AsteriskSCF
namespace SipSessionManager
{
+//
+// TODO: All of these config classes should be moved to a separate header file. This would
+// break the circular dependency between the endpoint and it's associated sessions.
+//
class SipEndpointFactory;
class SipSession;
@@ -243,6 +247,10 @@ public:
/**
* Implementation specific.
*/
+ //
+ // XXX: Accessing the config data by reference here is completely thread-violate, can it really be
+ // guaranteed that this data will not be accessed by multiple things at once?
+ //
SipEndpointConfig &getConfig();
std::string getName();
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 3dd19e5..ab342f0 100644
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -27,8 +27,12 @@
#include <AsteriskSCF/System/WorkQueue/WorkQueueIf.h>
#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/System/NAT/NATTraversalIf.h>
+#include "NATOptions.h"
using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::NAT::V1;
+using namespace std;
namespace
{
@@ -86,9 +90,12 @@ public:
SipSessionPriv(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
const std::string& destination, const PJSipManagerPtr& manager,
const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const AsteriskSCF::System::Component::V1::ReplicaPtr& replica)
+ const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
+ const NATEndpointOptions& natOptions)
: mAdapter(adapter), mDialog(0), mInviteSession(0), mEndpoint(endpoint), mDestination(destination),
- mManager(manager), mServiceLocator(serviceLocator), mReplica(replica) { };
+ mManager(manager), mServiceLocator(serviceLocator), mReplica(replica), mNatOptions(natOptions)
+ {
+ }
AsteriskSCF::SessionCommunications::V1::SessionInfoPtr getInfo()
{
@@ -248,12 +255,13 @@ public:
AsteriskSCF::System::Component::V1::ReplicaPtr mReplica;
SessionWorkPtr mSessionWork;
+
+ NATEndpointOptions mNatOptions;
};
void SipSession::initializePJSIPStructs()
{
- pj_str_t local_uri, remote_uri;
- SipEndpointConfig &config = mImplPriv->mEndpoint->getConfig();
+ SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
std::string prefix;
if (config.transportConfig.secureTransport == OUTBOUND || config.transportConfig.secureTransport == BOTH)
@@ -265,10 +273,49 @@ void SipSession::initializePJSIPStructs()
prefix = "sip";
}
+ //
+ // With STUN, the address for the contact header should match the externally mapped address.
+ //
+ char contact[64];
+ pj_str_t contact_uri;
+ TransportPtr transport;
+ if (config.transportConfig.enableNAT)
+ {
+ string transportId("stun:");
+ transportId += config.transportConfig.address;
+ transport = mImplPriv->mManager->getTransport(transportId);
+ if (transport)
+ {
+ //
+ // On a stun enabled transport, getAddress() gets the mapped address.
+ //
+ AsteriskSCF::Helpers::AddressPtr addr = transport->getAddress();
+ if (addr)
+ {
+ pj_ansi_sprintf(contact, "%s:%s@%s:%d", prefix.c_str(), config.transportConfig.user.c_str(),
+ addr->address().c_str(), addr->port());
+ contact_uri = pj_str(contact);
+ }
+ else
+ {
+ //
+ // If the addr is null it means that the binding on the NAT hasn't been obtained...
+ // proceed as normal.
+ //
+ transport.reset();
+ }
+ }
+ }
+
char local[64];
pj_ansi_sprintf(local, "%s:%s", prefix.c_str(), config.sessionConfig.sourceAddress.c_str());
- local_uri = pj_str(local);
-
+ pj_str_t local_uri = pj_str(local);
+ if (!transport)
+ {
+ contact_uri = local_uri;
+ }
+
+
char remote[64];
bool userDefined = mImplPriv->mDestination.size() != 0;
pj_ansi_sprintf(remote, "%s:%s%s%s",
@@ -276,15 +323,33 @@ void SipSession::initializePJSIPStructs()
userDefined ? mImplPriv->mDestination.c_str() : "",
userDefined ? "@" : "",
config.transportConfig.address.c_str());
- remote_uri = pj_str(remote);
+
+ pj_str_t remote_uri(pj_str(remote));
pjsip_dialog *dialog;
- if ((pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, &local_uri, &remote_uri, &remote_uri, &dialog)) !=
+ if ((pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, &contact_uri, &remote_uri, &remote_uri, &dialog)) !=
PJ_SUCCESS)
{
// What should we do here? Throw an exception?
return;
}
+
+ if (transport)
+ {
+ pjsip_tpselector selector;
+ if (transport->initSelector(selector))
+ {
+ if(pjsip_dlg_set_transport(dialog, &selector) != PJ_SUCCESS)
+ {
+ //
+ // This would be pretty weird.. I guess if the transport no longer exists at this point.
+ // We could just roll along and see if the default transport selection in pjsip
+ // hooks us up.
+ //
+ }
+ }
+ }
+
mImplPriv->mDialog = dialog;
pjsip_inv_session *inviteSession;
@@ -313,8 +378,8 @@ void SipSession::initializePJSIPStructs()
SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
const std::string& destination, const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool ipv6, bool isUAC)
- : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica))
+ const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool ipv6, bool isUAC, const NATEndpointOptions& natOptions)
+ : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
{
if (listener != 0)
{
@@ -346,8 +411,8 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
const Ice::Identity& mediaid, const AsteriskSCF::Media::V1::SessionPrx& mediasession,
const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool isUAC)
- : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica))
+ const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool isUAC, const NATEndpointOptions& natOptions)
+ : mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
{
mImplPriv->mSessionProxy =
AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(adapter->add(this, sessionid));
@@ -907,8 +972,10 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
AsteriskSCF::Media::RTP::V1::StreamSourceRTPPrx::uncheckedCast(mImplPriv->mSources.front());
std::string address = stream->getLocalAddress();
+ AsteriskSCF::Helpers::AddressPtr streamAddr(new AsteriskSCF::Helpers::Address(stream->getLocalAddress(),
+ stream->getLocalPort()));
- if (address.find(":") != std::string::npos)
+ if (streamAddr->isIPV6())
{
pj_strdup2(mImplPriv->mDialog->pool, &sdp->origin.addr_type, "IP6");
}
@@ -960,25 +1027,129 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
attr = static_cast<pjmedia_sdp_attr*>(pj_pool_zalloc(mImplPriv->mDialog->pool, sizeof(pjmedia_sdp_attr)));
pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "sendrecv");
sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
-
+
+ SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
+ if (config.sessionConfig.rtpOverICE)
+ {
+ bool sdpAttrSet = false;
+ size_t mediaIndex = 0;
+ std::vector<AsteriskSCF::Media::RTP::V1::RTPSessionPrx> sessions = mImplPriv->mRTPSessions;
+ for (std::vector<AsteriskSCF::Media::RTP::V1::RTPSessionPrx>::const_iterator i = sessions.begin();
+ i != sessions.end(); ++i)
+ {
+ InteractiveConnectionAgentPrx natFacet = InteractiveConnectionAgentPrx::checkedCast(*i,
+ InteractiveConnectionAgentFacetName);
+ if (natFacet)
+ {
+ CandidateSeq candidates = natFacet->getCandidates();
+ if (!sdpAttrSet)
+ {
+ pj_str_t natTypeStr;
+ char natTypeBuf[20];
+ //
+ // TODO: proper enum mapping function, just in case!
+ //
+ pj_ansi_sprintf(natTypeBuf, "%d", static_cast<unsigned>(natFacet->getNATType()));
+ pjmedia_sdp_attr* a = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "X-nat", &natTypeStr);
+ pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
+ sdpAttrSet = true;
+ }
+ ///
+ // create candidate lines!
+ //
+ pjmedia_sdp_media* currentMedia = sdp->media[mediaIndex];
+ //
+ // TODO - ice user & password
+ //
+ for (CandidateSeq::const_iterator j = candidates.begin(); j != candidates.end(); ++j)
+ {
+ CandidatePtr candidate = *j;
+ ostringstream os;
+ os << "candidate:" << candidate->foundation << ' ' << candidate->componentId << " UDP " <<
+ candidate->priority << ' ' << candidate->mappedAddress << ' ' << candidate->mappedPort << " typ ";
+ string hostType;
+ switch (candidate->type)
+ {
+ case Host:
+ hostType = "host";
+ break;
+ case ServerReflexive:
+ hostType = "srflx";
+ break;
+ case PeerReflexive:
+ hostType = "prflx";
+ break;
+ case Relayed:
+ hostType = "relay";
+ break;
+ }
+ os << hostType;
+ if (candidate->type != Host)
+ {
+ os << " raddr " << candidate->baseAddress << " rport " << candidate->basePort;
+ }
+ string t = os.str();
+ pj_str_t candidateStr = pj_str(const_cast<char*>(t.c_str()));
+ pjmedia_sdp_attr* newAttribute = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool,
+ "candidate", &candidateStr);
+ pjmedia_sdp_attr_add(¤tMedia->attr_count, currentMedia->attr, newAttribute);
+ }
+ }
+ break; // XXXX - we are currently only dealing with one media stream.. this loop really should be over the
+ // whole thing.
+ }
+ }
return sdp;
}
/**
- * Internal function called to request needed RTP sessions.
+ * Internal function called to request needed RTP sessions.
+ * NOTE: this only gets called from the constructor so locking is not an issue.
*/
void SipSession::requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats, bool ipv6)
{
// TODO: This needs to be improved for multiple streams
- AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr params =
- new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams();
+
+ AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr params;
+
+ //
+ // We allocate streams with ICE features enabled by providing alternate
+ // parameters to locate and allocate methods.
+ //
+ if (mImplPriv->mNatOptions.enableICE)
+ {
+ AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
+ new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
+ params = iceParams;
+ iceParams->enableRTPOverICE = true;
+ iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
+ }
+ else
+ {
+ params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
+ }
params->category = "rtp";
params->formats = formats;
params->ipv6 = ipv6;
AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx factory =
AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+ if (!factory)
+ {
+ assert("Location request has returned a nil proxy, this should throw!" == 0);
+ //
+ // TODO: throw!
+ //
+ }
AsteriskSCF::Media::RTP::V1::RTPSessionPrx session = factory->allocate(params);
+
+ if (!session)
+ {
+ assert("Allocation of rtp streams failed! This should've thrown an exception!" == 0);
+ //
+ // TODO Throw!
+ //
+ }
mImplPriv->mRTPSessions.push_back(session);
// Create a local copy of the sources, this won't get changed by the RTP session so it's all good
diff --git a/src/SipSession.h b/src/SipSession.h
index 3e63cf9..e379c0c 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -52,6 +52,8 @@ typedef IceUtil::Handle<SipEndpoint> SipEndpointPtr;
class PJSipManager;
typedef boost::shared_ptr<PJSipManager> PJSipManagerPtr;
+struct NATEndpointOptions;
+
/*
* Private implementation class for SipSession.
*/
@@ -101,14 +103,14 @@ public:
const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx&, const PJSipManagerPtr& manager,
const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
- bool ipv6, bool isUAC);
+ bool ipv6, bool isUAC, const NATEndpointOptions& natOptions);
SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&,
const Ice::Identity&, const AsteriskSCF::Media::V1::SessionPrx&,
const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
- bool isUAC);
+ bool isUAC, const NATEndpointOptions& natOptions);
bool operator==(const SipSession &other) const;
diff --git a/src/TCPTransport.cpp b/src/TCPTransport.cpp
index adbd999..71f5a63 100644
--- a/src/TCPTransport.cpp
+++ b/src/TCPTransport.cpp
@@ -15,9 +15,14 @@
*/
#include "UDPTransport.h"
-#include <pjlib.h>
#include "PJSipManager.h"
#include <boost/lexical_cast.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <pjsip.h>
+#include <pjlib.h>
+
+using namespace std;
namespace AsteriskSCF
{
@@ -27,7 +32,8 @@ namespace SipSessionManager
class TCPTransport : public Transport
{
public:
- TCPTransport(pjsip_tpfactory* t) :
+ TCPTransport(pjsip_tpfactory* t, const string& address, unsigned port) :
+ Transport(address, port),
mTransport(t)
{
}
@@ -45,21 +51,24 @@ public:
//
}
}
-
- void destroy()
+
+ bool initSelector(pjsip_tpselector& selector)
{
- destroyImpl();
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ selector.type = PJSIP_TPSELECTOR_LISTENER;
+ selector.u.listener = mTransport;
+ return true;
}
private:
- boost::mutex mLock;
+ boost::shared_mutex mLock;
pjsip_tpfactory* mTransport;
void destroyImpl()
{
pjsip_tpfactory* t = 0;
{
- boost::unique_lock<boost::mutex> lock(mLock);
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
t = mTransport;
mTransport = 0;
}
@@ -71,6 +80,11 @@ private:
// pjsip_tpmgr_unregister_tpfactory(mgr, t);
}
}
+
+ string idPrefix()
+ {
+ return "tcp";
+ }
};
TransportPtr createTCPTransport(const PJSipManagerPtr& manager, const std::string& address, int port)
@@ -88,7 +102,9 @@ TransportPtr createTCPTransport(const PJSipManagerPtr& manager, const std::strin
return TransportPtr();
}
- return TransportPtr(new TCPTransport(tcpTransport));
+ TransportPtr result(new TCPTransport(tcpTransport, address, port));
+ manager->addTransport(result->id(), result);
+ return result;
}
}
diff --git a/src/TLSTransport.cpp b/src/TLSTransport.cpp
index 0503662..171fb83 100644
--- a/src/TLSTransport.cpp
+++ b/src/TLSTransport.cpp
@@ -15,9 +15,12 @@
*/
#include "TLSTransport.h"
-#include <pjlib.h>
#include "PJSipManager.h"
+#include <pjlib.h>
#include <boost/lexical_cast.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <pjsip.h>
using namespace std;
@@ -29,7 +32,8 @@ namespace SipSessionManager
class TLSTransport : public Transport
{
public:
- TLSTransport(pjsip_tpfactory* factory) :
+ TLSTransport(pjsip_tpfactory* factory, const string& host, unsigned port) :
+ Transport(host, port),
mFactory(factory)
{
}
@@ -40,7 +44,18 @@ public:
// Nothing to do yet.. I think.
//
}
+
+ bool initSelector(pjsip_tpselector& selector)
+ {
+ selector.type = PJSIP_TPSELECTOR_LISTENER;
+ selector.u.listener = mFactory;
+ return true;
+ }
+ string idPrefix()
+ {
+ return "tls";
+ }
private:
pjsip_tpfactory* mFactory;
};
@@ -59,16 +74,19 @@ TransportPtr createTLSTransport(const PJSipManagerPtr&, const string& hostname,
pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &tlsString, &tlsAddr);
pj_sockaddr_set_port(&tlsAddr, boost::lexical_cast<pj_uint16_t>(port));
- pjsip_tpfactory *tlsTransport = 0;
#if PJSIP_HAS_TLS_TRANSPORT
- if (pjsip_tls_transport_start(manager->getEndpoint(), tlsSettings, &tlsAddr, NULL, 2, &tlsTransport) != PJ_SUCCESS)
-#endif
+ pjsip_tpfactory *tlsTransport = 0;
+ if (pjsip_tls_transport_start(manager->getEndpoint(), tlsSettings, &tlsAddr, NULL, 2, &tlsTransport) == PJ_SUCCESS)
{
- return TransportPtr();
+ TransportPtr result(new TLSTransport(tlsTransport, hostname, port));
+ manager->addTransport(result->id(), result);
+ return result;
}
+
+#endif
+ return TransportPtr();
- return TransportPtr(new TLSTransport(tlsTransport));
}
} /* End of namespace SipSessionManager */
diff --git a/src/Transports.cpp b/src/Transports.cpp
index f52987d..962bffc 100644
--- a/src/Transports.cpp
+++ b/src/Transports.cpp
@@ -15,17 +15,57 @@
*/
#include "Transports.h"
-#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/lexical_cast.hpp>
using namespace std;
using namespace AsteriskSCF::SipSessionManager;
-void Transport::setAddress(const AsteriskSCF::Helpers::AddressPtr& newAddress)
+Transport::Transport(const string& host, unsigned port) :
+ mAddress(new AsteriskSCF::Helpers::Address(host, port)),
+ mDestroyed(false)
{
- mAddress = newAddress;
+}
+
+void Transport::destroy()
+{
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ mDestroyed = true;
+ }
+ destroyImpl();
}
AsteriskSCF::Helpers::AddressPtr Transport::getAddress() const
{
return mAddress;
}
+
+bool Transport::isDestroyed()
+{
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ return mDestroyed;
+}
+
+string Transport::id()
+{
+ string t(idPrefix());
+ if (!t.empty())
+ {
+ t += ':';
+ }
+ AsteriskSCF::Helpers::AddressPtr addr = getAddress();
+ t += addr->address();
+ t += boost::lexical_cast<string>(addr->port());
+ return t;
+}
+
+bool Transport::initSelector(pjsip_tpselector&)
+{
+ return false;
+}
+
+string Transport::idPrefix()
+{
+ return "";
+}
diff --git a/src/Transports.h b/src/Transports.h
index 0e8a288..833c775 100644
--- a/src/Transports.h
+++ b/src/Transports.h
@@ -19,8 +19,24 @@
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
#include <AsteriskSCF/Helpers/Network.h>
+//
+// Developer note: Do not hold a reference to PJSipManager in the transport
+// instance or any derived instance. Currently many of the derived transports
+// add themselves to a registry of transports in the manager so holding on to a
+// reference would set up a mutual reference situation with a couple of
+// reference counted pointers. Eventually, the transport registry should be
+// moved of the PJSipManager, but then the warning would hold for that
+// transport registry was called!
+//
+
+//
+// Forward declaration.
+//
+struct pjsip_tpselector;
+
namespace AsteriskSCF
{
namespace SipSessionManager
@@ -29,15 +45,28 @@ namespace SipSessionManager
class Transport
{
public:
+ Transport(const std::string& host, unsigned port);
virtual ~Transport() {}
- virtual void destroy() = 0;
+ void destroy();
+
+ virtual AsteriskSCF::Helpers::AddressPtr getAddress() const;
+
+ virtual bool isDestroyed();
+
+ virtual std::string id();
+
+ virtual bool initSelector(pjsip_tpselector&);
+
+protected:
- void setAddress(const AsteriskSCF::Helpers::AddressPtr& address);
- AsteriskSCF::Helpers::AddressPtr getAddress() const;
+ virtual void destroyImpl() = 0;
+ virtual std::string idPrefix();
private:
+ boost::shared_mutex mLock;
AsteriskSCF::Helpers::AddressPtr mAddress;
+ bool mDestroyed;
};
typedef boost::shared_ptr<Transport> TransportPtr;
typedef std::vector<TransportPtr> TransportSeq;
diff --git a/src/UDPTransport.cpp b/src/UDPTransport.cpp
index 56750b8..15a3109 100644
--- a/src/UDPTransport.cpp
+++ b/src/UDPTransport.cpp
@@ -15,9 +15,14 @@
*/
#include "UDPTransport.h"
-#include <pjlib.h>
#include "PJSipManager.h"
#include <boost/lexical_cast.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <pjsip.h>
+#include <pjlib.h>
+
+using namespace std;
namespace AsteriskSCF
{
@@ -27,7 +32,8 @@ namespace SipSessionManager
class UDPTransport : public Transport
{
public:
- UDPTransport(pjsip_transport* t) :
+ UDPTransport(const string& address, unsigned port, pjsip_transport* t) :
+ Transport(address, port),
mTransport(t)
{
}
@@ -45,20 +51,24 @@ public:
//
}
}
-
- void destroy()
+
+ bool initSelector(pjsip_tpselector& selector)
{
- destroyImpl();
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ selector.type = PJSIP_TPSELECTOR_TRANSPORT;
+ selector.u.transport = mTransport;
+ return true;
}
+
private:
- boost::mutex mLock;
+ boost::shared_mutex mLock;
pjsip_transport* mTransport;
void destroyImpl()
{
pjsip_transport* t = 0;
{
- boost::unique_lock<boost::mutex> lock(mLock);
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
t = mTransport;
mTransport = 0;
}
@@ -67,6 +77,11 @@ private:
pjsip_transport_shutdown(t);
}
}
+
+ std::string idPrefix()
+ {
+ return "udp";
+ }
};
TransportPtr createUDPTransport(const PJSipManagerPtr& manager, const std::string& address, int port)
@@ -93,7 +108,9 @@ TransportPtr createUDPTransport(const PJSipManagerPtr& manager, const std::strin
return TransportPtr();
}
- return TransportPtr(new UDPTransport(udpTransport));
+ TransportPtr result(new UDPTransport(address, port, udpTransport));
+ manager->addTransport(result->id(), result);
+ return result;
}
}
-----------------------------------------------------------------------
--
asterisk-scf/integration/sip.git
More information about the asterisk-scf-commits
mailing list