modify timing issue and add test case for DiscoveryManagerUnitTest
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / resourceClient / RCSDiscoveryManagerImpl.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 #include <limits>
21
22 #include "RCSDiscoveryManagerImpl.h"
23
24 #include "OCPlatform.h"
25 #include "PresenceSubscriber.h"
26 #include "RCSAddressDetail.h"
27 #include "RCSAddress.h"
28
29 namespace
30 {
31     constexpr unsigned int LIMITNUMBER = std::numeric_limits<unsigned int>::max();
32     constexpr unsigned int INTERVALTIME = 60000;
33 }
34
35 namespace OIC
36 {
37     namespace Service
38     {
39         RCSDiscoveryManagerImpl::RCSDiscoveryManagerImpl()
40         {
41             srand(time(NULL));
42             requestMulticastPresence();
43             m_timer.post(INTERVALTIME, std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
44         }
45
46         RCSDiscoveryManagerImpl* RCSDiscoveryManagerImpl::getInstance()
47         {
48             static RCSDiscoveryManagerImpl instance;
49             return &instance;
50         }
51
52         void RCSDiscoveryManagerImpl::onResourceFound(std::shared_ptr< PrimitiveResource > resource,
53                     RCSDiscoveryManagerImpl::ID discoveryId,
54                     const RCSDiscoveryManager::ResourceDiscoveredCallback& discoverCB)
55         {
56             {
57                 std::lock_guard<std::mutex> lock(m_mutex);
58                 auto it = m_discoveryMap.find(discoveryId);
59
60                 if(it == m_discoveryMap.end()) return;
61                 if(it->second.isKnownResource(resource)) return;
62             }
63             discoverCB(std::make_shared<RCSRemoteResourceObject>(resource));
64         }
65
66         RCSDiscoveryManager::DiscoveryTask::Ptr RCSDiscoveryManagerImpl::startDiscovery
67                 (const RCSAddress& address, const std::string& relativeUri, const std::string& resourceType,
68                         RCSDiscoveryManager::ResourceDiscoveredCallback cb)
69         {
70             if (!cb)
71             {
72                 throw RCSInvalidParameterException { "Callback is empty" };
73             }
74
75             ID discoveryId = createId();
76             auto discoverCb = std::bind(&RCSDiscoveryManagerImpl::onResourceFound, this,
77                     std::placeholders::_1, discoveryId, std::move(cb));
78             DiscoveryRequestInfo discoveryItem(RCSAddressDetail::getDetail(address)->getAddress(), relativeUri,
79                     resourceType, std::move(discoverCb));
80             discoveryItem.discoverRequest();
81
82             std::lock_guard<std::mutex> lock(m_mutex);
83             m_discoveryMap.insert(std::make_pair(discoveryId, std::move(discoveryItem)));
84
85             return std::unique_ptr<RCSDiscoveryManager::DiscoveryTask>(
86                     new RCSDiscoveryManager::DiscoveryTask(discoveryId));
87         }
88
89         void RCSDiscoveryManagerImpl::requestMulticastPresence()
90         {
91             static constexpr char MULTICAST_PRESENCE_ADDRESS[] = "coap://" OC_MULTICAST_PREFIX;
92             OCDoHandle presenceHandle;
93             subscribePresence(presenceHandle, MULTICAST_PRESENCE_ADDRESS, OCConnectivityType::CT_DEFAULT,
94                     std::move(std::bind(&RCSDiscoveryManagerImpl::onPresence, this,
95                             std::placeholders::_1, std::placeholders::_2,std::placeholders::_3)));
96         }
97
98         void RCSDiscoveryManagerImpl::onPolling()
99         {
100             std::lock_guard<std::mutex> lock(m_mutex);
101
102             for(const auto& it : m_discoveryMap)
103             {
104                 it.second.discoverRequest();
105             }
106             m_timer.post(INTERVALTIME, std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
107         }
108
109         void RCSDiscoveryManagerImpl::onPresence(OCStackResult ret,
110                 const unsigned int /*seq*/, const std::string& address)
111         {
112             if(ret != OC_STACK_OK && ret != OC_STACK_RESOURCE_CREATED) return;
113
114             std::lock_guard<std::mutex> lock(m_mutex);
115             for(const auto& it : m_discoveryMap)
116             {
117                 if(it.second.isMatchingAddress(address))
118                 {
119                     it.second.discoverRequest();
120                 }
121             }
122         }
123
124         RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::createId()
125         {
126             std::lock_guard<std::mutex> lock(m_mutex);
127             static unsigned int s_uniqueId;
128
129             if(m_discoveryMap.size() >= LIMITNUMBER)
130             {
131                 throw RCSException { "Discovery request is full!" };
132             }
133             s_uniqueId++;
134             while(m_discoveryMap.find(s_uniqueId) != m_discoveryMap.end())
135             {
136                 s_uniqueId++;
137             }
138             return s_uniqueId;
139         }
140
141         void RCSDiscoveryManagerImpl::cancel(unsigned int id)
142         {
143             std::lock_guard<std::mutex> lock(m_mutex);
144             m_discoveryMap.erase(id);
145         }
146
147         bool RCSDiscoveryManagerImpl::isCanceled(unsigned int id)
148         {
149             std::lock_guard<std::mutex> lock(m_mutex);
150             auto it = m_discoveryMap.find(id);
151             if(it == m_discoveryMap.end()) return true;
152
153             return false;
154         }
155
156         DiscoveryRequestInfo::DiscoveryRequestInfo(const std::string &address, const std::string &relativeUri,
157                 const std::string &resourceType, DiscoverCallback cb) : m_address(address),
158                         m_relativeUri(relativeUri), m_resourceType(resourceType), m_discoverCB(cb) {}
159
160         void DiscoveryRequestInfo::discoverRequest() const
161         {
162             OIC::Service::discoverResource(m_address, m_relativeUri + "?rt=" + m_resourceType,
163                     OCConnectivityType::CT_DEFAULT, m_discoverCB);
164         }
165
166         bool DiscoveryRequestInfo::isKnownResource(const std::shared_ptr<PrimitiveResource>& resource)
167         {
168             std::string resourceId = resource->getSid() + resource->getUri();
169
170             auto it = std::find(m_receivedIds.begin(), m_receivedIds.end(), resourceId);
171
172             if(it != m_receivedIds.end()) return true;
173             m_receivedIds.push_back(resourceId);
174             return false;
175         }
176
177         bool DiscoveryRequestInfo::isMatchingAddress(const std::string& address) const
178         {
179             return m_address == RCSAddressDetail::getDetail(RCSAddress::multicast())->getAddress()
180                     || m_address == address;
181         }
182     }
183 }