Merge branch 'easysetup'
[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
21 #include "RCSDiscoveryManagerImpl.h"
22
23 #include "OCPlatform.h"
24 #include "PresenceSubscriber.h"
25 #include "RCSAddressDetail.h"
26 #include "RCSAddress.h"
27 #include "RCSRemoteResourceObject.h"
28
29 namespace
30 {
31     constexpr unsigned int POLLING_INTERVAL_TIME = 60000;
32
33     std::string makeResourceId(const std::shared_ptr< OIC::Service::PrimitiveResource >& resource)
34     {
35         return resource->getSid() + resource->getUri();
36     }
37
38     void validateTypes(const std::vector< std::string >& resourceTypes) {
39         if (resourceTypes.size() == 1) return;
40
41         for (const auto& type : resourceTypes)
42         {
43             if (type == OIC::Service::RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE)
44             {
45                 throw OIC::Service::RCSBadRequestException{
46                     "resource types must have no empty string!" };
47             }
48         }
49     }
50 }
51
52 namespace OIC
53 {
54     namespace Service
55     {
56         constexpr RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::INVALID_ID;
57         constexpr char const* RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE;
58
59         RCSDiscoveryManagerImpl::RCSDiscoveryManagerImpl()
60         {
61             subscribePresenceWithMulticast();
62
63             m_timer.post(POLLING_INTERVAL_TIME,
64                     std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
65         }
66
67         RCSDiscoveryManagerImpl* RCSDiscoveryManagerImpl::getInstance()
68         {
69             static RCSDiscoveryManagerImpl instance;
70             return &instance;
71         }
72
73         void RCSDiscoveryManagerImpl::onResourceFound(
74                 std::shared_ptr< PrimitiveResource > resource, ID discoveryId,
75                 const RCSDiscoveryManager::ResourceDiscoveredCallback& discoverCB)
76         {
77             {
78                 std::lock_guard < std::mutex > lock(m_mutex);
79                 auto it = m_discoveryMap.find(discoveryId);
80
81                 if (it == m_discoveryMap.end()) return;
82                 if (it->second.isKnownResource(resource)) return;
83
84                 it->second.addKnownResource(resource);
85             }
86             discoverCB(std::make_shared < RCSRemoteResourceObject > (resource));
87         }
88
89         RCSDiscoveryManager::DiscoveryTask::Ptr RCSDiscoveryManagerImpl::startDiscovery(
90                 const RCSAddress& address, const std::string& relativeUri,
91                 const std::vector< std::string >& resourceTypes,
92                 RCSDiscoveryManager::ResourceDiscoveredCallback cb)
93         {
94             if (!cb)
95             {
96                 throw RCSInvalidParameterException{ "Callback is empty" };
97             }
98
99             validateTypes(resourceTypes);
100
101             const ID discoveryId = createId();
102
103             DiscoveryRequestInfo discoveryInfo(address, relativeUri, resourceTypes,
104                     std::bind(&RCSDiscoveryManagerImpl::onResourceFound, this,
105                             std::placeholders::_1, discoveryId, std::move(cb)));
106
107             discoveryInfo.discover();
108
109             {
110                 std::lock_guard < std::mutex > lock(m_mutex);
111                 m_discoveryMap.insert(std::make_pair(discoveryId, std::move(discoveryInfo)));
112             }
113
114             return std::unique_ptr< RCSDiscoveryManager::DiscoveryTask >(
115                     new RCSDiscoveryManager::DiscoveryTask(discoveryId));
116         }
117
118         void RCSDiscoveryManagerImpl::subscribePresenceWithMulticast()
119         {
120             using namespace std::placeholders;
121
122             constexpr char MULTICAST_PRESENCE_ADDRESS[] = "coap://" OC_MULTICAST_PREFIX;
123
124             OCDoHandle presenceHandle;
125             subscribePresence(presenceHandle, MULTICAST_PRESENCE_ADDRESS,
126                     OCConnectivityType::CT_DEFAULT,
127                     std::bind(&RCSDiscoveryManagerImpl::onPresence, this, _1, _2, _3));
128         }
129
130         void RCSDiscoveryManagerImpl::onPolling()
131         {
132             {
133                 std::lock_guard < std::mutex > lock(m_mutex);
134
135                 for (const auto& it : m_discoveryMap)
136                 {
137                     it.second.discover();
138                 }
139             }
140             m_timer.post(POLLING_INTERVAL_TIME,
141                     std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
142         }
143
144         void RCSDiscoveryManagerImpl::onPresence(OCStackResult result, const unsigned int /*seq*/,
145                 const std::string& address)
146         {
147             if (result != OC_STACK_OK && result != OC_STACK_RESOURCE_CREATED) return;
148
149             std::lock_guard < std::mutex > lock(m_mutex);
150             for (const auto& it : m_discoveryMap)
151             {
152                 if (it.second.isMatchedAddress(address))
153                 {
154                     it.second.discover();
155                 }
156             }
157         }
158
159         RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::createId() const
160         {
161             static ID s_nextId = INVALID_ID + 1;
162
163             std::lock_guard < std::mutex > lock(m_mutex);
164
165             while (s_nextId == INVALID_ID || m_discoveryMap.find(s_nextId) != m_discoveryMap.end())
166             {
167                 ++s_nextId;
168             }
169
170             assert(s_nextId != INVALID_ID && "Invalid ID!");
171
172             return s_nextId++;
173         }
174
175         void RCSDiscoveryManagerImpl::cancel(ID id)
176         {
177             std::lock_guard < std::mutex > lock(m_mutex);
178             m_discoveryMap.erase(id);
179         }
180
181         DiscoveryRequestInfo::DiscoveryRequestInfo(const RCSAddress& address,
182                 const std::string& relativeUri, const std::vector< std::string >& resourceTypes,
183                 DiscoverCallback cb) :
184                 m_address{ address },
185                 m_relativeUri{ relativeUri },
186                 m_resourceTypes{ resourceTypes },
187                 m_knownResourceIds{ },
188                 m_discoverCb{ std::move(cb) }
189         {
190             if (m_resourceTypes.empty())
191             {
192                 m_resourceTypes.push_back(RCSDiscoveryManagerImpl::ALL_RESOURCE_TYPE);
193             }
194         }
195
196         void DiscoveryRequestInfo::discover() const
197         {
198             for (const auto& it : m_resourceTypes)
199             {
200                 discoverResource(m_address, m_relativeUri + "?rt=" + it, m_discoverCb);
201             }
202         }
203
204         bool DiscoveryRequestInfo::isKnownResource(
205                 const std::shared_ptr< PrimitiveResource >& resource) const
206         {
207             return m_knownResourceIds.find(makeResourceId(resource)) != m_knownResourceIds.end();
208         }
209
210         void DiscoveryRequestInfo::addKnownResource(
211                 const std::shared_ptr< PrimitiveResource >& resource)
212         {
213             m_knownResourceIds.insert(makeResourceId(resource));
214         }
215
216         bool DiscoveryRequestInfo::isMatchedAddress(const std::string& address) const
217         {
218             return RCSAddressDetail::getDetail(m_address)->isMulticast()
219                     || RCSAddressDetail::getDetail(m_address)->getAddress() == address;
220         }
221     }
222 }