Refactored 'RCSDiscoveryManager'
[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
39 namespace OIC
40 {
41     namespace Service
42     {
43         constexpr RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::INVALID_ID;
44
45         RCSDiscoveryManagerImpl::RCSDiscoveryManagerImpl()
46         {
47             subscribePresenceWithMuticast();
48
49             m_timer.post(POLLING_INTERVAL_TIME, std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
50         }
51
52         RCSDiscoveryManagerImpl* RCSDiscoveryManagerImpl::getInstance()
53         {
54             static RCSDiscoveryManagerImpl instance;
55             return &instance;
56         }
57
58         void RCSDiscoveryManagerImpl::onResourceFound(std::shared_ptr<PrimitiveResource> resource,
59                 ID discoveryId, const RCSDiscoveryManager::ResourceDiscoveredCallback& discoverCB)
60         {
61             {
62                 std::lock_guard< std::mutex > lock(m_mutex);
63                 auto it = m_discoveryMap.find(discoveryId);
64
65                 if (it == m_discoveryMap.end()) return;
66                 if (it->second.isKnownResource(resource)) return;
67
68                 it->second.addKnownResource(resource);
69             }
70             discoverCB(std::make_shared< RCSRemoteResourceObject > (resource));
71         }
72
73         RCSDiscoveryManager::DiscoveryTask::Ptr RCSDiscoveryManagerImpl::startDiscovery(
74                 const RCSAddress& address, const std::string& relativeUri,
75                 const std::string& resourceType, RCSDiscoveryManager::ResourceDiscoveredCallback cb)
76         {
77             if (!cb)
78             {
79                 throw RCSInvalidParameterException{ "Callback is empty" };
80             }
81
82             const ID discoveryId = createId();
83
84             DiscoveryRequestInfo discoveryInfo(address, relativeUri, resourceType,
85                     std::bind(&RCSDiscoveryManagerImpl::onResourceFound, this,
86                             std::placeholders::_1, discoveryId, std::move(cb)));
87             discoveryInfo.discover();
88
89             {
90                 std::lock_guard< std::mutex > lock(m_mutex);
91                 m_discoveryMap.insert(std::make_pair(discoveryId, std::move(discoveryInfo)));
92             }
93
94             return std::unique_ptr< RCSDiscoveryManager::DiscoveryTask >(
95                     new RCSDiscoveryManager::DiscoveryTask(discoveryId));
96         }
97
98         void RCSDiscoveryManagerImpl::subscribePresenceWithMuticast()
99         {
100             using namespace std::placeholders;
101
102             constexpr char MULTICAST_PRESENCE_ADDRESS[] = "coap://" OC_MULTICAST_PREFIX;
103
104             OCDoHandle presenceHandle;
105             subscribePresence(presenceHandle, MULTICAST_PRESENCE_ADDRESS,
106                     OCConnectivityType::CT_DEFAULT,
107                     std::bind(&RCSDiscoveryManagerImpl::onPresence, this, _1, _2, _3));
108         }
109
110         void RCSDiscoveryManagerImpl::onPolling()
111         {
112             {
113                 std::lock_guard< std::mutex > lock(m_mutex);
114
115                 for (const auto& it : m_discoveryMap)
116                 {
117                     it.second.discover();
118                 }
119             }
120             m_timer.post(POLLING_INTERVAL_TIME, std::bind(&RCSDiscoveryManagerImpl::onPolling, this));
121         }
122
123         void RCSDiscoveryManagerImpl::onPresence(OCStackResult result, const unsigned int /*seq*/,
124                 const std::string& address)
125         {
126             if (result != OC_STACK_OK && result != OC_STACK_RESOURCE_CREATED) return;
127
128             std::lock_guard< std::mutex > lock(m_mutex);
129             for (const auto& it : m_discoveryMap)
130             {
131                 if (it.second.isMatchedAddress(address))
132                 {
133                     it.second.discover();
134                 }
135             }
136         }
137
138         RCSDiscoveryManagerImpl::ID RCSDiscoveryManagerImpl::createId() const
139         {
140             static ID s_nextId = INVALID_ID + 1;
141
142             std::lock_guard< std::mutex > lock(m_mutex);
143
144             while (s_nextId == INVALID_ID || m_discoveryMap.find(s_nextId) != m_discoveryMap.end())
145             {
146                 ++s_nextId;
147             }
148
149             assert(s_nextId != INVALID_ID && "Invalid ID!");
150
151             return s_nextId++;
152         }
153
154         void RCSDiscoveryManagerImpl::cancel(ID id)
155         {
156             std::lock_guard< std::mutex > lock(m_mutex);
157             m_discoveryMap.erase(id);
158         }
159
160         DiscoveryRequestInfo::DiscoveryRequestInfo(const RCSAddress& address,
161                 const std::string& relativeUri, const std::string& resourceType,
162                 DiscoverCallback cb) :
163                 m_address{ address },
164                 m_relativeUri{ relativeUri },
165                 m_resourceType{ resourceType },
166                 m_knownResourceIds{ },
167                 m_discoverCb{ std::move(cb) }
168         {
169         }
170
171         void DiscoveryRequestInfo::discover() const
172         {
173             discoverResource(m_address, m_relativeUri + "?rt=" + m_resourceType, m_discoverCb);
174         }
175
176         bool DiscoveryRequestInfo::isKnownResource(
177                 const std::shared_ptr< PrimitiveResource >& resource) const
178         {
179             return m_knownResourceIds.find(makeResourceId(resource)) != m_knownResourceIds.end();
180         }
181
182         void DiscoveryRequestInfo::addKnownResource(
183                 const std::shared_ptr< PrimitiveResource >& resource)
184         {
185             m_knownResourceIds.insert(makeResourceId(resource));
186         }
187
188         bool DiscoveryRequestInfo::isMatchedAddress(const std::string& address) const
189         {
190             return RCSAddressDetail::getDetail(m_address)->isMulticast() ||
191                     RCSAddressDetail::getDetail(m_address)->getAddress() == address;
192         }
193     }
194 }