replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / resourceClient / RCSDiscoveryManagerImpl.cpp
index 660a126..319c9b8 100755 (executable)
 // limitations under the License.
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
 #include "RCSDiscoveryManagerImpl.h"
 
 #include "OCPlatform.h"
-
 #include "PresenceSubscriber.h"
 #include "RCSAddressDetail.h"
 #include "RCSAddress.h"
+#include "RCSRemoteResourceObject.h"
+
+namespace
+{
+    constexpr unsigned int POLLING_INTERVAL_TIME = 60000;
+
+    std::string makeResourceId(const std::shared_ptr< OIC::Service::PrimitiveResource >& resource)
+    {
+        return resource->getSid() + resource->getUri();
+    }
+
+    void validateTypes(const std::vector< std::string >& resourceTypes) {
+        if (resourceTypes.size() == 1) return;
 
-constexpr unsigned int RESETNUMBER = 0;
-constexpr unsigned int LIMITNUMBER = 1000;
-constexpr unsigned int INTERVALTIME = 60000;
+        for (const auto& type : resourceTypes)
+        {
+            if (type == OIC::Service::RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE)
+            {
+                throw OIC::Service::RCSBadRequestException{
+                    "resource types must have no empty string!" };
+            }
+        }
+    }
+}
 
 namespace OIC
 {
     namespace Service
     {
-        unsigned int RCSDiscoveryManagerImpl::s_uniqueId = RESETNUMBER;
-        RCSDiscoveryManagerImpl * RCSDiscoveryManagerImpl::s_instance(nullptr);
-        std::mutex RCSDiscoveryManagerImpl::s_mutexForCreation;
+        constexpr RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::INVALID_ID;
+        constexpr char const* RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE;
+
+        RCSDiscoveryManagerImpl::RCSDiscoveryManagerImpl()
+        {
+            subscribePresenceWithMulticast();
 
-        RCSDiscoveryManagerImpl::RCSDiscoveryManagerImpl() : m_timerHandle(0){}
+            m_timer.post(POLLING_INTERVAL_TIME,
+                    std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
+        }
 
         RCSDiscoveryManagerImpl* RCSDiscoveryManagerImpl::getInstance()
         {
-            if (!s_instance)
-            {
-                s_mutexForCreation.lock();
-                if (!s_instance)
-                {
-                    s_instance = new RCSDiscoveryManagerImpl();
-                    srand(time(NULL));
-                    s_instance->initializedDiscoveryEnvironment();
-                    s_instance->requestMulticastPresence();
-                    s_instance->m_timerHandle = s_instance->m_timer.post(INTERVALTIME, s_instance->m_pollingCB);
-                }
-                s_mutexForCreation.unlock();
-            }
-            return s_instance;
+            static RCSDiscoveryManagerImpl instance;
+            return &instance;
         }
 
-        void RCSDiscoveryManagerImpl::findCallback(std::shared_ptr< PrimitiveResource > resource,
-            RCSDiscoveryManagerImpl::ID discoverID)
+        void RCSDiscoveryManagerImpl::onResourceFound(
+                std::shared_ptr< PrimitiveResource > resource, ID discoveryId,
+                const RCSDiscoveryManager::ResourceDiscoveredCallback& discoverCB)
         {
-            std::unique_lock<std::mutex> lock(m_mutex);
-
-           if(!isDuplicatedCallback(resource,discoverID))
             {
-               for(auto it = m_discoveryMap.begin(); it != m_discoveryMap.end(); ++it)
-               {
-                   if(it->first == discoverID)
-                   {
-                        it->second.m_isReceivedFindCallback = true;
-                        it->second.m_discoverCB(std::make_shared<RCSRemoteResourceObject>(resource));
-                   }
-                }
+                std::lock_guard < std::mutex > lock(m_mutex);
+                auto it = m_discoveryMap.find(discoveryId);
+
+                if (it == m_discoveryMap.end()) return;
+                if (it->second.isKnownResource(resource)) return;
+
+                it->second.addKnownResource(resource);
             }
+            discoverCB(std::make_shared < RCSRemoteResourceObject > (resource));
         }
 
-        std::unique_ptr<RCSDiscoveryManager::DiscoveryTask> RCSDiscoveryManagerImpl::startDiscovery
-        (const RCSAddress& address, const std::string& relativeURI, const std::string& resourceType,
+        RCSDiscoveryManager::DiscoveryTask::Ptr RCSDiscoveryManagerImpl::startDiscovery(
+                const RCSAddress& address, const std::string& relativeUri,
+                const std::vector< std::string >& resourceTypes,
                 RCSDiscoveryManager::ResourceDiscoveredCallback cb)
         {
             if (!cb)
             {
-                throw InvalidParameterException { "input Parameter(callback) is NULL" };
+                throw RCSInvalidParameterException{ "Callback is empty" };
             }
 
-            DiscoverRequestInfo discoveryItem;
-            discoveryItem.m_address = RCSAddressDetail::getDetail(address)->getAddress();
-            discoveryItem.m_relativeUri = relativeURI;
-            discoveryItem.m_resourceType = resourceType;
-            discoveryItem.m_discoverCB = std::move(cb);
-            discoveryItem.m_isReceivedFindCallback = false;
+            validateTypes(resourceTypes);
 
-            ID discoverID = createId();
-            discoveryItem.m_findCB = std::bind(&RCSDiscoveryManagerImpl::findCallback, this,
-                    std::placeholders::_1, discoverID);
-            m_discoveryMap.insert(std::make_pair(discoverID, discoveryItem));
+            const ID discoveryId = createId();
 
-            OIC::Service::discoverResource(RCSAddressDetail::getDetail(RCSAddress::multicast())->getAddress(),
-                    discoveryItem.m_relativeUri + "?rt=" +discoveryItem.m_resourceType,
-                    OCConnectivityType::CT_DEFAULT, discoveryItem.m_findCB);
+            DiscoveryRequestInfo discoveryInfo(address, relativeUri, resourceTypes,
+                    std::bind(&RCSDiscoveryManagerImpl::onResourceFound, this,
+                            std::placeholders::_1, discoveryId, std::move(cb)));
 
-            return std::unique_ptr<RCSDiscoveryManager::DiscoveryTask>(
-                    new RCSDiscoveryManager::DiscoveryTask(discoverID));
-        }
+            discoveryInfo.discover();
 
-        void RCSDiscoveryManagerImpl::initializedDiscoveryEnvironment()
-        {
-            m_presenceCB = std::bind(&RCSDiscoveryManagerImpl::presenceCallback, this,
-                    std::placeholders::_1, std::placeholders::_2,std::placeholders::_3);
-            m_pollingCB = std::bind(&RCSDiscoveryManagerImpl::pollingCallback, this,
-                std::placeholders::_1);
+            {
+                std::lock_guard < std::mutex > lock(m_mutex);
+                m_discoveryMap.insert(std::make_pair(discoveryId, std::move(discoveryInfo)));
+            }
+
+            return std::unique_ptr< RCSDiscoveryManager::DiscoveryTask >(
+                    new RCSDiscoveryManager::DiscoveryTask(discoveryId));
         }
 
-        void RCSDiscoveryManagerImpl::requestMulticastPresence()
+        void RCSDiscoveryManagerImpl::subscribePresenceWithMulticast()
         {
-            static constexpr char MULTICAST_PRESENCE_ADDRESS[] = "coap://" OC_MULTICAST_PREFIX;
+            using namespace std::placeholders;
+
+            constexpr char MULTICAST_PRESENCE_ADDRESS[] = "coap://" OC_MULTICAST_PREFIX;
+
             OCDoHandle presenceHandle;
             subscribePresence(presenceHandle, MULTICAST_PRESENCE_ADDRESS,
-                            OCConnectivityType::CT_DEFAULT, std::move(m_presenceCB));
+                    OCConnectivityType::CT_DEFAULT,
+                    std::bind(&RCSDiscoveryManagerImpl::onPresence, this, _1, _2, _3));
         }
 
-        bool RCSDiscoveryManagerImpl::isDuplicatedCallback(std::shared_ptr< PrimitiveResource > resource,
-                ID discoverID)
+        void RCSDiscoveryManagerImpl::onPolling()
         {
-            std::string retID = resource->getSid()+resource->getUri();
-            auto it = m_discoveryMap.find(discoverID);
-            std::list<std::string>::iterator itor;
-            if(it==m_discoveryMap.end())
             {
-                return false;
-            }
-            itor = std::find(it->second.m_receivedIds.begin(),it->second.m_receivedIds.end(),retID);
-            if(itor != it->second.m_receivedIds.end())
-            {
-              return true;
-            }
-            it->second.m_receivedIds.push_back(retID);
-
-            return false;
-        }
+                std::lock_guard < std::mutex > lock(m_mutex);
 
-        void RCSDiscoveryManagerImpl::pollingCallback(unsigned int /*msg*/)
-        {
-            std::unique_lock<std::mutex> lock(m_mutex);
-            for(auto it = m_discoveryMap.begin(); it != m_discoveryMap.end(); ++it)
-            {
-                OIC::Service::discoverResource(it->second.m_address,it->second.m_relativeUri+ "?rt="
-                        +it->second.m_resourceType, OCConnectivityType::CT_DEFAULT, it->second.m_findCB);
+                for (const auto& it : m_discoveryMap)
+                {
+                    it.second.discover();
+                }
             }
-            m_timerHandle = m_timer.post(INTERVALTIME, m_pollingCB);
+            m_timer.post(POLLING_INTERVAL_TIME,
+                    std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
         }
 
-        void RCSDiscoveryManagerImpl::presenceCallback(OCStackResult ret,
-                const unsigned int /*seq*/, const std::string& /*address*/)
+        void RCSDiscoveryManagerImpl::onPresence(OCStackResult result, const unsigned int /*seq*/,
+                const std::string& address)
         {
-            if(ret == OC_STACK_OK || ret == OC_STACK_RESOURCE_CREATED || ret == OC_STACK_RESOURCE_DELETED)
+            if (result != OC_STACK_OK && result != OC_STACK_RESOURCE_CREATED) return;
+
+            std::lock_guard < std::mutex > lock(m_mutex);
+            for (const auto& it : m_discoveryMap)
             {
-                std::unique_lock<std::mutex> lock(m_mutex);
-                for(auto it = m_discoveryMap.begin(); it != m_discoveryMap.end(); ++it)
+                if (it.second.isMatchedAddress(address))
                 {
-                    if(!it->second.m_isReceivedFindCallback)
-                    {
-                        OIC::Service::discoverResource(it->second.m_address, it->second.m_relativeUri+ "?rt=" +
-                            it->second.m_resourceType, OCConnectivityType::CT_DEFAULT, it->second.m_findCB);
-                    }
+                    it.second.discover();
                 }
             }
         }
 
-        RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::createId()
+        RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::createId() const
         {
-            std::unique_lock<std::mutex> lock(m_mutex);
-            if(s_uniqueId<LIMITNUMBER)
+            static ID s_nextId = INVALID_ID + 1;
+
+            std::lock_guard < std::mutex > lock(m_mutex);
+
+            while (s_nextId == INVALID_ID || m_discoveryMap.find(s_nextId) != m_discoveryMap.end())
             {
-                 s_uniqueId++;
+                ++s_nextId;
             }
-            else
+
+            assert(s_nextId != INVALID_ID && "Invalid ID!");
+
+            return s_nextId++;
+        }
+
+        void RCSDiscoveryManagerImpl::cancel(ID id)
+        {
+            std::lock_guard < std::mutex > lock(m_mutex);
+            m_discoveryMap.erase(id);
+        }
+
+        DiscoveryRequestInfo::DiscoveryRequestInfo(const RCSAddress& address,
+                const std::string& relativeUri, const std::vector< std::string >& resourceTypes,
+                DiscoverCallback cb) :
+                m_address{ address },
+                m_relativeUri{ relativeUri },
+                m_resourceTypes{ resourceTypes },
+                m_knownResourceIds{ },
+                m_discoverCb{ std::move(cb) }
+        {
+            if (m_resourceTypes.empty())
             {
-                s_uniqueId = RESETNUMBER;
+                m_resourceTypes.push_back(RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE);
             }
-            while(m_discoveryMap.size() != LIMITNUMBER)
+        }
+
+        void DiscoveryRequestInfo::discover() const
+        {
+            for (const auto& it : m_resourceTypes)
             {
-                if(m_discoveryMap.find(s_uniqueId) == m_discoveryMap.end())
+                std::string uri = std::string(OC_RSRVD_WELL_KNOWN_URI);
+                if (!it.empty())
                 {
-                    return s_uniqueId;
+                    uri = std::string(OC_RSRVD_WELL_KNOWN_URI) + "?rt=" + it;
                 }
-                s_uniqueId++;
+                discoverResource(m_address, uri, m_discoverCb);
             }
+        }
 
-            return RESETNUMBER;
+        bool DiscoveryRequestInfo::isKnownResource(
+                const std::shared_ptr< PrimitiveResource >& resource) const
+        {
+            return m_knownResourceIds.find(makeResourceId(resource)) != m_knownResourceIds.end();
+        }
+
+        void DiscoveryRequestInfo::addKnownResource(
+                const std::shared_ptr< PrimitiveResource >& resource)
+        {
+            m_knownResourceIds.insert(makeResourceId(resource));
+        }
+
+        bool DiscoveryRequestInfo::isMatchedAddress(const std::string& address) const
+        {
+            return RCSAddressDetail::getDetail(m_address)->isMulticast()
+                    || RCSAddressDetail::getDetail(m_address)->getAddress() == address;
         }
     }
 }