[RE] Added Secure Resource Linux Sample Apps to the RE Layer
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / serverBuilder / src / RCSResourceObject.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 "RCSResourceObject.h"
22
23 #include <string>
24 #include <functional>
25 #include <vector>
26
27 #include "RequestHandler.h"
28 #include "AssertUtils.h"
29 #include "AtomicHelper.h"
30 #include "ResourceAttributesConverter.h"
31 #include "ResourceAttributesUtils.h"
32 #include "RCSRequest.h"
33
34 #include "logger.h"
35 #include "OCPlatform.h"
36
37 #define LOG_TAG "RCSResourceObject"
38
39 namespace
40 {
41     using namespace OIC::Service;
42
43     inline bool hasProperty(uint8_t base, uint8_t target)
44     {
45         return (base & target) == target;
46     }
47
48     inline uint8_t makePropertyFlags(uint8_t base, uint8_t target, bool add)
49     {
50         if (add)
51         {
52             return base | target;
53         }
54
55         return base & ~target;
56     }
57
58     template <typename RESPONSE>
59     OCEntityHandlerResult sendResponse(RCSResourceObject& resource,
60             const std::shared_ptr< OC::OCResourceRequest >& ocRequest, RESPONSE&& response)
61     {
62         auto ocResponse = response.getHandler()->buildResponse(resource);
63         ocResponse->setRequestHandle(ocRequest->getRequestHandle());
64         ocResponse->setResourceHandle(ocRequest->getResourceHandle());
65
66         try
67         {
68             if (OC::OCPlatform::sendResponse(ocResponse) == OC_STACK_OK)
69             {
70                 return OC_EH_OK;
71             }
72         }
73         catch (const OC::OCException& e)
74         {
75             OC_LOG_V(WARNING, LOG_TAG, "Error (%s)", e.what());
76         }
77
78         return OC_EH_ERROR;
79     }
80
81     RCSResourceAttributes getAttributesFromOCRequest(
82             const std::shared_ptr< OC::OCResourceRequest >& request)
83     {
84         return ResourceAttributesConverter::fromOCRepresentation(
85                 request->getResourceRepresentation());
86     }
87
88     template< typename HANDLER, typename RESPONSE =
89             typename std::decay<HANDLER>::type::result_type >
90     RESPONSE invokeHandler(RCSResourceAttributes& attrs,
91             const std::shared_ptr< OC::OCResourceRequest >& ocRequest,
92             std::shared_ptr< HANDLER > handler)
93     {
94         if (handler)
95         {
96             return (*handler)(RCSRequest{ ocRequest->getResourceUri() }, attrs);
97         }
98
99         return RESPONSE::defaultAction();
100     }
101
102     typedef void (RCSResourceObject::* AutoNotifyFunc)
103             (bool, RCSResourceObject::AutoNotifyPolicy) const;
104
105     std::function<void()> createAutoNotifyInvoker(AutoNotifyFunc autoNotifyFunc,
106             const RCSResourceObject& resourceObject, const RCSResourceAttributes& resourceAttributes,
107             RCSResourceObject::AutoNotifyPolicy autoNotifyPolicy)
108     {
109         if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::UPDATED)
110         {
111             auto&& compareAttributesFunc =
112                     std::bind(std::not_equal_to<RCSResourceAttributes>(),
113                                 resourceAttributes,
114                                 std::cref(resourceAttributes));
115             return std::bind(autoNotifyFunc,
116                     &resourceObject, std::move(compareAttributesFunc), autoNotifyPolicy);
117         }
118         else if(autoNotifyPolicy == RCSResourceObject::AutoNotifyPolicy::ALWAYS)
119         {
120             return std::bind(autoNotifyFunc,
121                     &resourceObject, true, autoNotifyPolicy);
122         }
123         return {};
124     }
125 } // unnamed namespace
126
127
128 namespace OIC
129 {
130     namespace Service
131     {
132
133         RCSResourceObject::Builder::Builder(const std::string& uri, const std::string& type,
134                 const std::string& interface) :
135                 m_uri{ uri },
136                 m_type{ type },
137                 m_interface{ interface },
138                 m_properties{ OC_DISCOVERABLE | OC_OBSERVABLE },
139                 m_resourceAttributes{ }
140         {
141         }
142
143         RCSResourceObject::Builder& RCSResourceObject::Builder::setDiscoverable(
144                 bool discoverable)
145         {
146             m_properties = ::makePropertyFlags(m_properties, OC_DISCOVERABLE, discoverable);
147             return *this;
148         }
149
150         RCSResourceObject::Builder& RCSResourceObject::Builder::setObservable(
151                 bool observable)
152         {
153             m_properties = ::makePropertyFlags(m_properties, OC_OBSERVABLE, observable);
154             return *this;
155         }
156
157         RCSResourceObject::Builder& RCSResourceObject::Builder::setSecureFlag(
158             bool secureFlag)
159         {
160             m_properties = ::makePropertyFlags(m_properties, OC_SECURE, secureFlag);
161             return *this;
162         }
163         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
164                 const RCSResourceAttributes& attrs)
165         {
166             m_resourceAttributes = attrs;
167             return *this;
168         }
169
170         RCSResourceObject::Builder& RCSResourceObject::Builder::setAttributes(
171                 RCSResourceAttributes&& attrs)
172         {
173             m_resourceAttributes = std::move(attrs);
174             return *this;
175         }
176
177         RCSResourceObject::Ptr RCSResourceObject::Builder::build()
178         {
179             OCResourceHandle handle{ nullptr };
180
181             RCSResourceObject::Ptr server {
182                 new RCSResourceObject{ m_properties, std::move(m_resourceAttributes) } };
183
184             OC::EntityHandler entityHandler{ std::bind(&RCSResourceObject::entityHandler,
185                     server.get(), std::placeholders::_1) };
186
187             typedef OCStackResult (*RegisterResource)(OCResourceHandle&, std::string&,
188                     const std::string&, const std::string&, OC::EntityHandler, uint8_t);
189
190             invokeOCFunc(static_cast<RegisterResource>(OC::OCPlatform::registerResource),
191                     handle, m_uri, m_type, m_interface, entityHandler, m_properties);
192
193             server->m_resourceHandle = handle;
194
195             return server;
196         }
197
198
199         RCSResourceObject::RCSResourceObject(uint8_t properties, RCSResourceAttributes&& attrs) :
200                 m_properties { properties },
201                 m_resourceHandle{ },
202                 m_resourceAttributes{ std::move(attrs) },
203                 m_getRequestHandler{ },
204                 m_setRequestHandler{ },
205                 m_autoNotifyPolicy { AutoNotifyPolicy::UPDATED },
206                 m_setRequestHandlerPolicy { SetRequestHandlerPolicy::NEVER },
207                 m_attributeUpdatedListeners{ },
208                 m_lockOwner{ },
209                 m_mutex{ },
210                 m_mutexAttributeUpdatedListeners{ }
211         {
212             m_lockOwner.reset(new AtomicThreadId);
213         }
214
215         RCSResourceObject::~RCSResourceObject()
216         {
217             if (m_resourceHandle)
218             {
219                 try
220                 {
221                     OC::OCPlatform::unregisterResource(m_resourceHandle);
222                 }
223                 catch (...)
224                 {
225                     OC_LOG(WARNING, LOG_TAG, "Failed to unregister resource.");
226                 }
227             }
228         }
229
230         template< typename K, typename V >
231         void RCSResourceObject::setAttributeInternal(K&& key, V&& value)
232         {
233             bool needToNotify = false;
234             bool valueUpdated = false;
235
236             {
237                 WeakGuard lock(*this);
238
239                 if (lock.hasLocked())
240                 {
241                     needToNotify = true;
242                     valueUpdated = testValueUpdated(key, value);
243                 }
244
245                 m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value);
246             }
247
248             if (needToNotify) autoNotify(valueUpdated);
249         }
250         void RCSResourceObject::setAttribute(const std::string& key,
251                 const RCSResourceAttributes::Value& value)
252         {
253             setAttributeInternal(key, value);
254         }
255
256         void RCSResourceObject::setAttribute(const std::string& key,
257                 RCSResourceAttributes::Value&& value)
258         {
259             setAttributeInternal(key, std::move(value));
260         }
261
262         void RCSResourceObject::setAttribute(std::string&& key,
263                 const RCSResourceAttributes::Value& value)
264         {
265             setAttributeInternal(std::move(key), value);
266         }
267
268         void RCSResourceObject::setAttribute(std::string&& key,
269                 RCSResourceAttributes::Value&& value)
270         {
271             setAttributeInternal(std::move(key), std::move(value));
272         }
273
274         RCSResourceAttributes::Value RCSResourceObject::getAttributeValue(
275                 const std::string& key) const
276         {
277             WeakGuard lock(*this);
278             return m_resourceAttributes.at(key);
279         }
280
281         bool RCSResourceObject::removeAttribute(const std::string& key)
282         {
283             bool needToNotify = false;
284             bool erased = false;
285             {
286                 WeakGuard lock(*this);
287
288                 if (m_resourceAttributes.erase(key))
289                 {
290                     erased = true;
291                     needToNotify = lock.hasLocked();
292                 }
293             }
294
295             if (needToNotify) autoNotify(true);
296
297             return erased;
298         }
299
300         bool RCSResourceObject::containsAttribute(const std::string& key) const
301         {
302             WeakGuard lock(*this);
303             return m_resourceAttributes.contains(key);
304         }
305
306         RCSResourceAttributes& RCSResourceObject::getAttributes()
307         {
308             expectOwnLock();
309             return m_resourceAttributes;
310         }
311
312         const RCSResourceAttributes& RCSResourceObject::getAttributes() const
313         {
314             expectOwnLock();
315             return m_resourceAttributes;
316         }
317
318         void RCSResourceObject::expectOwnLock() const
319         {
320             if (getLockOwner() != std::this_thread::get_id())
321             {
322                 throw NoLockException{ "Must acquire the lock first using LockGuard." };
323             }
324         }
325
326         std::thread::id RCSResourceObject::getLockOwner() const noexcept
327         {
328             return *m_lockOwner;
329         }
330
331         void RCSResourceObject::setLockOwner(std::thread::id&& id) const noexcept
332         {
333             m_lockOwner->store(std::move(id));
334         }
335
336         bool RCSResourceObject::isObservable() const
337         {
338             return ::hasProperty(m_properties, OC_OBSERVABLE);
339         }
340
341         bool RCSResourceObject::isDiscoverable() const
342         {
343             return ::hasProperty(m_properties, OC_DISCOVERABLE);
344         }
345
346         void RCSResourceObject::setGetRequestHandler(GetRequestHandler h)
347         {
348             m_getRequestHandler = std::make_shared< GetRequestHandler >(std::move(h));
349         }
350
351         void RCSResourceObject::setSetRequestHandler(SetRequestHandler h)
352         {
353             m_setRequestHandler = std::make_shared< SetRequestHandler >(std::move(h));
354         }
355
356         void RCSResourceObject::notify() const
357         {
358             typedef OCStackResult (*NotifyAllObservers)(OCResourceHandle);
359
360             invokeOCFuncWithResultExpect({ OC_STACK_OK, OC_STACK_NO_OBSERVERS },
361                     static_cast< NotifyAllObservers >(OC::OCPlatform::notifyAllObservers),
362                     m_resourceHandle);
363         }
364
365         void RCSResourceObject::addAttributeUpdatedListener(const std::string& key,
366                 AttributeUpdatedListener h)
367         {
368             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
369
370             m_attributeUpdatedListeners[key] =
371                     std::make_shared< AttributeUpdatedListener >(std::move(h));
372         }
373
374         void RCSResourceObject::addAttributeUpdatedListener(std::string&& key,
375                 AttributeUpdatedListener h)
376         {
377             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
378
379             m_attributeUpdatedListeners[std::move(key)] =
380                     std::make_shared< AttributeUpdatedListener >(std::move(h));
381         }
382
383         bool RCSResourceObject::removeAttributeUpdatedListener(const std::string& key)
384         {
385             std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
386
387             return m_attributeUpdatedListeners.erase(key) != 0;
388         }
389
390         bool RCSResourceObject::testValueUpdated(const std::string& key,
391                 const RCSResourceAttributes::Value& value) const
392         {
393             return m_resourceAttributes.contains(key) == false
394                     || m_resourceAttributes.at(key) != value;
395         }
396
397         void RCSResourceObject::setAutoNotifyPolicy(AutoNotifyPolicy policy)
398         {
399             m_autoNotifyPolicy = policy;
400         }
401
402         RCSResourceObject::AutoNotifyPolicy RCSResourceObject::getAutoNotifyPolicy() const
403         {
404             return m_autoNotifyPolicy;
405         }
406
407         void RCSResourceObject::setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
408         {
409             m_setRequestHandlerPolicy = policy;
410         }
411
412         auto RCSResourceObject::getSetRequestHandlerPolicy() const -> SetRequestHandlerPolicy
413         {
414             return m_setRequestHandlerPolicy;
415         }
416
417         void RCSResourceObject::autoNotify(bool isAttributesChanged) const
418         {
419             autoNotify(isAttributesChanged, m_autoNotifyPolicy);
420         }
421
422         void RCSResourceObject::autoNotify(
423                         bool isAttributesChanged, AutoNotifyPolicy autoNotifyPolicy) const
424         {
425             if(autoNotifyPolicy == AutoNotifyPolicy::NEVER) return;
426             if(autoNotifyPolicy == AutoNotifyPolicy::UPDATED &&
427                     isAttributesChanged == false) return;
428
429             notify();
430         }
431
432         OCEntityHandlerResult RCSResourceObject::entityHandler(
433                 const std::shared_ptr< OC::OCResourceRequest >& request)
434         {
435             OC_LOG(WARNING, LOG_TAG, "entityHandler");
436             if (!request)
437             {
438                 return OC_EH_ERROR;
439             }
440
441             try
442             {
443                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::RequestFlag)
444                 {
445                     return handleRequest(request);
446                 }
447
448                 if (request->getRequestHandlerFlag() & OC::RequestHandlerFlag::ObserverFlag)
449                 {
450                     return handleObserve(request);
451                 }
452             }
453             catch (const std::exception& e)
454             {
455                 OC_LOG_V(WARNING, LOG_TAG, "Failed to handle request : %s", e.what());
456                 throw;
457             }
458             catch (...)
459             {
460                 OC_LOG(WARNING, LOG_TAG, "Failed to handle request.");
461                 throw;
462             }
463
464             return OC_EH_ERROR;
465         }
466
467         OCEntityHandlerResult RCSResourceObject::handleRequest(
468                 const std::shared_ptr< OC::OCResourceRequest >& request)
469         {
470             assert(request != nullptr);
471
472             if (request->getRequestType() == "GET")
473             {
474                 return handleRequestGet(request);
475             }
476
477             if (request->getRequestType() == "POST")
478             {
479                 return handleRequestSet(request);
480             }
481
482             return OC_EH_ERROR;
483         }
484
485         OCEntityHandlerResult RCSResourceObject::handleRequestGet(
486                 const std::shared_ptr< OC::OCResourceRequest >& request)
487         {
488             assert(request != nullptr);
489
490             auto attrs = getAttributesFromOCRequest(request);
491
492             return sendResponse(*this, request, invokeHandler(attrs, request, m_getRequestHandler));
493         }
494
495         bool RCSResourceObject::applyAcceptanceMethod(const RCSSetResponse& response,
496                 const RCSResourceAttributes& requstAttrs)
497         {
498             auto requestHandler = response.getHandler();
499
500             assert(requestHandler != nullptr);
501
502             auto replaced = requestHandler->applyAcceptanceMethod(response.getAcceptanceMethod(),
503                     *this, requstAttrs);
504
505             OC_LOG_V(WARNING, LOG_TAG, "replaced num %zu", replaced.size());
506             for (const auto& attrKeyValPair : replaced)
507             {
508                 std::shared_ptr< AttributeUpdatedListener > foundListener;
509                 {
510                     std::lock_guard< std::mutex > lock(m_mutexAttributeUpdatedListeners);
511
512                     auto it = m_attributeUpdatedListeners.find(attrKeyValPair.first);
513                     if (it != m_attributeUpdatedListeners.end())
514                     {
515                         foundListener = it->second;
516                     }
517                 }
518
519                 if (foundListener)
520                 {
521                     (*foundListener)(attrKeyValPair.second, requstAttrs.at(attrKeyValPair.first));
522                 }
523             }
524
525             return !replaced.empty();
526         }
527
528         OCEntityHandlerResult RCSResourceObject::handleRequestSet(
529                 const std::shared_ptr< OC::OCResourceRequest >& request)
530         {
531             assert(request != nullptr);
532
533             auto attrs = getAttributesFromOCRequest(request);
534             auto response = invokeHandler(attrs, request, m_setRequestHandler);
535
536             auto attrsChanged = applyAcceptanceMethod(response, attrs);
537
538             try
539             {
540                 autoNotify(attrsChanged, m_autoNotifyPolicy);
541                 return sendResponse(*this, request, response);
542             } catch (const RCSPlatformException& e) {
543                 OC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what());
544                 return OC_EH_ERROR;
545             }
546         }
547
548         OCEntityHandlerResult RCSResourceObject::handleObserve(
549                 const std::shared_ptr< OC::OCResourceRequest >&)
550         {
551             if (!isObservable())
552             {
553                 return OC_EH_ERROR;
554             }
555
556             return OC_EH_OK;
557         }
558
559         RCSResourceObject::LockGuard::LockGuard(const RCSResourceObject::Ptr ptr) :
560                 m_resourceObject(*ptr),
561                 m_autoNotifyPolicy{ ptr->getAutoNotifyPolicy() },
562                 m_isOwningLock{ false }
563         {
564             init();
565         }
566
567         RCSResourceObject::LockGuard::LockGuard(
568                 const RCSResourceObject& serverResource) :
569                 m_resourceObject(serverResource),
570                 m_autoNotifyPolicy{ serverResource.getAutoNotifyPolicy() },
571                 m_isOwningLock{ false }
572         {
573             init();
574         }
575
576         RCSResourceObject::LockGuard::LockGuard(
577                 const RCSResourceObject::Ptr ptr, AutoNotifyPolicy autoNotifyPolicy) :
578                 m_resourceObject(*ptr),
579                 m_autoNotifyPolicy { autoNotifyPolicy },
580                 m_isOwningLock{ false }
581         {
582             init();
583         }
584
585         RCSResourceObject::LockGuard::LockGuard(
586                 const RCSResourceObject& resourceObject, AutoNotifyPolicy autoNotifyPolicy) :
587                 m_resourceObject(resourceObject),
588                 m_autoNotifyPolicy { autoNotifyPolicy },
589                 m_isOwningLock{ false }
590         {
591             init();
592         }
593
594         RCSResourceObject::LockGuard::~LockGuard() noexcept(false)
595         {
596             if (!std::uncaught_exception() && m_autoNotifyFunc) m_autoNotifyFunc();
597
598             if (m_isOwningLock)
599             {
600                 m_resourceObject.setLockOwner(std::thread::id{ });
601                 m_resourceObject.m_mutex.unlock();
602             }
603         }
604
605         void RCSResourceObject::LockGuard::init()
606         {
607             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
608             {
609                 m_resourceObject.m_mutex.lock();
610                 m_resourceObject.setLockOwner(std::this_thread::get_id());
611                 m_isOwningLock = true;
612             }
613             m_autoNotifyFunc = ::createAutoNotifyInvoker(&RCSResourceObject::autoNotify,
614                     m_resourceObject, m_resourceObject.m_resourceAttributes, m_autoNotifyPolicy);
615         }
616
617         RCSResourceObject::WeakGuard::WeakGuard(
618                 const RCSResourceObject& resourceObject) :
619                 m_isOwningLock{ false },
620                 m_resourceObject(resourceObject)
621         {
622             if (m_resourceObject.getLockOwner() != std::this_thread::get_id())
623             {
624                 m_resourceObject.m_mutex.lock();
625                 m_resourceObject.setLockOwner(std::this_thread::get_id());
626                 m_isOwningLock = true;
627             }
628         }
629
630         RCSResourceObject::WeakGuard::~WeakGuard()
631         {
632             if (m_isOwningLock)
633             {
634                 m_resourceObject.setLockOwner(std::thread::id{ });
635                 m_resourceObject.m_mutex.unlock();
636             }
637         }
638
639         bool RCSResourceObject::WeakGuard::hasLocked() const
640         {
641             return m_isOwningLock;
642         }
643
644     }
645 }