[asterisk-scf-commits] asterisk-scf/integration/ice-util-cpp.git branch "sessiondefaults" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Thu Jul 28 16:37:19 CDT 2011


branch "sessiondefaults" has been created
        at  d6682ab6dbbfede4c14ea5a8111a53e8be0b3738 (commit)

- Log -----------------------------------------------------------------
commit d6682ab6dbbfede4c14ea5a8111a53e8be0b3738
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Thu Jul 28 16:35:36 2011 -0500

    Added a Set template for managing collections of Proxies or Handles, with
    logging, locking, etc.

diff --git a/include/AsteriskSCF/Collections/Set.h b/include/AsteriskSCF/Collections/Set.h
new file mode 100644
index 0000000..9c763bf
--- /dev/null
+++ b/include/AsteriskSCF/Collections/Set.h
@@ -0,0 +1,322 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-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 <vector>
+
+#include <boost/thread/locks.hpp>
+
+#include <Ice/Ice.h>
+
+#include <AsteriskSCF/System/ExceptionsIf.h>
+#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/Helpers/ProxyHelper.h>
+
+namespace AsteriskSCF
+{
+namespace Collections
+{
+
+/**
+ * Maintains a set of type T. 
+ * The items are keyed on a type K.
+ * The set maintains at most one item of a given id. 
+ * The id for an item is obtained via an overridable member function
+ * getIdentity(). 
+ */
+template <typename T, typename K, typename NullItemException>
+class Set
+{
+public:
+    Set(const Ice::ObjectAdapterPtr& adapter,
+        const AsteriskSCF::System::Logging::Logger& logger,
+        const std::string& loggingLabel,
+        bool doesThrow = true)
+              : mLogger(logger),
+                mLoggingLabel(loggingLabel),
+                mAdapter(adapter),
+                mDoesThrow(doesThrow)
+    {
+    }
+
+    Set(const Ice::ObjectAdapterPtr& adapter,
+        const std::string& loggingLabel,
+        bool doesThrow = true)
+             : mLogger(AsteriskSCF::System::Logging::getLoggerFactory().getLogger("AsteriskSCF.Collections")),
+               mLoggingLabel(loggingLabel),
+               mAdapter(adapter),
+               mDoesThrow(doesThrow)
+               
+    {
+    }
+
+    int size()
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        return mMap.size();
+    }
+
+    /**
+     * Add a single item.
+     */
+    void add(const T& item)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (item == 0)
+        {
+            mLogger(AsteriskSCF::System::Logging::Warning) << "Attempting to add a null member for " << mLoggingLabel;
+            if (mDoesThrow)
+            {
+               throw NullItemException();
+            }
+            return;
+        }
+
+        K id = getIdentity(item);
+
+        if (mMap.find(id) != mMap.end())
+        {
+            mLogger(AsteriskSCF::System::Logging::Warning) << "Replacing member " << id << " for " <<  mLoggingLabel;
+        }
+
+        mMap[id] = item;
+    }
+
+    /** 
+     * Add a vector of items.
+     */
+    void add(const std::vector<T>& items)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        for (std::vector<T>::const_iterator i = items.begin(); i != items.end(); ++i)
+        {
+            if ((*i) == 0)
+            {
+                mLogger(AsteriskSCF::System::Logging::Warning) << "Attempting to add a null member for " << mLoggingLabel;
+                continue;
+            }
+
+            K id = getIdentity(*i);
+
+            if (mMap.find(id) != mMap.end())
+            {
+                mLogger(AsteriskSCF::System::Logging::Warning) << "Replacing member " << id << " for " <<  mLoggingLabel;
+            }
+
+            mMap[id] = (*i);
+        }
+    }
+
+    /**
+     * Remove a vector of items.
+     */
+    void remove(const std::vector<T>& items)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        std::vector<K> idsNotFound; 
+
+        for (std::vector<T>::const_iterator i = items.begin(); i != items.end(); ++i)
+        {
+            K id = getIdentity(*i);
+
+            std::map<K, T>::iterator searchResult = mMap.find(id);
+            if (searchResult != mMap.end())
+            {
+                mMap.erase(searchResult);
+            }
+            else
+            {
+                idsNotFound.push_back(id);
+            }
+        }
+
+        for(std::vector<K>::const_iterator s = idsNotFound.begin(); s != idsNotFound.end(); ++s)
+        {
+            mLogger(AsteriskSCF::System::Logging::Warning) << "Attempted to remove non-existent member " << (*s);
+        }
+    }
+
+    /**
+     * Remove an item.
+     */
+    void remove(const T& item)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        K id = getIdentity(item);
+        std::map<K, T>::iterator searchResult = mMap.find(id);
+
+        if (searchResult != mMap.end())
+        {
+            mMap.erase(searchResult);
+            return;
+        }
+
+        mLogger(AsteriskSCF::System::Logging::Warning) << "Attempted to remove non-existent member " << id;
+        if (mDoesThrow)
+        {
+            throw AsteriskSCF::System::V1::UnknownObject(id);
+        }
+    }
+
+    /**
+     * Retrieves all the items in the set.
+     */
+    std::vector<T> getAll()
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        std::vector<T> result;
+
+        for (std::map<K,T>::const_iterator pair = mMap.begin(); pair != mMap.end(); ++pair)
+        {
+            result.push_back(pair->second);
+        }
+
+        return result;
+    }
+
+    /**
+     * Retrieves specific items from the set.
+     * The identies of the items in the collection passed in 
+     * are used to retrieve from the managed set.
+     */
+    std::vector<T> get(const std::vector<T>& toRetrieve)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        std::vector<T> result;
+
+        for (std::vector<T>::const_iterator i = toRetrieve.begin(); i != toRetrieve.end(); ++i)
+        {
+            std::map<K,T>::const_iterator pair = mMap.find(getIdentity(*i));
+            if (pair != mMap.end())
+            {
+                result.push_back(pair->second);
+            }
+        }
+
+        return result;
+    }
+
+    T get(const K& key)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        std::map<K, T>::const_iterator pair = mMap.find(key);
+         
+        if (pair != mMap.end())
+        {
+            return pair->second;
+        }
+
+        if (mDoesThrow)
+        {
+            throw AsteriskSCF::System::V1::UnknownObject(key);
+        }
+        return 0;
+    }
+
+    bool has(K key)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+
+        std::map<K, T>::const_iterator search = mMap.find(key);
+        return (search != mMap.end());
+    }
+
+protected:
+
+    virtual K getIdentity(const T& item) = 0;
+
+    AsteriskSCF::System::Logging::Logger mLogger;
+    std::string mLoggingLabel;
+    Ice::ObjectAdapterPtr mAdapter;
+    boost::shared_mutex mLock;
+    std::map<K, T> mMap;
+    bool mDoesThrow;
+};
+
+/**
+ * Maintains a set of handles of type S.
+ * The type S is assumed to be derived from Ice::Handle. 
+ */
+ template <typename S>
+ class HandleSet : public Set<S, std::string, AsteriskSCF::System::V1::NullHandleException>
+ {
+ public:
+    HandleSet(const Ice::ObjectAdapterPtr& adapter,
+              const AsteriskSCF::System::Logging::Logger& logger,
+              const std::string& loggingLabel,
+              bool doesThrow = true)
+                  : Set(adapter,
+                        logger,
+                        loggingLabel,
+                        doesThrow)
+    {
+    }
+
+    HandleSet(const Ice::ObjectAdapterPtr& adapter,
+              const std::string& loggingLabel,
+              bool doesThrow = true)
+                 : Set(adapter,
+                       loggingLabel,
+                       doesThrow)
+               
+    {
+    }
+
+ protected:
+     virtual std::string getIdentity(const S& item)
+     {
+         return item->ice_id();
+     }
+ };
+
+/**
+* Maintains a set of proxies of type S. 
+* The type S is assumed to be derived from Ice::Proxy. 
+*/
+template <typename S>
+class ProxySet : public Set<S, std::string, AsteriskSCF::System::V1::NullProxyException>
+{
+public:
+ProxySet(const Ice::ObjectAdapterPtr& adapter,
+         const AsteriskSCF::System::Logging::Logger& logger,
+         const std::string& loggingLabel,
+         bool doesThrow = true)
+            : Set(adapter,
+                  logger,
+                  loggingLabel,
+                  doesThrow)
+{
+}
+
+ProxySet(const Ice::ObjectAdapterPtr& adapter,
+         const std::string& loggingLabel,
+         bool doesThrow = true)
+            : Set(adapter,
+                  loggingLabel,
+                  doesThrow)
+               
+{
+}
+
+protected:
+    virtual std::string getIdentity(const S& item)
+    {
+        return mAdapter->getCommunicator()->identityToString(item->ice_getIdentity());
+    }
+};
+
+} // end namespace Collections
+} // end namespace AsteriskSCF
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 610766e..993713d 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -16,5 +16,6 @@ astscf_test_icebox(astscf-ice-util-cpp-test config/IceUtilCppTests.conf)
 
 add_subdirectory(Async)
 add_subdirectory(Replication)
+add_subdirectory(Collections)
 add_subdirectory(ThreadPool)
 add_subdirectory(WorkQueue)
diff --git a/test/Collections/CMakeLists.txt b/test/Collections/CMakeLists.txt
new file mode 100644
index 0000000..87768a6
--- /dev/null
+++ b/test/Collections/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+astscf_component_init(CollectionsTest)
+astscf_slice_collection(LOCAL PATH "${CMAKE_CURRENT_SOURCE_DIR}")
+astscf_component_add_files(CollectionsTest TestCollections.cpp)
+astscf_component_add_slices(CollectionsTest LOCAL TestCollectionsIf.ice)
+astscf_component_add_boost_libraries(CollectionsTest unit_test_framework thread date_time)
+astscf_component_add_slice_collection_libraries(CollectionsTest ASTSCF)
+astscf_component_build_icebox(CollectionsTest)
+astscf_test_icebox(CollectionsTest test/Collections/TestCollections.conf)
+target_link_libraries(CollectionsTest logging-client)
diff --git a/test/Collections/TestCollections.conf b/test/Collections/TestCollections.conf
new file mode 100644
index 0000000..fa50cb4
--- /dev/null
+++ b/test/Collections/TestCollections.conf
@@ -0,0 +1,3 @@
+
+IceBox.Service.CollectionsTest = CollectionsTest:create --log_level=all
+
diff --git a/test/Collections/TestCollections.cpp b/test/Collections/TestCollections.cpp
new file mode 100644
index 0000000..fb54ce9
--- /dev/null
+++ b/test/Collections/TestCollections.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+#define BOOST_TEST_MODULE StateReplicatorComponentTestSuite
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/debug.hpp>
+
+#include <Ice/Ice.h>
+#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+
+#include <TestCollectionsIf.h>
+#include <AsteriskSCF/Collections/Set.h>
+
+using namespace std;
+using namespace AsteriskSCF::Collections;
+using namespace AsteriskSCF::CollectionsTest;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::V1;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.TestCollections");
+}
+
+class SampleListenerImpl : public SampleListener
+{
+public:
+    SampleListenerImpl() : mHiCalled(0) {}
+
+    void hiThere(const Ice::Current &)
+    {
+        mHiCalled++;
+    }
+
+int mHiCalled;
+};
+typedef IceUtil::Handle<SampleListenerImpl> SampleListenerImplPtr;
+
+struct GlobalData
+{
+public:
+    SampleListenerPrx prx1;
+    SampleListenerPrx prx2;
+    SampleListenerPrx prx3;
+
+    ChildValue1Ptr ptr1;
+    ChildValue2Ptr ptr2;
+    ChildValue3Ptr ptr3;
+};
+GlobalData global;
+
+/**
+ * A global fixture for Ice initialization.
+ * Provides setup/teardown for the entire set of tests.
+ */
+struct GlobalIceFixture
+{
+    GlobalIceFixture()
+    {
+        ::boost::debug::detect_memory_leaks(false);
+        ::boost::unit_test::unit_test_log.set_stream( std::cout );
+
+        int status = 0;
+        try
+        {
+             IceBoxTestEnv.adapter = IceBoxTestEnv.communicator->createObjectAdapterWithEndpoints("TestCollections","default");
+
+             SampleListenerImplPtr listener = new SampleListenerImpl();
+             global.prx1 = SampleListenerPrx::uncheckedCast(IceBoxTestEnv.adapter->addWithUUID(listener));
+
+             listener = new SampleListenerImpl();
+             global.prx2 = SampleListenerPrx::uncheckedCast(IceBoxTestEnv.adapter->addWithUUID(listener));
+
+             listener = new SampleListenerImpl();
+             global.prx3 = SampleListenerPrx::uncheckedCast(IceBoxTestEnv.adapter->addWithUUID(listener));
+
+             global.ptr1 = new ChildValue1();
+             global.ptr1->base = 1;
+             global.ptr1->foo = 500;
+
+             global.ptr2 = new ChildValue2();
+             global.ptr2->base = 2;
+             global.ptr2->bar = "bar";
+
+             global.ptr3 = new ChildValue3();
+             global.ptr3->base = 3;
+        }
+        catch (const Ice::Exception& ex)
+        {
+            cerr << ex << endl;
+            status = 1;
+        }
+        catch (const char* msg)
+        {
+            cerr << msg << endl;
+            status = 1;
+        }
+    } // end Fixture() constructor
+
+
+    ~GlobalIceFixture()
+    {
+    }
+};
+
+BOOST_GLOBAL_FIXTURE(GlobalIceFixture);
+
+
+struct PerTestFixture
+{
+public:
+    PerTestFixture()
+    {
+    }
+
+    ~PerTestFixture()
+    {
+    }
+
+};
+
+/**
+ * Test a proxy collection
+ */
+BOOST_AUTO_TEST_CASE(ProxySetTest)
+{
+    ProxySet<SampleListenerPrx> proxySet(IceBoxTestEnv.adapter, lg, "Sample Listeners");
+
+    /////////////////////////////////////////////////////////////
+    // Try accessing the empty set first. 
+    // We'll try all the accessor operations just to make sure 
+    // the template instantiation is fully compiled. 
+
+    bool caught(false);
+    vector<SampleListenerPrx> results;
+
+    try
+    {
+        vector<SampleListenerPrx> toRetrieve;            
+            
+        toRetrieve.push_back(global.prx1);
+        toRetrieve.push_back(global.prx2);
+        results = proxySet.get(toRetrieve);
+    }
+    catch(const NullProxyException&)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == false);
+    BOOST_CHECK(results.size() == 0);
+
+    caught = false;
+    try
+    {
+        SampleListenerPrx single = proxySet.get("RandomNonsense");
+    }
+    catch(const UnknownObject&)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == true);
+
+    caught = false;
+    try
+    {
+        results = proxySet.getAll();
+    }
+    catch(...)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == false);
+    BOOST_CHECK(results.size() == 0);
+
+    BOOST_CHECK(proxySet.has("Something") == false);
+
+    ///////////////////////////////////////////////////////
+    // Now add some content added.
+
+    proxySet.add(global.prx1);
+
+    vector<SampleListenerPrx> multiple;
+    multiple.push_back(global.prx2);
+    multiple.push_back(global.prx3);
+
+    proxySet.add(multiple);
+
+    BOOST_CHECK(proxySet.has( IceBoxTestEnv.adapter->getCommunicator()->identityToString(global.prx1->ice_getIdentity())) == true);
+
+    BOOST_CHECK(proxySet.size() == 3);
+
+    proxySet.remove(global.prx2);
+
+    BOOST_CHECK(proxySet.size() == 2);
+
+    results = proxySet.getAll();
+    BOOST_CHECK(results.size() == 2);
+
+    SampleListenerPrx prx = proxySet.get(IceBoxTestEnv.adapter->getCommunicator()->identityToString(global.prx1->ice_getIdentity()));
+    BOOST_CHECK(prx->ice_getIdentity() == global.prx1->ice_getIdentity());
+
+    vector<SampleListenerPrx> toRetrieve;
+    toRetrieve.push_back(global.prx3);
+
+    results = proxySet.get(toRetrieve);
+    BOOST_CHECK(results.size() == 1);
+
+    vector<SampleListenerPrx> toRemove;
+    toRemove.push_back(global.prx1);
+    toRemove.push_back(global.prx3);
+
+    proxySet.remove(toRemove);
+
+    BOOST_CHECK(proxySet.size() == 0);
+}
+
+/**
+ * Test a handle collection
+ */
+BOOST_AUTO_TEST_CASE(HandleSetTest)
+{
+    HandleSet<BaseValuePtr> handleSet(IceBoxTestEnv.adapter, lg, "Values Set");
+
+    /////////////////////////////////////////////////////////////
+    // Try accessing the empty set first. 
+    // We'll try all the accessor operations just to make sure 
+    // the template instantiation is fully compiled. 
+
+    bool caught(false);
+    vector<BaseValuePtr> results;
+
+    try
+    {
+        vector<BaseValuePtr> toRetrieve;            
+            
+        toRetrieve.push_back(global.ptr1);
+        toRetrieve.push_back(global.ptr2);
+        results = handleSet.get(toRetrieve);
+    }
+    catch(const NullProxyException&)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == false);
+    BOOST_CHECK(results.size() == 0);
+
+    caught = false;
+    try
+    {
+        BaseValuePtr single = handleSet.get("RandomNonsense");
+    }
+    catch(const UnknownObject&)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == true);
+
+    caught = false;
+    try
+    {
+        results = handleSet.getAll();
+    }
+    catch(...)
+    {
+        caught = true;
+    }
+
+    BOOST_CHECK(caught == false);
+    BOOST_CHECK(results.size() == 0);
+
+    BOOST_CHECK(handleSet.has("Something") == false);
+
+    ///////////////////////////////////////////////////////
+    // Now add some content added.
+
+    handleSet.add(global.ptr1);
+
+    vector<BaseValuePtr> multiple;
+    multiple.push_back(global.ptr2);
+    multiple.push_back(global.ptr3);
+
+    handleSet.add(multiple);
+
+    BOOST_CHECK(handleSet.has(global.ptr1->ice_id()) == true);
+
+    BOOST_CHECK(handleSet.size() == 3);
+
+    handleSet.remove(global.ptr2);
+
+    BOOST_CHECK(handleSet.size() == 2);
+
+    results = handleSet.getAll();
+    BOOST_CHECK(results.size() == 2);
+
+    BaseValuePtr ptr = handleSet.get(global.ptr1->ice_id());
+    BOOST_CHECK(ptr->ice_id() == global.ptr1->ice_id());
+
+    vector<BaseValuePtr> toRetrieve;
+    toRetrieve.push_back(global.ptr3);
+
+    results = handleSet.get(toRetrieve);
+    BOOST_CHECK(results.size() == 1);
+
+}
diff --git a/test/Collections/TestCollectionsIf.ice b/test/Collections/TestCollectionsIf.ice
new file mode 100644
index 0000000..c1ef54f
--- /dev/null
+++ b/test/Collections/TestCollectionsIf.ice
@@ -0,0 +1,48 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-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
+
+module AsteriskSCF
+{
+module CollectionsTest
+{
+interface SampleListener
+{
+    void hiThere();
+};
+
+class BaseValue
+{
+   int base;
+};
+
+class ChildValue1 extends BaseValue
+{
+   int foo;
+};
+
+class ChildValue2 extends BaseValue
+{
+   string bar;
+};
+
+class ChildValue3 extends BaseValue
+{
+   int other;
+};
+
+}; /* End of module CollectionsTest*/
+}; /* End of module AsteriskSCF */
\ No newline at end of file

commit f18ca9c161f989c7a2f8423c0b4b17b7ea594bac
Author: Brent Eagles <beagles at digium.com>
Date:   Wed Jul 20 15:35:33 2011 -0230

    - Added helper classes for dealing with network addresses. These employ the
      relevant boost libraries and provide rudimentary hostname->IP address
      resolution.
    - Added a simple helper free function for converting an Ice Candidate object
      to an ICE SDP attribute.

diff --git a/include/AsteriskSCF/Helpers/Network.h b/include/AsteriskSCF/Helpers/Network.h
new file mode 100644
index 0000000..23a0f3c
--- /dev/null
+++ b/include/AsteriskSCF/Helpers/Network.h
@@ -0,0 +1,98 @@
+/*
+ * 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 <string>
+#include <vector>
+#include <boost/thread.hpp>
+
+#ifdef _WIN32
+#pragma warning(push)
+#pragma warning(disable: 4251)
+#endif
+
+namespace AsteriskSCF
+{
+namespace Helpers
+{
+
+//
+// NOTE: I discovered that boost asio covers this territory, only with greater detail. I decided to keep going as I was
+// planning something far more basic to use. It's implemented in terms of asio though.
+//
+class ASTSCF_DLL_EXPORT Address
+{
+    //
+    // We don't want a proper assignment operator, this is to behave more like
+    // an atomic type and the only way to really do that is to hide the members
+    // and only allow modification through construction.
+    //
+    void operator=(const Address&);
+public:
+
+    Address(const std::string& hostname, unsigned port);
+    Address(const Address&);
+
+    unsigned port() const;
+    std::string hostname() const;
+    std::string address() const;
+
+    bool isIPV6();
+
+    std::string toString() const;
+    
+private:
+    std::string mHostname;
+    std::string mAddress;
+    unsigned mPort;
+
+    bool mIsIPV6;
+};
+typedef boost::shared_ptr<Address> AddressPtr;
+typedef std::vector<AddressPtr> AddressSeq;
+
+/** 
+ *
+ **/
+class ASTSCF_DLL_EXPORT DNSQuery
+{
+public:
+    virtual ~DNSQuery();
+    static boost::shared_ptr<DNSQuery> create(const std::string& hostname, const std::string& serviceName);
+    static boost::shared_ptr<DNSQuery> create(const std::string& hostname, const int portNumber);
+    
+    virtual AddressSeq execute() = 0;
+
+protected:
+    DNSQuery();
+
+private:
+    //
+    // Not implemented.
+    //
+    DNSQuery(const DNSQuery&);
+    void operator=(const DNSQuery&);
+};
+typedef boost::shared_ptr<DNSQuery> DNSQueryPtr;
+
+
+} /* End of namespace Helpers */
+} /* End of namespace AsteriskSCF */
+
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
diff --git a/include/AsteriskSCF/NAT/Candidates.h b/include/AsteriskSCF/NAT/Candidates.h
new file mode 100644
index 0000000..1aa024e
--- /dev/null
+++ b/include/AsteriskSCF/NAT/Candidates.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <string>
+#include <AsteriskSCF/System/NAT/NATTraversalIf.h>
+
+namespace AsteriskSCF
+{
+namespace NAT
+{
+
+/**
+ * 
+ * toSDP() creates an SDP compliant attribute line for the provided candidate.
+ *
+ **/
+std::string ASTSCF_DLL_EXPORT toSDP(const AsteriskSCF::System::NAT::V1::CandidatePtr& candidate);
+
+} /* End of namespace NAT */
+} /* End of namespace AsteriskSCF */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 082821e..d0a9c90 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,8 +4,10 @@ astscf_component_add_files(astscf-ice-util-cpp ${project_headers})
 add_subdirectory(CollocatedIceStorm)
 add_subdirectory(WorkQueue)
 add_subdirectory(ThreadPool)
+add_subdirectory(Helpers)
+add_subdirectory(NAT)
 astscf_component_add_ice_libraries(astscf-ice-util-cpp IceStorm IceBox)
-astscf_component_add_boost_libraries(astscf-ice-util-cpp core thread date_time)
+astscf_component_add_boost_libraries(astscf-ice-util-cpp core thread date_time system)
 astscf_component_add_slice_collection_libraries(astscf-ice-util-cpp ASTSCF)
 astscf_component_build_library(astscf-ice-util-cpp)
 target_link_libraries(astscf-ice-util-cpp logging-client)
diff --git a/src/Helpers/CMakeLists.txt b/src/Helpers/CMakeLists.txt
new file mode 100644
index 0000000..1c4069e
--- /dev/null
+++ b/src/Helpers/CMakeLists.txt
@@ -0,0 +1 @@
+astscf_component_add_files(astscf-ice-util-cpp Network.cpp)
diff --git a/src/Helpers/Network.cpp b/src/Helpers/Network.cpp
new file mode 100644
index 0000000..d596c52
--- /dev/null
+++ b/src/Helpers/Network.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 <AsteriskSCF/Helpers/Network.h>
+#include <boost/asio.hpp>
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iostream>
+
+using namespace std;
+using namespace AsteriskSCF::Helpers;
+using namespace boost::asio::ip;
+
+Address::Address(const string& host, unsigned p) :
+    mHostname(host),
+    mPort(p),
+    mIsIPV6(false)
+{
+    try
+    {
+        boost::asio::ip::address a(address::from_string(mHostname));
+        mAddress = mHostname;
+        mIsIPV6 = a.is_v6();
+    }
+    catch (const exception&)
+    {
+        DNSQueryPtr q = DNSQuery::create(mHostname, 0);
+        AddressSeq results = q->execute();
+        if (!results.empty())
+        {
+            mIsIPV6 = results[0]->isIPV6();
+            mAddress = results[0]->address();
+        }
+    }
+}
+    
+unsigned Address::port() const
+{
+    return mPort;
+}
+
+string Address::hostname() const
+{
+    return mHostname;
+}
+
+string Address::address() const
+{
+    return mAddress;
+}
+
+bool Address::isIPV6()
+{
+    return mIsIPV6;
+}
+
+string Address::toString() const
+{
+    stringstream os;
+    if (mHostname == mAddress)
+    {
+        os << mHostname << ':' << mPort;
+    }
+    else
+    {
+        os << mHostname << '/' << mAddress << ':' << mPort;
+    }
+    return os.str();
+}
+
+class DNSQueryImpl : public DNSQuery
+{
+public:
+    explicit DNSQueryImpl(const tcp::resolver::query& query) :
+        mQuery(query),
+        mResolver(mIO)
+    {
+    }
+
+    AddressSeq execute()
+    {
+        //
+        // TODO: this can also be made to run asynchronously.
+        //
+        AddressSeq result;
+        for (tcp::resolver::iterator server = mResolver.resolve(mQuery);
+            server != tcp::resolver::iterator(); ++server)
+        {
+            tcp::endpoint ep = *server;
+            result.push_back(AddressPtr(new Address(ep.address().to_string(), ep.port())));
+        }
+        return result;
+    }
+
+private:
+    tcp::resolver::query mQuery;
+    boost::asio::io_service mIO;
+    tcp::resolver mResolver;
+};
+
+DNSQuery::~DNSQuery()
+{
+    //
+    // No-op.
+    //
+}
+
+DNSQueryPtr DNSQuery::create(const string& hostname, const string& serviceName)
+{
+    tcp::resolver::query q(hostname, serviceName);
+    return DNSQueryPtr(new DNSQueryImpl(q));
+}
+
+DNSQueryPtr DNSQuery::create(const string& hostname, const int portnumber)
+{
+    tcp::resolver::query q(hostname, boost::lexical_cast<string>(portnumber));
+    return DNSQueryPtr(new DNSQueryImpl(q));
+}
+
+DNSQuery::DNSQuery()
+{
+}
diff --git a/src/NAT/CMakeLists.txt b/src/NAT/CMakeLists.txt
new file mode 100644
index 0000000..b90886b
--- /dev/null
+++ b/src/NAT/CMakeLists.txt
@@ -0,0 +1 @@
+astscf_component_add_files(astscf-ice-util-cpp Candidates.cpp)
diff --git a/src/NAT/Candidates.cpp b/src/NAT/Candidates.cpp
new file mode 100644
index 0000000..06600e7
--- /dev/null
+++ b/src/NAT/Candidates.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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 <boost/asio/ip/address.hpp>
+#include <AsteriskSCF/NAT/Candidates.h>
+#include <AsteriskSCF/Helpers/Network.h>
+#include <sstream>
+#include <boost/functional/hash.hpp>
+
+using namespace AsteriskSCF::System::NAT::V1;
+using namespace AsteriskSCF::NAT;
+using namespace std;
+
+std::string toSDP(const AsteriskSCF::System::NAT::V1::CandidatePtr& candidate)
+{
+    stringstream os;
+    if (!candidate)
+    {
+        return "";
+    }
+
+    os << "candidate:";
+    if (candidate->foundation.empty())
+    {
+        //
+        // Foundation prefix.
+        //
+        switch (candidate->type)
+        {
+        case Host:
+            os << 'H';
+            break;
+
+        case ServerReflexive:
+            os << 'S';
+            break;
+
+        case PeerReflexive:
+            os << 'P';
+            break;
+
+        case Relayed:
+            os << 'R';
+            break;
+
+        default:
+            assert("Unknown candidate type encountered." == 0);
+        }
+        //
+        // Calculate foundation.
+        //
+        string address;
+        unsigned port;
+        if (candidate->mappedAddress.empty())
+        {
+            //
+            // If we do not have a mapped address and the candidate type is not host, then
+            // something is wrong!
+            //
+            assert (candidate->type == Host);
+            address = candidate->baseAddress;
+            port = candidate->basePort;
+        }
+        else
+        {
+            address = candidate->mappedAddress;
+            port = candidate->mappedPort;
+        }
+        AsteriskSCF::Helpers::AddressPtr addr(new AsteriskSCF::Helpers::Address(address, port));
+        //
+        // Now we can be sure we have a numeric ip address.. it would definitely fail in other ways
+        // before we got this far.
+        //
+        string ipaddr = addr->address();
+        if (addr->isIPV6())
+        {
+            boost::asio::ip::address_v6 ip = boost::asio::ip::address_v6::from_string(ipaddr);
+            boost::asio::ip::address_v6::bytes_type ipbytes = ip.to_bytes();
+            size_t seedVal = 0;
+            for (size_t i = 0; i < (sizeof(ipbytes) / sizeof(ipbytes[0])); ++i)
+            {
+                boost::hash_combine(seedVal, ipbytes[i]);
+            }
+            os << seedVal;
+        }
+        else
+        {
+            boost::asio::ip::address_v4 ip = boost::asio::ip::address_v4::from_string(ipaddr);
+            os << ip.to_ulong();
+        }
+    }
+    else
+    {
+        os << candidate->foundation;
+    }
+    os << ' ';
+    os << candidate->componentId;
+    os << ' ';
+    switch (candidate->transport)
+    {
+    case UDP:
+        os << "UDP";
+        break;
+    case TCP:
+        os << "TCP";
+        break;
+    default:
+        assert("Invalid transport value" == 0);
+    }
+
+    //
+    // If the candidate is a host candidate then we are almost done.
+    //
+    if (candidate->type == Host)
+    {
+        os << candidate->baseAddress << ' ' << candidate->basePort << " typ host";
+        return os.str();
+    }
+    //
+    // Otherwise, we've got a bit more to do.
+    //
+    os << candidate->mappedAddress << ' ' << candidate->mappedPort << "typ ";
+    switch (candidate->type)
+    {
+    case Host:
+        assert("This value isn't valid here" == 0);
+        break;
+
+    case ServerReflexive:
+        os <<  "srflx ";
+        break;
+
+    case PeerReflexive:
+        os << "prflx ";
+        break;
+
+    case Relayed:
+        os << "relay ";
+        break;
+
+    default:
+        assert("Unknown candidate type encountered." == 0);
+    }
+
+    os << "raddr " << candidate->baseAddress << " rport " << candidate->basePort;
+    return os.str();
+}

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


-- 
asterisk-scf/integration/ice-util-cpp.git



More information about the asterisk-scf-commits mailing list