Fix invalid memory access on resource cache module.
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / resourceCache / src / DataCache.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 <memory>
22 #include <cstdlib>
23 #include <functional>
24 #include <map>
25 #include <utility>
26 #include <ctime>
27
28 #include "DataCache.h"
29
30 #include "ResponseStatement.h"
31 #include "RCSResourceAttributes.h"
32 #include "ExpiryTimer.h"
33
34 namespace OIC
35 {
36     namespace Service
37     {
38
39         namespace
40         {
41             std::mutex cbMutex;
42             void vertifyObserveCB(
43                 const HeaderOptions &_hos, const ResponseStatement &_rep,
44                 int _result, int _seq, std::weak_ptr<DataCache> rpPtr)
45             {
46                 std::lock_guard<std::mutex> lock(cbMutex);
47                 std::shared_ptr<DataCache> Ptr = rpPtr.lock();
48                 if(Ptr)
49                 {
50                     Ptr->onObserve(_hos, _rep, _result, _seq);
51                 }
52             }
53             ObserveCB vertifiedObserveCB(std::weak_ptr<DataCache> rpPtr)
54             {
55                 return std::bind(vertifyObserveCB,
56                         std::placeholders::_1, std::placeholders::_2,
57                         std::placeholders::_3, std::placeholders::_4, rpPtr);
58             }
59
60             void vertifyGetCB(
61                     const HeaderOptions &_hos, const ResponseStatement &_rep,
62                     int _result, std::weak_ptr<DataCache> rpPtr)
63             {
64                 std::lock_guard<std::mutex> lock(cbMutex);
65                 std::shared_ptr<DataCache> Ptr = rpPtr.lock();
66                 if(Ptr)
67                 {
68                     Ptr->onGet(_hos, _rep, _result);
69                 }
70             }
71             GetCB vertifiedGetCB(std::weak_ptr<DataCache> rpPtr)
72             {
73                 return std::bind(vertifyGetCB,
74                         std::placeholders::_1, std::placeholders::_2,
75                         std::placeholders::_3, rpPtr);
76             }
77         }
78
79         DataCache::DataCache()
80         {
81             subscriberList = std::unique_ptr<SubscriberInfo>(new SubscriberInfo());
82
83             sResource = nullptr;
84
85             state = CACHE_STATE::READY_YET;
86             mode = CACHE_MODE::FREQUENCY;
87
88             networkTimeOutHandle = 0;
89             pollingHandle = 0;
90         }
91
92         DataCache::~DataCache()
93         {
94             state = CACHE_STATE::DESTROYED;
95
96             if (subscriberList != nullptr)
97             {
98                 subscriberList->clear();
99                 subscriberList.release();
100             }
101
102             if(mode == CACHE_MODE::OBSERVE)
103             {
104                 try
105                 {
106                     sResource->cancelObserve();
107                 } catch (...)
108                 {
109                     // ignore the exception because data cache was released.
110                 }
111             }
112         }
113
114         void DataCache::initializeDataCache(PrimitiveResourcePtr pResource)
115         {
116             sResource = pResource;
117             pObserveCB = vertifiedObserveCB(std::weak_ptr<DataCache>(shared_from_this()));
118             pGetCB = vertifiedGetCB(std::weak_ptr<DataCache>(shared_from_this()));
119             pTimerCB = (TimerCB)(std::bind(&DataCache::onTimeOut, this, std::placeholders::_1));
120             pPollingCB = (TimerCB)(std::bind(&DataCache::onPollingOut, this, std::placeholders::_1));
121
122             sResource->requestGet(pGetCB);
123             if (sResource->isObservable())
124             {
125                 sResource->requestObserve(pObserveCB);
126             }
127             networkTimeOutHandle = networkTimer.postTimer(CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
128         }
129
130         CacheID DataCache::addSubscriber(CacheCB func, REPORT_FREQUENCY rf, long repeatTime)
131         {
132             Report_Info newItem;
133             newItem.rf = rf;
134             newItem.repeatTime = repeatTime;
135             newItem.timerID = 0;
136
137             newItem.reportID = generateCacheID();
138
139             std::lock_guard<std::mutex> lock(m_mutex);
140             if (subscriberList != nullptr)
141             {
142                 subscriberList->insert(
143                     std::make_pair(newItem.reportID, std::make_pair(newItem, func)));
144             }
145
146             return newItem.reportID;
147         }
148
149         CacheID DataCache::deleteSubscriber(CacheID id)
150         {
151             CacheID ret = 0;
152
153             SubscriberInfoPair pair = findSubscriber(id);
154
155             std::lock_guard<std::mutex> lock(m_mutex);
156             if (pair.first != 0)
157             {
158                 ret = pair.first;
159                 subscriberList->erase(pair.first);
160             }
161
162             return ret;
163         }
164
165         SubscriberInfoPair DataCache::findSubscriber(CacheID id)
166         {
167             SubscriberInfoPair ret;
168
169             std::lock_guard<std::mutex> lock(m_mutex);
170             for (auto &i : *subscriberList)
171             {
172                 if (i.first == id)
173                 {
174                     ret = std::make_pair(i.first, std::make_pair((Report_Info)i.second.first,
175                                          (CacheCB)i.second.second));
176                     break;
177                 }
178             }
179
180             return ret;
181         }
182
183         const PrimitiveResourcePtr DataCache::getPrimitiveResource() const
184         {
185             return (sResource != nullptr) ? sResource : nullptr;
186         }
187
188         const RCSResourceAttributes DataCache::getCachedData() const
189         {
190             if (state != CACHE_STATE::READY || attributes.empty())
191             {
192                 return RCSResourceAttributes();
193             }
194             const RCSResourceAttributes retAtt = attributes;
195             return retAtt;
196         }
197
198         void DataCache::onObserve(
199             const HeaderOptions &_hos, const ResponseStatement &_rep, int _result, int _seq)
200         {
201
202             if (_result != OC_STACK_OK || _rep.getAttributes().empty())
203             {
204                 return;
205             }
206
207             if (state != CACHE_STATE::READY)
208             {
209                 state = CACHE_STATE::READY;
210             }
211
212             if (mode != CACHE_MODE::OBSERVE)
213             {
214                 mode = CACHE_MODE::OBSERVE;
215             }
216
217             networkTimer.cancelTimer(networkTimeOutHandle);
218             networkTimeOutHandle = networkTimer.postTimer(CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
219
220             notifyObservers(_rep.getAttributes());
221         }
222
223         void DataCache::onGet(const HeaderOptions &_hos,
224                               const ResponseStatement &_rep, int _result)
225         {
226             if (_result != OC_STACK_OK || _rep.getAttributes().empty())
227             {
228                 return;
229             }
230
231             if (state != CACHE_STATE::READY)
232             {
233                 state = CACHE_STATE::READY;
234             }
235
236             if (mode != CACHE_MODE::OBSERVE)
237             {
238                 networkTimer.cancelTimer(networkTimeOutHandle);
239                 networkTimeOutHandle = networkTimer.postTimer(
240                                            CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
241
242                 pollingHandle = pollingTimer.postTimer(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
243             }
244
245             notifyObservers(_rep.getAttributes());
246         }
247
248         void DataCache::notifyObservers(const RCSResourceAttributes Att)
249         {
250             if (attributes == Att)
251             {
252                 return;
253             }
254
255             attributes = Att;
256
257             std::lock_guard<std::mutex> lock(m_mutex);
258             for (auto &i : * subscriberList)
259             {
260                 if (i.second.first.rf == REPORT_FREQUENCY::UPTODATE)
261                 {
262                     i.second.second(this->sResource, Att);
263                 }
264             }
265         }
266
267         CACHE_STATE DataCache::getCacheState() const
268         {
269             return state;
270         }
271
272         void DataCache::onTimeOut(unsigned int timerID)
273         {
274             if(mode == CACHE_MODE::OBSERVE)
275             {
276                 sResource->cancelObserve();
277                 mode = CACHE_MODE::FREQUENCY;
278
279                 networkTimer.cancelTimer(networkTimeOutHandle);
280                 networkTimeOutHandle = networkTimer.postTimer(
281                         CACHE_DEFAULT_EXPIRED_MILLITIME, pTimerCB);
282
283                 pollingHandle = pollingTimer.postTimer(CACHE_DEFAULT_REPORT_MILLITIME, pPollingCB);
284                 return;
285             }
286
287             state = CACHE_STATE::LOST_SIGNAL;
288         }
289         void DataCache::onPollingOut(const unsigned int timerID)
290         {
291             if (sResource != nullptr)
292             {
293                 mode = CACHE_MODE::FREQUENCY;
294                 sResource->requestGet(pGetCB);
295             }
296             return;
297         }
298
299         CacheID DataCache::generateCacheID()
300         {
301             CacheID retID = 0;
302             srand(time(NULL));
303
304             while (1)
305             {
306                 if (findSubscriber(retID).first == 0 && retID != 0)
307                 {
308                     break;
309                 }
310                 retID = rand();
311             }
312
313             return retID;
314         }
315
316         void DataCache::requestGet()
317         {
318             state = CACHE_STATE::UPDATING;
319             if (sResource != nullptr)
320             {
321                 sResource->requestGet(pGetCB);
322             }
323         }
324
325         bool DataCache::isEmptySubscriber() const
326         {
327             std::lock_guard<std::mutex> lock(m_mutex);
328             return (subscriberList != nullptr) ? subscriberList->empty() : true;
329         }
330     } // namespace Service
331 } // namespace OIC