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