Improved OIC Virtual Resource definitions (IOT-603)
[platform/upstream/iotivity.git] / resource / src / InProcClientWrapper.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 "InProcClientWrapper.h"
22 #include "ocstack.h"
23
24 #include "OCPlatform.h"
25 #include "OCResource.h"
26 #include "ocpayload.h"
27 #include <OCSerialization.h>
28 using namespace std;
29
30 namespace OC
31 {
32     InProcClientWrapper::InProcClientWrapper(
33         std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
34             : m_threadRun(false), m_csdkLock(csdkLock),
35               m_cfg { cfg }
36     {
37         // if the config type is server, we ought to never get called.  If the config type
38         // is both, we count on the server to run the thread and do the initialize
39
40         if(m_cfg.mode == ModeType::Client)
41         {
42             OCTransportFlags serverFlags =
43                             static_cast<OCTransportFlags>(m_cfg.serverConnectivity & CT_MASK_FLAGS);
44             OCTransportFlags clientFlags =
45                             static_cast<OCTransportFlags>(m_cfg.clientConnectivity & CT_MASK_FLAGS);
46             OCStackResult result = OCInit1(OC_CLIENT, serverFlags, clientFlags);
47
48             if(OC_STACK_OK != result)
49             {
50                 throw InitializeException(OC::InitException::STACK_INIT_ERROR, result);
51             }
52
53             m_threadRun = true;
54             m_listeningThread = std::thread(&InProcClientWrapper::listeningFunc, this);
55         }
56     }
57
58     InProcClientWrapper::~InProcClientWrapper()
59     {
60         if(m_threadRun && m_listeningThread.joinable())
61         {
62             m_threadRun = false;
63             m_listeningThread.join();
64         }
65
66         // only stop if we are the ones who actually called 'init'.  We are counting
67         // on the server to do the stop.
68         if(m_cfg.mode == ModeType::Client)
69         {
70             OCStop();
71         }
72     }
73
74     void InProcClientWrapper::listeningFunc()
75     {
76         while(m_threadRun)
77         {
78             OCStackResult result;
79             auto cLock = m_csdkLock.lock();
80             if(cLock)
81             {
82                 std::lock_guard<std::recursive_mutex> lock(*cLock);
83                 result = OCProcess();
84             }
85             else
86             {
87                 result = OC_STACK_ERROR;
88             }
89
90             if(result != OC_STACK_OK)
91             {
92                 // TODO: do something with result if failed?
93             }
94
95             // To minimize CPU utilization we may wish to do this with sleep
96             std::this_thread::sleep_for(std::chrono::milliseconds(10));
97         }
98     }
99
100     OCRepresentation parseGetSetCallback(OCClientResponse* clientResponse)
101     {
102         if(clientResponse->payload == nullptr ||
103                 (
104                     clientResponse->payload->type != PAYLOAD_TYPE_DEVICE &&
105                     clientResponse->payload->type != PAYLOAD_TYPE_PLATFORM &&
106                     clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION
107                 )
108           )
109         {
110             //OCPayloadDestroy(clientResponse->payload);
111             return OCRepresentation();
112         }
113
114         MessageContainer oc;
115         oc.setPayload(clientResponse->payload);
116         //OCPayloadDestroy(clientResponse->payload);
117
118         std::vector<OCRepresentation>::const_iterator it = oc.representations().begin();
119         if(it == oc.representations().end())
120         {
121             return OCRepresentation();
122         }
123
124         // first one is considered the root, everything else is considered a child of this one.
125         OCRepresentation root = *it;
126         ++it;
127
128         std::for_each(it, oc.representations().end(),
129                 [&root](const OCRepresentation& repItr)
130                 {root.addChild(repItr);});
131         return root;
132
133     }
134
135     OCStackApplicationResult listenCallback(void* ctx, OCDoHandle handle,
136         OCClientResponse* clientResponse)
137     {
138         ClientCallbackContext::ListenContext* context =
139             static_cast<ClientCallbackContext::ListenContext*>(ctx);
140
141         if(clientResponse->result != OC_STACK_OK)
142         {
143             oclog() << "listenCallback(): failed to create resource. clientResponse: "
144                     << clientResponse->result
145                     << std::flush;
146
147             return OC_STACK_KEEP_TRANSACTION;
148         }
149
150         if(!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
151         {
152             oclog() << "listenCallback(): clientResponse payload was null or the wrong type"
153                 << std::flush;
154             return OC_STACK_KEEP_TRANSACTION;
155         }
156
157         auto clientWrapper = context->clientWrapper.lock();
158
159         if(!clientWrapper)
160         {
161             oclog() << "listenCallback(): failed to get a shared_ptr to the client wrapper"
162                     << std::flush;
163             return OC_STACK_KEEP_TRANSACTION;
164         }
165
166         ListenOCContainer container(clientWrapper, clientResponse->devAddr,
167                                 reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
168         // loop to ensure valid construction of all resources
169         for(auto resource : container.Resources())
170         {
171             std::thread exec(context->callback, resource);
172             exec.detach();
173         }
174
175
176         return OC_STACK_KEEP_TRANSACTION;
177     }
178
179     OCStackResult InProcClientWrapper::ListenForResource(
180             const std::string& serviceUrl,  // unused
181             const std::string& resourceType,
182             OCConnectivityType connectivityType,
183             FindCallback& callback, QualityOfService QoS)
184     {
185         if(!callback)
186         {
187             return OC_STACK_INVALID_PARAM;
188         }
189
190         OCStackResult result;
191
192         ClientCallbackContext::ListenContext* context =
193             new ClientCallbackContext::ListenContext(callback, shared_from_this());
194         OCCallbackData cbdata(
195                 static_cast<void*>(context),
196                 listenCallback,
197                 [](void* c){delete static_cast<ClientCallbackContext::ListenContext*>(c);}
198             );
199
200         auto cLock = m_csdkLock.lock();
201         if(cLock)
202         {
203             std::lock_guard<std::recursive_mutex> lock(*cLock);
204             result = OCDoResource(nullptr, OC_REST_DISCOVER,
205                                   resourceType.c_str(),
206                                   nullptr, nullptr, connectivityType,
207                                   static_cast<OCQualityOfService>(QoS),
208                                   &cbdata,
209                                   nullptr, 0);
210         }
211         else
212         {
213             delete context;
214             result = OC_STACK_ERROR;
215         }
216         return result;
217     }
218
219     OCStackApplicationResult listenDeviceCallback(void* ctx, OCDoHandle handle,
220             OCClientResponse* clientResponse)
221     {
222         ClientCallbackContext::DeviceListenContext* context =
223             static_cast<ClientCallbackContext::DeviceListenContext*>(ctx);
224
225         try
226         {
227             OCRepresentation rep = parseGetSetCallback(clientResponse);
228             std::thread exec(context->callback, rep);
229             exec.detach();
230         }
231         catch(OC::OCException& e)
232         {
233             oclog() <<"Exception in listenDeviceCallback, ignoring response: "
234                 <<e.what() <<std::flush;
235         }
236
237         return OC_STACK_KEEP_TRANSACTION;
238     }
239
240     OCStackResult InProcClientWrapper::ListenForDevice(
241             const std::string& serviceUrl,  // unused
242             const std::string& deviceURI,
243             OCConnectivityType connectivityType,
244             FindDeviceCallback& callback,
245             QualityOfService QoS)
246     {
247         if(!callback)
248         {
249             return OC_STACK_INVALID_PARAM;
250         }
251         OCStackResult result;
252
253         ClientCallbackContext::DeviceListenContext* context =
254             new ClientCallbackContext::DeviceListenContext(callback, shared_from_this());
255         OCCallbackData cbdata(
256                 static_cast<void*>(context),
257                 listenDeviceCallback,
258                 [](void* c){delete static_cast<ClientCallbackContext::DeviceListenContext*>(c);}
259                 );
260
261         auto cLock = m_csdkLock.lock();
262         if(cLock)
263         {
264             std::lock_guard<std::recursive_mutex> lock(*cLock);
265             result = OCDoResource(nullptr, OC_REST_DISCOVER,
266                                   deviceURI.c_str(),
267                                   nullptr, nullptr, connectivityType,
268                                   static_cast<OCQualityOfService>(QoS),
269                                   &cbdata,
270                                   nullptr, 0);
271         }
272         else
273         {
274             delete context;
275             result = OC_STACK_ERROR;
276         }
277         return result;
278     }
279
280     void parseServerHeaderOptions(OCClientResponse* clientResponse,
281                     HeaderOptions& serverHeaderOptions)
282     {
283         if(clientResponse)
284         {
285             // Parse header options from server
286             uint16_t optionID;
287             std::string optionData;
288
289             for(int i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
290             {
291                 optionID = clientResponse->rcvdVendorSpecificHeaderOptions[i].optionID;
292                 optionData = reinterpret_cast<const char*>
293                                 (clientResponse->rcvdVendorSpecificHeaderOptions[i].optionData);
294                 HeaderOption::OCHeaderOption headerOption(optionID, optionData);
295                 serverHeaderOptions.push_back(headerOption);
296             }
297         }
298         else
299         {
300             // clientResponse is invalid
301             // TODO check proper logging
302             std::cout << " Invalid response " << std::endl;
303         }
304     }
305
306     OCStackApplicationResult getResourceCallback(void* ctx, OCDoHandle handle,
307         OCClientResponse* clientResponse)
308     {
309         ClientCallbackContext::GetContext* context =
310             static_cast<ClientCallbackContext::GetContext*>(ctx);
311
312         OCRepresentation rep;
313         HeaderOptions serverHeaderOptions;
314         OCStackResult result = clientResponse->result;
315         if(result == OC_STACK_OK)
316         {
317             parseServerHeaderOptions(clientResponse, serverHeaderOptions);
318             try
319             {
320                 rep = parseGetSetCallback(clientResponse);
321             }
322             catch(OC::OCException& e)
323             {
324                 result = e.code();
325             }
326         }
327
328         std::thread exec(context->callback, serverHeaderOptions, rep, result);
329         exec.detach();
330         return OC_STACK_DELETE_TRANSACTION;
331     }
332
333     OCStackResult InProcClientWrapper::GetResourceRepresentation(
334         const OCDevAddr& devAddr,
335         const std::string& resourceUri,
336         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
337         GetCallback& callback, QualityOfService QoS)
338     {
339         if(!callback)
340         {
341             return OC_STACK_INVALID_PARAM;
342         }
343         OCStackResult result;
344         ClientCallbackContext::GetContext* ctx =
345             new ClientCallbackContext::GetContext(callback);
346         OCCallbackData cbdata(
347                 static_cast<void*>(ctx),
348                 getResourceCallback,
349                 [](void* c){delete static_cast<ClientCallbackContext::GetContext*>(c);}
350                 );
351
352         std::string uri = assembleSetResourceUri(resourceUri, queryParams);
353
354         auto cLock = m_csdkLock.lock();
355
356         if(cLock)
357         {
358             std::lock_guard<std::recursive_mutex> lock(*cLock);
359             OCHeaderOption options[MAX_HEADER_OPTIONS];
360
361             result = OCDoResource(
362                                   nullptr, OC_REST_GET,
363                                   uri.c_str(),
364                                   &devAddr, nullptr,
365                                   CT_DEFAULT,
366                                   static_cast<OCQualityOfService>(QoS),
367                                   &cbdata,
368                                   assembleHeaderOptions(options, headerOptions),
369                                   headerOptions.size());
370         }
371         else
372         {
373             delete ctx;
374             result = OC_STACK_ERROR;
375         }
376         return result;
377     }
378
379
380     OCStackApplicationResult setResourceCallback(void* ctx, OCDoHandle handle,
381         OCClientResponse* clientResponse)
382     {
383         ClientCallbackContext::SetContext* context =
384             static_cast<ClientCallbackContext::SetContext*>(ctx);
385         OCRepresentation attrs;
386         HeaderOptions serverHeaderOptions;
387
388         OCStackResult result = clientResponse->result;
389         if (OC_STACK_OK               == result ||
390             OC_STACK_RESOURCE_CREATED == result ||
391             OC_STACK_RESOURCE_DELETED == result)
392         {
393             parseServerHeaderOptions(clientResponse, serverHeaderOptions);
394             try
395             {
396                 attrs = parseGetSetCallback(clientResponse);
397             }
398             catch(OC::OCException& e)
399             {
400                 result = e.code();
401             }
402         }
403
404         std::thread exec(context->callback, serverHeaderOptions, attrs, result);
405         exec.detach();
406         return OC_STACK_DELETE_TRANSACTION;
407     }
408
409     std::string InProcClientWrapper::assembleSetResourceUri(std::string uri,
410         const QueryParamsMap& queryParams)
411     {
412         if(uri.back() == '/')
413         {
414             uri.resize(uri.size()-1);
415         }
416
417         ostringstream paramsList;
418         if(queryParams.size() > 0)
419         {
420             paramsList << '?';
421         }
422
423         for(auto& param : queryParams)
424         {
425             paramsList << param.first <<'='<<param.second<<';';
426         }
427
428         std::string queryString = paramsList.str();
429         if(queryString.back() == ';')
430         {
431             queryString.resize(queryString.size() - 1);
432         }
433
434         std::string ret = uri + queryString;
435         return ret;
436     }
437
438     OCPayload* InProcClientWrapper::assembleSetResourcePayload(const OCRepresentation& rep)
439     {
440         MessageContainer ocInfo;
441         ocInfo.addRepresentation(rep);
442         return reinterpret_cast<OCPayload*>(ocInfo.getPayload());
443     }
444
445     OCStackResult InProcClientWrapper::PostResourceRepresentation(
446         const OCDevAddr& devAddr,
447         const std::string& uri,
448         const OCRepresentation& rep,
449         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
450         PostCallback& callback, QualityOfService QoS)
451     {
452         if(!callback)
453         {
454             return OC_STACK_INVALID_PARAM;
455         }
456         OCStackResult result;
457         ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
458         OCCallbackData cbdata(
459                 static_cast<void*>(ctx),
460                 setResourceCallback,
461                 [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);}
462                 );
463
464         std::string url = assembleSetResourceUri(uri, queryParams);
465
466         auto cLock = m_csdkLock.lock();
467
468         if(cLock)
469         {
470             std::lock_guard<std::recursive_mutex> lock(*cLock);
471             OCHeaderOption options[MAX_HEADER_OPTIONS];
472
473             result = OCDoResource(nullptr, OC_REST_POST,
474                                   url.c_str(), &devAddr,
475                                   assembleSetResourcePayload(rep),
476                                   CT_DEFAULT,
477                                   static_cast<OCQualityOfService>(QoS),
478                                   &cbdata,
479                                   assembleHeaderOptions(options, headerOptions),
480                                   headerOptions.size());
481         }
482         else
483         {
484             delete ctx;
485             result = OC_STACK_ERROR;
486         }
487
488         return result;
489     }
490
491     OCStackResult InProcClientWrapper::PutResourceRepresentation(
492         const OCDevAddr& devAddr,
493         const std::string& uri,
494         const OCRepresentation& rep,
495         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
496         PutCallback& callback, QualityOfService QoS)
497     {
498         if(!callback)
499         {
500             return OC_STACK_INVALID_PARAM;
501         }
502         OCStackResult result;
503         ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
504         OCCallbackData cbdata(
505                 static_cast<void*>(ctx),
506                 setResourceCallback,
507                 [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);}
508                 );
509
510         std::string url = assembleSetResourceUri(uri, queryParams).c_str();
511
512         auto cLock = m_csdkLock.lock();
513
514         if(cLock)
515         {
516             std::lock_guard<std::recursive_mutex> lock(*cLock);
517             OCDoHandle handle;
518             OCHeaderOption options[MAX_HEADER_OPTIONS];
519
520             result = OCDoResource(&handle, OC_REST_PUT,
521                                   url.c_str(), &devAddr,
522                                   assembleSetResourcePayload(rep),
523                                   CT_DEFAULT,
524                                   static_cast<OCQualityOfService>(QoS),
525                                   &cbdata,
526                                   assembleHeaderOptions(options, headerOptions),
527                                   headerOptions.size());
528         }
529         else
530         {
531             delete ctx;
532             result = OC_STACK_ERROR;
533         }
534
535         return result;
536     }
537
538     OCStackApplicationResult deleteResourceCallback(void* ctx, OCDoHandle handle,
539         OCClientResponse* clientResponse)
540     {
541         ClientCallbackContext::DeleteContext* context =
542             static_cast<ClientCallbackContext::DeleteContext*>(ctx);
543         HeaderOptions serverHeaderOptions;
544
545         if(clientResponse->result == OC_STACK_OK)
546         {
547             parseServerHeaderOptions(clientResponse, serverHeaderOptions);
548         }
549         std::thread exec(context->callback, serverHeaderOptions, clientResponse->result);
550         exec.detach();
551         return OC_STACK_DELETE_TRANSACTION;
552     }
553
554     OCStackResult InProcClientWrapper::DeleteResource(
555         const OCDevAddr& devAddr,
556         const std::string& uri,
557         const HeaderOptions& headerOptions, DeleteCallback& callback, QualityOfService QoS)
558     {
559         if(!callback)
560         {
561             return OC_STACK_INVALID_PARAM;
562         }
563         OCStackResult result;
564         ClientCallbackContext::DeleteContext* ctx =
565             new ClientCallbackContext::DeleteContext(callback);
566         OCCallbackData cbdata(
567                 static_cast<void*>(ctx),
568                 deleteResourceCallback,
569                 [](void* c){delete static_cast<ClientCallbackContext::DeleteContext*>(c);}
570                 );
571
572         auto cLock = m_csdkLock.lock();
573
574         if(cLock)
575         {
576             OCHeaderOption options[MAX_HEADER_OPTIONS];
577
578             std::lock_guard<std::recursive_mutex> lock(*cLock);
579
580             result = OCDoResource(nullptr, OC_REST_DELETE,
581                                   uri.c_str(), &devAddr,
582                                   nullptr,
583                                   CT_DEFAULT,
584                                   static_cast<OCQualityOfService>(m_cfg.QoS),
585                                   &cbdata,
586                                   assembleHeaderOptions(options, headerOptions),
587                                   headerOptions.size());
588         }
589         else
590         {
591             delete ctx;
592             result = OC_STACK_ERROR;
593         }
594
595         return result;
596     }
597
598     OCStackApplicationResult observeResourceCallback(void* ctx, OCDoHandle handle,
599         OCClientResponse* clientResponse)
600     {
601         ClientCallbackContext::ObserveContext* context =
602             static_cast<ClientCallbackContext::ObserveContext*>(ctx);
603         OCRepresentation attrs;
604         HeaderOptions serverHeaderOptions;
605         uint32_t sequenceNumber = clientResponse->sequenceNumber;
606         OCStackResult result = clientResponse->result;
607         if(clientResponse->result == OC_STACK_OK)
608         {
609             parseServerHeaderOptions(clientResponse, serverHeaderOptions);
610             try
611             {
612                 attrs = parseGetSetCallback(clientResponse);
613             }
614             catch(OC::OCException& e)
615             {
616                 result = e.code();
617             }
618         }
619         std::thread exec(context->callback, serverHeaderOptions, attrs,
620                     result, sequenceNumber);
621         exec.detach();
622         if(sequenceNumber == OC_OBSERVE_DEREGISTER)
623         {
624             return OC_STACK_DELETE_TRANSACTION;
625         }
626         return OC_STACK_KEEP_TRANSACTION;
627     }
628
629     OCStackResult InProcClientWrapper::ObserveResource(ObserveType observeType, OCDoHandle* handle,
630         const OCDevAddr& devAddr,
631         const std::string& uri,
632         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
633         ObserveCallback& callback, QualityOfService QoS)
634     {
635         if(!callback)
636         {
637             return OC_STACK_INVALID_PARAM;
638         }
639         OCStackResult result;
640
641         ClientCallbackContext::ObserveContext* ctx =
642             new ClientCallbackContext::ObserveContext(callback);
643         OCCallbackData cbdata(
644                 static_cast<void*>(ctx),
645                 observeResourceCallback,
646                 [](void* c){delete static_cast<ClientCallbackContext::ObserveContext*>(c);}
647                 );
648
649         OCMethod method;
650         if (observeType == ObserveType::Observe)
651         {
652             method = OC_REST_OBSERVE;
653         }
654         else if (observeType == ObserveType::ObserveAll)
655         {
656             method = OC_REST_OBSERVE_ALL;
657         }
658         else
659         {
660             method = OC_REST_OBSERVE_ALL;
661         }
662
663         std::string url = assembleSetResourceUri(uri, queryParams).c_str();
664
665         auto cLock = m_csdkLock.lock();
666
667         if(cLock)
668         {
669             std::lock_guard<std::recursive_mutex> lock(*cLock);
670             OCHeaderOption options[MAX_HEADER_OPTIONS];
671
672             result = OCDoResource(handle, method,
673                                   url.c_str(), &devAddr,
674                                   nullptr,
675                                   CT_DEFAULT,
676                                   static_cast<OCQualityOfService>(QoS),
677                                   &cbdata,
678                                   assembleHeaderOptions(options, headerOptions),
679                                   headerOptions.size());
680         }
681         else
682         {
683             delete ctx;
684             return OC_STACK_ERROR;
685         }
686
687         return result;
688     }
689
690     OCStackResult InProcClientWrapper::CancelObserveResource(
691             OCDoHandle handle,
692             const std::string& host, // unused
693             const std::string& uri,  // unused
694             const HeaderOptions& headerOptions,
695             QualityOfService QoS)
696     {
697         OCStackResult result;
698         auto cLock = m_csdkLock.lock();
699
700         if(cLock)
701         {
702             std::lock_guard<std::recursive_mutex> lock(*cLock);
703             OCHeaderOption options[MAX_HEADER_OPTIONS];
704
705             result = OCCancel(handle,
706                     static_cast<OCQualityOfService>(QoS),
707                     assembleHeaderOptions(options, headerOptions),
708                     headerOptions.size());
709         }
710         else
711         {
712             result = OC_STACK_ERROR;
713         }
714
715         return result;
716     }
717
718     OCStackApplicationResult subscribePresenceCallback(void* ctx, OCDoHandle handle,
719             OCClientResponse* clientResponse)
720     {
721         ClientCallbackContext::SubscribePresenceContext* context =
722         static_cast<ClientCallbackContext::SubscribePresenceContext*>(ctx);
723
724         /*
725          * This a hack while we rethink presence subscription.
726          */
727         std::string url = clientResponse->devAddr.addr;
728
729         std::thread exec(context->callback, clientResponse->result,
730                     clientResponse->sequenceNumber, url);
731
732         exec.detach();
733
734         return OC_STACK_KEEP_TRANSACTION;
735     }
736
737     OCStackResult InProcClientWrapper::SubscribePresence(OCDoHandle* handle,
738         const std::string& host, const std::string& resourceType,
739         OCConnectivityType connectivityType, SubscribeCallback& presenceHandler)
740     {
741         if(!presenceHandler)
742         {
743             return OC_STACK_INVALID_PARAM;
744         }
745
746         ClientCallbackContext::SubscribePresenceContext* ctx =
747             new ClientCallbackContext::SubscribePresenceContext(presenceHandler);
748         OCCallbackData cbdata(
749                 static_cast<void*>(ctx),
750                 subscribePresenceCallback,
751                 [](void* c)
752                 {delete static_cast<ClientCallbackContext::SubscribePresenceContext*>(c);}
753                 );
754
755         auto cLock = m_csdkLock.lock();
756
757         std::ostringstream os;
758         os << host << OC_RSRVD_PRESENCE_URI;;
759
760         if(!resourceType.empty())
761         {
762             os << "?rt=" << resourceType;
763         }
764
765         if(!cLock)
766         {
767             delete ctx;
768             return OC_STACK_ERROR;
769         }
770
771         return OCDoResource(handle, OC_REST_PRESENCE,
772                             os.str().c_str(), nullptr,
773                             nullptr, connectivityType,
774                             OC_LOW_QOS, &cbdata, NULL, 0);
775     }
776
777     OCStackResult InProcClientWrapper::UnsubscribePresence(OCDoHandle handle)
778     {
779         OCStackResult result;
780         auto cLock = m_csdkLock.lock();
781
782         if(cLock)
783         {
784             std::lock_guard<std::recursive_mutex> lock(*cLock);
785             result = OCCancel(handle, OC_LOW_QOS, NULL, 0);
786         }
787         else
788         {
789             result = OC_STACK_ERROR;
790         }
791
792         return result;
793     }
794
795     OCStackResult InProcClientWrapper::GetDefaultQos(QualityOfService& qos)
796     {
797         qos = m_cfg.QoS;
798         return OC_STACK_OK;
799     }
800
801     OCHeaderOption* InProcClientWrapper::assembleHeaderOptions(OCHeaderOption options[],
802            const HeaderOptions& headerOptions)
803     {
804         int i = 0;
805
806         if( headerOptions.size() == 0)
807         {
808             return nullptr;
809         }
810
811         for (auto it=headerOptions.begin(); it != headerOptions.end(); ++it)
812         {
813             options[i] = OCHeaderOption(OC_COAP_ID,
814                     it->getOptionID(),
815                     it->getOptionData().length() + 1,
816                     reinterpret_cast<const uint8_t*>(it->getOptionData().c_str()));
817             i++;
818         }
819
820         return options;
821     }
822 }