[IOT-1440] findResource() to return list of discovered resources.
[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         root.setDevAddr(clientResponse->devAddr);
127         root.setUri(clientResponse->resourceUri);
128         ++it;
129
130         std::for_each(it, oc.representations().end(),
131                 [&root](const OCRepresentation& repItr)
132                 {root.addChild(repItr);});
133         return root;
134
135     }
136
137     OCStackApplicationResult listenCallback(void* ctx, OCDoHandle /*handle*/,
138         OCClientResponse* clientResponse)
139     {
140         ClientCallbackContext::ListenContext* context =
141             static_cast<ClientCallbackContext::ListenContext*>(ctx);
142
143         if (clientResponse->result != OC_STACK_OK)
144         {
145             oclog() << "listenCallback(): failed to create resource. clientResponse: "
146                     << clientResponse->result
147                     << std::flush;
148
149             return OC_STACK_KEEP_TRANSACTION;
150         }
151
152         if (!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
153         {
154             oclog() << "listenCallback(): clientResponse payload was null or the wrong type"
155                 << std::flush;
156             return OC_STACK_KEEP_TRANSACTION;
157         }
158
159         auto clientWrapper = context->clientWrapper.lock();
160
161         if (!clientWrapper)
162         {
163             oclog() << "listenCallback(): failed to get a shared_ptr to the client wrapper"
164                     << std::flush;
165             return OC_STACK_KEEP_TRANSACTION;
166         }
167
168         try
169         {
170             ListenOCContainer container(clientWrapper, clientResponse->devAddr,
171                                     reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
172             // loop to ensure valid construction of all resources
173
174             for(auto resource : container.Resources())
175             {
176                 std::thread exec(context->callback, resource);
177                 exec.detach();
178             }
179         }
180         catch (std::exception &e)
181         {
182             oclog() << "Exception in listCallback, ignoring response: "
183                     << e.what() << std::flush;
184         }
185
186
187         return OC_STACK_KEEP_TRANSACTION;
188     }
189
190     OCStackApplicationResult listenErrorCallback(void* ctx, OCDoHandle /*handle*/,
191         OCClientResponse* clientResponse)
192     {
193         if (!ctx || !clientResponse)
194         {
195             return OC_STACK_KEEP_TRANSACTION;
196         }
197
198         ClientCallbackContext::ListenErrorContext* context =
199             static_cast<ClientCallbackContext::ListenErrorContext*>(ctx);
200         if (!context)
201         {
202             return OC_STACK_KEEP_TRANSACTION;
203         }
204
205         OCStackResult result = clientResponse->result;
206         if (result == OC_STACK_OK)
207         {
208             if (!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
209             {
210                 oclog() << "listenCallback(): clientResponse payload was null or the wrong type"
211                     << std::flush;
212                 return OC_STACK_KEEP_TRANSACTION;
213             }
214
215             auto clientWrapper = context->clientWrapper.lock();
216
217             if (!clientWrapper)
218             {
219                 oclog() << "listenCallback(): failed to get a shared_ptr to the client wrapper"
220                         << std::flush;
221                 return OC_STACK_KEEP_TRANSACTION;
222             }
223
224             ListenOCContainer container(clientWrapper, clientResponse->devAddr,
225                                         reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
226             // loop to ensure valid construction of all resources
227             for (auto resource : container.Resources())
228             {
229                 std::thread exec(context->callback, resource);
230                 exec.detach();
231             }
232             return OC_STACK_KEEP_TRANSACTION;
233         }
234
235         std::string resourceURI = clientResponse->resourceUri;
236         std::thread exec(context->errorCallback, resourceURI, result);
237         exec.detach();
238         return OC_STACK_KEEP_TRANSACTION;
239     }
240
241     OCStackResult InProcClientWrapper::ListenForResource(
242             const std::string& serviceUrl,
243             const std::string& resourceType,
244             OCConnectivityType connectivityType,
245             FindCallback& callback, QualityOfService QoS)
246     {
247         if (!callback)
248         {
249             return OC_STACK_INVALID_PARAM;
250         }
251
252         OCStackResult result;
253         ostringstream resourceUri;
254         resourceUri << serviceUrl << resourceType;
255
256         ClientCallbackContext::ListenContext* context =
257             new ClientCallbackContext::ListenContext(callback, shared_from_this());
258         OCCallbackData cbdata;
259         cbdata.context = static_cast<void*>(context),
260         cbdata.cb      = listenCallback;
261         cbdata.cd      = [](void* c){delete (ClientCallbackContext::ListenContext*)c;};
262
263         auto cLock = m_csdkLock.lock();
264         if (cLock)
265         {
266             std::lock_guard<std::recursive_mutex> lock(*cLock);
267             result = OCDoResource(nullptr, OC_REST_DISCOVER,
268                                   resourceUri.str().c_str(),
269                                   nullptr, nullptr, connectivityType,
270                                   static_cast<OCQualityOfService>(QoS),
271                                   &cbdata,
272                                   nullptr, 0);
273         }
274         else
275         {
276             delete context;
277             result = OC_STACK_ERROR;
278         }
279         return result;
280     }
281
282     OCStackResult InProcClientWrapper::ListenErrorForResource(
283             const std::string& serviceUrl,
284             const std::string& resourceType,
285             OCConnectivityType connectivityType,
286             FindCallback& callback, FindErrorCallback& errorCallback,
287             QualityOfService QoS)
288     {
289         if (!callback)
290         {
291             return OC_STACK_INVALID_PARAM;
292         }
293
294         ostringstream resourceUri;
295         resourceUri << serviceUrl << resourceType;
296
297         ClientCallbackContext::ListenErrorContext* context =
298             new ClientCallbackContext::ListenErrorContext(callback, errorCallback,
299                                                           shared_from_this());
300         if (!context)
301         {
302             return OC_STACK_ERROR;
303         }
304
305         OCCallbackData cbdata(
306                 static_cast<void*>(context),
307                 listenErrorCallback,
308                 [](void* c){delete static_cast<ClientCallbackContext::ListenErrorContext*>(c);}
309             );
310
311         OCStackResult result;
312         auto cLock = m_csdkLock.lock();
313         if (cLock)
314         {
315             std::lock_guard<std::recursive_mutex> lock(*cLock);
316             result = OCDoResource(nullptr, OC_REST_DISCOVER,
317                                   resourceUri.str().c_str(),
318                                   nullptr, nullptr, connectivityType,
319                                   static_cast<OCQualityOfService>(QoS),
320                                   &cbdata,
321                                   nullptr, 0);
322         }
323         else
324         {
325             delete context;
326             result = OC_STACK_ERROR;
327         }
328         return result;
329     }
330
331     OCStackApplicationResult listenCallback2(void* ctx, OCDoHandle /*handle*/,
332         OCClientResponse* clientResponse)
333     {
334         ClientCallbackContext::ListenContext2* context =
335             static_cast<ClientCallbackContext::ListenContext2*>(ctx);
336
337         if (clientResponse->result != OC_STACK_OK)
338         {
339             oclog() << "listenCallback2(): failed to create resource. clientResponse: "
340                     << clientResponse->result
341                     << std::flush;
342
343             return OC_STACK_KEEP_TRANSACTION;
344         }
345
346         if (!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
347         {
348             oclog() << "listenCallback2(): clientResponse payload was null or the wrong type"
349                 << std::flush;
350             return OC_STACK_KEEP_TRANSACTION;
351         }
352
353         auto clientWrapper = context->clientWrapper.lock();
354
355         if (!clientWrapper)
356         {
357             oclog() << "listenCallback2(): failed to get a shared_ptr to the client wrapper"
358                     << std::flush;
359             return OC_STACK_KEEP_TRANSACTION;
360         }
361
362         try
363         {
364             ListenOCContainer container(clientWrapper, clientResponse->devAddr,
365                                     reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
366
367             std::thread exec(context->callback, container.Resources());
368             exec.detach();
369         }
370         catch (std::exception &e)
371         {
372             oclog() << "Exception in listCallback2, ignoring response: "
373                     << e.what() << std::flush;
374         }
375
376
377         return OC_STACK_KEEP_TRANSACTION;
378     }
379
380     OCStackResult InProcClientWrapper::ListenForResource2(
381             const std::string& serviceUrl,
382             const std::string& resourceType,
383             OCConnectivityType connectivityType,
384             FindResListCallback& callback, QualityOfService QoS)
385     {
386         if (!callback)
387         {
388             return OC_STACK_INVALID_PARAM;
389         }
390
391         OCStackResult result;
392         ostringstream resourceUri;
393         resourceUri << serviceUrl << resourceType;
394
395         ClientCallbackContext::ListenContext2* context =
396             new ClientCallbackContext::ListenContext2(callback, shared_from_this());
397         OCCallbackData cbdata;
398         cbdata.context = static_cast<void*>(context),
399         cbdata.cb      = listenCallback2;
400         cbdata.cd      = [](void* c){delete (ClientCallbackContext::ListenContext2*)c;};
401
402         auto cLock = m_csdkLock.lock();
403         if (cLock)
404         {
405             std::lock_guard<std::recursive_mutex> lock(*cLock);
406             result = OCDoResource(nullptr, OC_REST_DISCOVER,
407                                   resourceUri.str().c_str(),
408                                   nullptr, nullptr, connectivityType,
409                                   static_cast<OCQualityOfService>(QoS),
410                                   &cbdata,
411                                   nullptr, 0);
412         }
413         else
414         {
415             delete context;
416             result = OC_STACK_ERROR;
417         }
418         return result;
419     }
420
421 #ifdef WITH_MQ
422     OCStackApplicationResult listenMQCallback(void* ctx, OCDoHandle /*handle*/,
423                                               OCClientResponse* clientResponse)
424     {
425         ClientCallbackContext::MQTopicContext* context =
426             static_cast<ClientCallbackContext::MQTopicContext*>(ctx);
427
428         if (!clientResponse || !context)
429         {
430             return OC_STACK_DELETE_TRANSACTION;
431         }
432
433         std::string resourceURI = clientResponse->resourceUri;
434         if (clientResponse->result != OC_STACK_OK)
435         {
436             oclog() << "listenMQCallback(): failed to create resource. clientResponse: "
437                     << clientResponse->result
438                     << std::flush;
439
440             std::thread exec(context->callback, clientResponse->result,
441                              resourceURI, nullptr);
442             exec.detach();
443
444             return OC_STACK_DELETE_TRANSACTION;
445         }
446
447         auto clientWrapper = context->clientWrapper.lock();
448         if (!clientWrapper)
449         {
450             oclog() << "listenMQCallback(): failed to get a shared_ptr to the client wrapper"
451                     << std::flush;
452             return OC_STACK_DELETE_TRANSACTION;
453         }
454
455         try
456         {
457             ListenOCContainer container(clientWrapper, clientResponse->devAddr,
458                                         (OCRepPayload *) clientResponse->payload);
459
460             // loop to ensure valid construction of all resources
461             for (auto resource : container.Resources())
462             {
463                 std::thread exec(context->callback, clientResponse->result,
464                                  resourceURI, resource);
465                 exec.detach();
466             }
467         }
468         catch (std::exception &e)
469         {
470             oclog() << "Exception in listCallback, ignoring response: "
471                     << e.what() << std::flush;
472         }
473
474         return OC_STACK_DELETE_TRANSACTION;
475     }
476
477     OCStackResult InProcClientWrapper::ListenForMQTopic(const OCDevAddr& devAddr,
478                                                         const std::string& resourceUri,
479                                                         const QueryParamsMap& queryParams,
480                                                         const HeaderOptions& headerOptions,
481                                                         MQTopicCallback& callback,
482                                                         QualityOfService QoS)
483     {
484         oclog() << "ListenForMQTopic()" << std::flush;
485
486         if (!callback)
487         {
488             return OC_STACK_INVALID_PARAM;
489         }
490
491         ClientCallbackContext::MQTopicContext* context =
492             new ClientCallbackContext::MQTopicContext(callback, shared_from_this());
493         OCCallbackData cbdata;
494         cbdata.context = static_cast<void*>(context),
495         cbdata.cb      = listenMQCallback;
496         cbdata.cd      = [](void* c){delete (ClientCallbackContext::MQTopicContext*)c;};
497
498         std::string uri = assembleSetResourceUri(resourceUri, queryParams);
499
500         OCStackResult result = OC_STACK_ERROR;
501         auto cLock = m_csdkLock.lock();
502         if (cLock)
503         {
504             std::lock_guard<std::recursive_mutex> lock(*cLock);
505             OCHeaderOption options[MAX_HEADER_OPTIONS];
506             result = OCDoResource(
507                                   nullptr, OC_REST_GET,
508                                   uri.c_str(),
509                                   &devAddr, nullptr,
510                                   CT_DEFAULT,
511                                   static_cast<OCQualityOfService>(QoS),
512                                   &cbdata,
513                                   assembleHeaderOptions(options, headerOptions),
514                                   headerOptions.size());
515         }
516         else
517         {
518             delete context;
519         }
520
521         return result;
522     }
523 #endif
524
525     OCStackApplicationResult listenDeviceCallback(void* ctx,
526                                                   OCDoHandle /*handle*/,
527             OCClientResponse* clientResponse)
528     {
529         ClientCallbackContext::DeviceListenContext* context =
530             static_cast<ClientCallbackContext::DeviceListenContext*>(ctx);
531
532         try
533         {
534             OCRepresentation rep = parseGetSetCallback(clientResponse);
535             std::thread exec(context->callback, rep);
536             exec.detach();
537         }
538         catch(OC::OCException& e)
539         {
540             oclog() <<"Exception in listenDeviceCallback, ignoring response: "
541                 <<e.what() <<std::flush;
542         }
543
544         return OC_STACK_KEEP_TRANSACTION;
545     }
546
547     OCStackResult InProcClientWrapper::ListenForDevice(
548             const std::string& serviceUrl,
549             const std::string& deviceURI,
550             OCConnectivityType connectivityType,
551             FindDeviceCallback& callback,
552             QualityOfService QoS)
553     {
554         if (!callback)
555         {
556             return OC_STACK_INVALID_PARAM;
557         }
558         OCStackResult result;
559         ostringstream deviceUri;
560         deviceUri << serviceUrl << deviceURI;
561
562         ClientCallbackContext::DeviceListenContext* context =
563             new ClientCallbackContext::DeviceListenContext(callback, shared_from_this());
564         OCCallbackData cbdata;
565
566         cbdata.context = static_cast<void*>(context),
567         cbdata.cb      = listenDeviceCallback;
568         cbdata.cd      = [](void* c){delete (ClientCallbackContext::DeviceListenContext*)c;};
569
570         auto cLock = m_csdkLock.lock();
571         if (cLock)
572         {
573             std::lock_guard<std::recursive_mutex> lock(*cLock);
574             result = OCDoResource(nullptr, OC_REST_DISCOVER,
575                                   deviceUri.str().c_str(),
576                                   nullptr, nullptr, connectivityType,
577                                   static_cast<OCQualityOfService>(QoS),
578                                   &cbdata,
579                                   nullptr, 0);
580         }
581         else
582         {
583             delete context;
584             result = OC_STACK_ERROR;
585         }
586         return result;
587     }
588
589     void parseServerHeaderOptions(OCClientResponse* clientResponse,
590                     HeaderOptions& serverHeaderOptions)
591     {
592         if (clientResponse)
593         {
594             // Parse header options from server
595             uint16_t optionID;
596             std::string optionData;
597
598             for(int i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
599             {
600                 optionID = clientResponse->rcvdVendorSpecificHeaderOptions[i].optionID;
601                 optionData = reinterpret_cast<const char*>
602                                 (clientResponse->rcvdVendorSpecificHeaderOptions[i].optionData);
603                 HeaderOption::OCHeaderOption headerOption(optionID, optionData);
604                 serverHeaderOptions.push_back(headerOption);
605             }
606         }
607         else
608         {
609             // clientResponse is invalid
610             // TODO check proper logging
611             std::cout << " Invalid response " << std::endl;
612         }
613     }
614
615 #ifdef WITH_MQ
616     OCStackApplicationResult createMQTopicCallback(void* ctx, OCDoHandle /*handle*/,
617                     OCClientResponse* clientResponse)
618     {
619         ClientCallbackContext::MQTopicContext* context =
620             static_cast<ClientCallbackContext::MQTopicContext*>(ctx);
621         HeaderOptions serverHeaderOptions;
622
623         if (!clientResponse || !context)
624         {
625             return OC_STACK_DELETE_TRANSACTION;
626         }
627
628         std::string createdUri;
629         bool isLocationOption = false;
630         OCStackResult result = clientResponse->result;
631         if (OC_STACK_OK               == result ||
632             OC_STACK_RESOURCE_CREATED == result)
633         {
634             parseServerHeaderOptions(clientResponse, serverHeaderOptions);
635
636             for (auto headerOption : serverHeaderOptions)
637             {
638                 if (HeaderOption::LOCATION_PATH_OPTION_ID == headerOption.getOptionID())
639                 {
640                     createdUri += "/";
641                     createdUri += headerOption.getOptionData();
642                     if (!isLocationOption)
643                     {
644                         isLocationOption = true;
645                     }
646                 }
647             }
648         }
649
650         if (!isLocationOption)
651         {
652             createdUri = std::string(clientResponse->resourceUri);
653         }
654
655         auto clientWrapper = context->clientWrapper.lock();
656
657         if (!clientWrapper)
658         {
659             oclog() << "createMQTopicCallback(): failed to get a shared_ptr to the client wrapper"
660                     << std::flush;
661             return OC_STACK_DELETE_TRANSACTION;
662         }
663
664         try
665         {
666             if (OC_STACK_OK               == result ||
667                 OC_STACK_RESOURCE_CREATED == result)
668             {
669                 ListenOCContainer container(clientWrapper, clientResponse->devAddr,
670                                             createdUri);
671                 for (auto resource : container.Resources())
672                 {
673                     std::thread exec(context->callback, result,
674                                      createdUri,
675                                      resource);
676                     exec.detach();
677                 }
678             }
679             else
680             {
681                 std::thread exec(context->callback, result,
682                                  createdUri,
683                                  nullptr);
684                 exec.detach();
685             }
686         }
687         catch (std::exception &e)
688         {
689             oclog() << "Exception in createMQTopicCallback, ignoring response: "
690                     << e.what() << std::flush;
691         }
692         return OC_STACK_DELETE_TRANSACTION;
693     }
694
695     OCStackResult InProcClientWrapper::PutMQTopicRepresentation(
696                 const OCDevAddr& devAddr,
697                 const std::string& uri,
698                 const OCRepresentation& rep,
699                 const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
700                 MQTopicCallback& callback, QualityOfService QoS)
701     {
702         if (!callback)
703         {
704             return OC_STACK_INVALID_PARAM;
705         }
706         OCStackResult result;
707         ClientCallbackContext::MQTopicContext* ctx =
708                 new ClientCallbackContext::MQTopicContext(callback, shared_from_this());
709         OCCallbackData cbdata;
710         cbdata.context = static_cast<void*>(ctx),
711         cbdata.cb      = createMQTopicCallback;
712         cbdata.cd      = [](void* c){delete (ClientCallbackContext::MQTopicContext*)c;};
713
714         std::string url = assembleSetResourceUri(uri, queryParams);
715
716         auto cLock = m_csdkLock.lock();
717
718         if (cLock)
719         {
720             std::lock_guard<std::recursive_mutex> lock(*cLock);
721             OCHeaderOption options[MAX_HEADER_OPTIONS];
722
723             result = OCDoResource(nullptr, OC_REST_PUT,
724                                   url.c_str(), &devAddr,
725                                   assembleSetResourcePayload(rep),
726                                   CT_DEFAULT,
727                                   static_cast<OCQualityOfService>(QoS),
728                                   &cbdata,
729                                   assembleHeaderOptions(options, headerOptions),
730                                   headerOptions.size());
731         }
732         else
733         {
734             delete ctx;
735             result = OC_STACK_ERROR;
736         }
737
738         return result;
739     }
740 #endif
741     OCStackApplicationResult getResourceCallback(void* ctx,
742                                                  OCDoHandle /*handle*/,
743         OCClientResponse* clientResponse)
744     {
745         ClientCallbackContext::GetContext* context =
746             static_cast<ClientCallbackContext::GetContext*>(ctx);
747
748         OCRepresentation rep;
749         HeaderOptions serverHeaderOptions;
750         OCStackResult result = clientResponse->result;
751
752         parseServerHeaderOptions(clientResponse, serverHeaderOptions);
753         try
754         {
755             rep = parseGetSetCallback(clientResponse);
756         }
757         catch(OC::OCException& e)
758         {
759             result = e.code();
760         }
761
762         std::thread exec(context->callback, serverHeaderOptions, rep, result);
763         exec.detach();
764         return OC_STACK_DELETE_TRANSACTION;
765     }
766
767     OCStackResult InProcClientWrapper::GetResourceRepresentation(
768         const OCDevAddr& devAddr,
769         const std::string& resourceUri,
770         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
771         OCConnectivityType connectivityType,
772         GetCallback& callback, QualityOfService QoS)
773     {
774         if (!callback)
775         {
776             return OC_STACK_INVALID_PARAM;
777         }
778         OCStackResult result;
779         ClientCallbackContext::GetContext* ctx =
780             new ClientCallbackContext::GetContext(callback);
781         OCCallbackData cbdata;
782         cbdata.context = static_cast<void*>(ctx),
783         cbdata.cb      = getResourceCallback;
784         cbdata.cd      = [](void* c){delete (ClientCallbackContext::GetContext*)c;};
785
786
787         std::string uri = assembleSetResourceUri(resourceUri, queryParams);
788
789         auto cLock = m_csdkLock.lock();
790
791         if (cLock)
792         {
793             std::lock_guard<std::recursive_mutex> lock(*cLock);
794             OCHeaderOption options[MAX_HEADER_OPTIONS];
795
796             result = OCDoResource(
797                                   nullptr, OC_REST_GET,
798                                   uri.c_str(),
799                                   &devAddr, nullptr,
800                                   connectivityType,
801                                   static_cast<OCQualityOfService>(QoS),
802                                   &cbdata,
803                                   assembleHeaderOptions(options, headerOptions),
804                                   headerOptions.size());
805         }
806         else
807         {
808             delete ctx;
809             result = OC_STACK_ERROR;
810         }
811         return result;
812     }
813
814
815     OCStackApplicationResult setResourceCallback(void* ctx,
816                                                  OCDoHandle /*handle*/,
817         OCClientResponse* clientResponse)
818     {
819         ClientCallbackContext::SetContext* context =
820             static_cast<ClientCallbackContext::SetContext*>(ctx);
821         OCRepresentation attrs;
822         HeaderOptions serverHeaderOptions;
823
824         OCStackResult result = clientResponse->result;
825
826         parseServerHeaderOptions(clientResponse, serverHeaderOptions);
827         try
828         {
829             attrs = parseGetSetCallback(clientResponse);
830         }
831         catch(OC::OCException& e)
832         {
833             result = e.code();
834         }
835
836         std::thread exec(context->callback, serverHeaderOptions, attrs, result);
837         exec.detach();
838         return OC_STACK_DELETE_TRANSACTION;
839     }
840
841     std::string InProcClientWrapper::assembleSetResourceUri(std::string uri,
842         const QueryParamsMap& queryParams)
843     {
844         if (!uri.empty())
845         {
846             if (uri.back() == '/')
847             {
848                 uri.resize(uri.size() - 1);
849             }
850         }
851
852         ostringstream paramsList;
853         if (queryParams.size() > 0)
854         {
855             paramsList << '?';
856         }
857
858         for (auto& param : queryParams)
859         {
860             paramsList << param.first <<'='<<param.second<<';';
861         }
862
863         std::string queryString = paramsList.str();
864
865         if (queryString.empty())
866         {
867             return uri;
868         }
869
870         if (queryString.back() == ';')
871         {
872             queryString.resize(queryString.size() - 1);
873         }
874
875         std::string ret = uri + queryString;
876         return ret;
877     }
878
879     std::string InProcClientWrapper::assembleSetResourceUri(std::string uri,
880         const QueryParamsList& queryParams)
881     {
882         if (!uri.empty())
883         {
884             if (uri.back() == '/')
885             {
886                 uri.resize(uri.size() - 1);
887             }
888         }
889
890         ostringstream paramsList;
891         if (queryParams.size() > 0)
892         {
893             paramsList << '?';
894         }
895
896         for (auto& param : queryParams)
897         {
898             for (auto& paramList : param.second)
899             {
900                 paramsList << param.first << '=' << paramList << ';';
901             }
902         }
903
904         std::string queryString = paramsList.str();
905
906         if (queryString.empty())
907         {
908             return uri;
909         }
910
911         if (queryString.back() == ';')
912         {
913             queryString.resize(queryString.size() - 1);
914         }
915
916         std::string ret = uri + queryString;
917         return ret;
918     }
919
920     OCPayload* InProcClientWrapper::assembleSetResourcePayload(const OCRepresentation& rep)
921     {
922         MessageContainer ocInfo;
923         ocInfo.addRepresentation(rep);
924         for(const OCRepresentation& r : rep.getChildren())
925         {
926             ocInfo.addRepresentation(r);
927         }
928
929         return reinterpret_cast<OCPayload*>(ocInfo.getPayload());
930     }
931
932     OCStackResult InProcClientWrapper::PostResourceRepresentation(
933         const OCDevAddr& devAddr,
934         const std::string& uri,
935         const OCRepresentation& rep,
936         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
937         OCConnectivityType connectivityType,
938         PostCallback& callback, QualityOfService QoS)
939     {
940         if (!callback)
941         {
942             return OC_STACK_INVALID_PARAM;
943         }
944         OCStackResult result;
945         ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
946         OCCallbackData cbdata;
947         cbdata.context = static_cast<void*>(ctx),
948         cbdata.cb      = setResourceCallback;
949         cbdata.cd      = [](void* c){delete (ClientCallbackContext::SetContext*)c;};
950
951
952         std::string url = assembleSetResourceUri(uri, queryParams);
953
954         auto cLock = m_csdkLock.lock();
955
956         if (cLock)
957         {
958             std::lock_guard<std::recursive_mutex> lock(*cLock);
959             OCHeaderOption options[MAX_HEADER_OPTIONS];
960
961             result = OCDoResource(nullptr, OC_REST_POST,
962                                   url.c_str(), &devAddr,
963                                   assembleSetResourcePayload(rep),
964                                   connectivityType,
965                                   static_cast<OCQualityOfService>(QoS),
966                                   &cbdata,
967                                   assembleHeaderOptions(options, headerOptions),
968                                   headerOptions.size());
969         }
970         else
971         {
972             delete ctx;
973             result = OC_STACK_ERROR;
974         }
975
976         return result;
977     }
978
979     OCStackResult InProcClientWrapper::PutResourceRepresentation(
980         const OCDevAddr& devAddr,
981         const std::string& uri,
982         const OCRepresentation& rep,
983         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
984         PutCallback& callback, QualityOfService QoS)
985     {
986         if (!callback)
987         {
988             return OC_STACK_INVALID_PARAM;
989         }
990         OCStackResult result;
991         ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
992         OCCallbackData cbdata;
993         cbdata.context = static_cast<void*>(ctx),
994         cbdata.cb      = setResourceCallback;
995         cbdata.cd      = [](void* c){delete (ClientCallbackContext::SetContext*)c;};
996
997
998         std::string url = assembleSetResourceUri(uri, queryParams).c_str();
999
1000         auto cLock = m_csdkLock.lock();
1001
1002         if (cLock)
1003         {
1004             std::lock_guard<std::recursive_mutex> lock(*cLock);
1005             OCDoHandle handle;
1006             OCHeaderOption options[MAX_HEADER_OPTIONS];
1007
1008             result = OCDoResource(&handle, OC_REST_PUT,
1009                                   url.c_str(), &devAddr,
1010                                   assembleSetResourcePayload(rep),
1011                                   CT_DEFAULT,
1012                                   static_cast<OCQualityOfService>(QoS),
1013                                   &cbdata,
1014                                   assembleHeaderOptions(options, headerOptions),
1015                                   headerOptions.size());
1016         }
1017         else
1018         {
1019             delete ctx;
1020             result = OC_STACK_ERROR;
1021         }
1022
1023         return result;
1024     }
1025
1026     OCStackApplicationResult deleteResourceCallback(void* ctx,
1027                                                     OCDoHandle /*handle*/,
1028         OCClientResponse* clientResponse)
1029     {
1030         ClientCallbackContext::DeleteContext* context =
1031             static_cast<ClientCallbackContext::DeleteContext*>(ctx);
1032         HeaderOptions serverHeaderOptions;
1033
1034         parseServerHeaderOptions(clientResponse, serverHeaderOptions);
1035
1036         std::thread exec(context->callback, serverHeaderOptions, clientResponse->result);
1037         exec.detach();
1038         return OC_STACK_DELETE_TRANSACTION;
1039     }
1040
1041     OCStackResult InProcClientWrapper::DeleteResource(
1042         const OCDevAddr& devAddr,
1043         const std::string& uri,
1044         const HeaderOptions& headerOptions,
1045         OCConnectivityType connectivityType,
1046         DeleteCallback& callback,
1047         QualityOfService /*QoS*/)
1048     {
1049         if (!callback)
1050         {
1051             return OC_STACK_INVALID_PARAM;
1052         }
1053         OCStackResult result;
1054         ClientCallbackContext::DeleteContext* ctx =
1055             new ClientCallbackContext::DeleteContext(callback);
1056         OCCallbackData cbdata;
1057         cbdata.context = static_cast<void*>(ctx),
1058         cbdata.cb      = deleteResourceCallback;
1059         cbdata.cd      = [](void* c){delete (ClientCallbackContext::DeleteContext*)c;};
1060
1061
1062         auto cLock = m_csdkLock.lock();
1063
1064         if (cLock)
1065         {
1066             OCHeaderOption options[MAX_HEADER_OPTIONS];
1067
1068             std::lock_guard<std::recursive_mutex> lock(*cLock);
1069
1070             result = OCDoResource(nullptr, OC_REST_DELETE,
1071                                   uri.c_str(), &devAddr,
1072                                   nullptr,
1073                                   connectivityType,
1074                                   static_cast<OCQualityOfService>(m_cfg.QoS),
1075                                   &cbdata,
1076                                   assembleHeaderOptions(options, headerOptions),
1077                                   headerOptions.size());
1078         }
1079         else
1080         {
1081             delete ctx;
1082             result = OC_STACK_ERROR;
1083         }
1084
1085         return result;
1086     }
1087
1088     OCStackApplicationResult observeResourceCallback(void* ctx,
1089                                                      OCDoHandle /*handle*/,
1090         OCClientResponse* clientResponse)
1091     {
1092         ClientCallbackContext::ObserveContext* context =
1093             static_cast<ClientCallbackContext::ObserveContext*>(ctx);
1094         OCRepresentation attrs;
1095         HeaderOptions serverHeaderOptions;
1096         uint32_t sequenceNumber = clientResponse->sequenceNumber;
1097         OCStackResult result = clientResponse->result;
1098
1099         parseServerHeaderOptions(clientResponse, serverHeaderOptions);
1100         try
1101         {
1102             attrs = parseGetSetCallback(clientResponse);
1103         }
1104         catch(OC::OCException& e)
1105         {
1106             result = e.code();
1107         }
1108
1109         std::thread exec(context->callback, serverHeaderOptions, attrs,
1110                     result, sequenceNumber);
1111         exec.detach();
1112         if (sequenceNumber == MAX_SEQUENCE_NUMBER + 1)
1113         {
1114             return OC_STACK_DELETE_TRANSACTION;
1115         }
1116
1117         return OC_STACK_KEEP_TRANSACTION;
1118     }
1119
1120     OCStackResult InProcClientWrapper::ObserveResource(ObserveType observeType, OCDoHandle* handle,
1121         const OCDevAddr& devAddr,
1122         const std::string& uri,
1123         const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
1124         ObserveCallback& callback, QualityOfService QoS)
1125     {
1126         if (!callback)
1127         {
1128             return OC_STACK_INVALID_PARAM;
1129         }
1130         OCStackResult result;
1131
1132         ClientCallbackContext::ObserveContext* ctx =
1133             new ClientCallbackContext::ObserveContext(callback);
1134         OCCallbackData cbdata;
1135         cbdata.context = static_cast<void*>(ctx),
1136         cbdata.cb      = observeResourceCallback;
1137         cbdata.cd      = [](void* c){delete (ClientCallbackContext::ObserveContext*)c;};
1138
1139
1140         OCMethod method;
1141         if (observeType == ObserveType::Observe)
1142         {
1143             method = OC_REST_OBSERVE;
1144         }
1145         else if (observeType == ObserveType::ObserveAll)
1146         {
1147             method = OC_REST_OBSERVE_ALL;
1148         }
1149         else
1150         {
1151             method = OC_REST_OBSERVE_ALL;
1152         }
1153
1154         std::string url = assembleSetResourceUri(uri, queryParams).c_str();
1155
1156         auto cLock = m_csdkLock.lock();
1157
1158         if (cLock)
1159         {
1160             std::lock_guard<std::recursive_mutex> lock(*cLock);
1161             OCHeaderOption options[MAX_HEADER_OPTIONS];
1162
1163             result = OCDoResource(handle, method,
1164                                   url.c_str(), &devAddr,
1165                                   nullptr,
1166                                   CT_DEFAULT,
1167                                   static_cast<OCQualityOfService>(QoS),
1168                                   &cbdata,
1169                                   assembleHeaderOptions(options, headerOptions),
1170                                   headerOptions.size());
1171         }
1172         else
1173         {
1174             delete ctx;
1175             return OC_STACK_ERROR;
1176         }
1177
1178         return result;
1179     }
1180
1181     OCStackResult InProcClientWrapper::CancelObserveResource(
1182             OCDoHandle handle,
1183             const std::string& /*host*/,
1184             const std::string& /*uri*/,
1185             const HeaderOptions& headerOptions,
1186             QualityOfService QoS)
1187     {
1188         OCStackResult result;
1189         auto cLock = m_csdkLock.lock();
1190
1191         if (cLock)
1192         {
1193             std::lock_guard<std::recursive_mutex> lock(*cLock);
1194             OCHeaderOption options[MAX_HEADER_OPTIONS];
1195
1196             result = OCCancel(handle,
1197                     static_cast<OCQualityOfService>(QoS),
1198                     assembleHeaderOptions(options, headerOptions),
1199                     headerOptions.size());
1200         }
1201         else
1202         {
1203             result = OC_STACK_ERROR;
1204         }
1205
1206         return result;
1207     }
1208
1209     OCStackApplicationResult subscribePresenceCallback(void* ctx,
1210                                                        OCDoHandle /*handle*/,
1211             OCClientResponse* clientResponse)
1212     {
1213         ClientCallbackContext::SubscribePresenceContext* context =
1214         static_cast<ClientCallbackContext::SubscribePresenceContext*>(ctx);
1215
1216         /*
1217          * This a hack while we rethink presence subscription.
1218          */
1219         std::string url = clientResponse->devAddr.addr;
1220
1221         std::thread exec(context->callback, clientResponse->result,
1222                     clientResponse->sequenceNumber, url);
1223
1224         exec.detach();
1225
1226         return OC_STACK_KEEP_TRANSACTION;
1227     }
1228
1229     OCStackResult InProcClientWrapper::SubscribePresence(OCDoHandle* handle,
1230         const std::string& host, const std::string& resourceType,
1231         OCConnectivityType connectivityType, SubscribeCallback& presenceHandler)
1232     {
1233         if (!presenceHandler)
1234         {
1235             return OC_STACK_INVALID_PARAM;
1236         }
1237
1238         ClientCallbackContext::SubscribePresenceContext* ctx =
1239             new ClientCallbackContext::SubscribePresenceContext(presenceHandler);
1240         OCCallbackData cbdata;
1241         cbdata.context = static_cast<void*>(ctx),
1242         cbdata.cb      = subscribePresenceCallback;
1243         cbdata.cd      = [](void* c){delete (ClientCallbackContext::SubscribePresenceContext*)c;};
1244
1245
1246         auto cLock = m_csdkLock.lock();
1247
1248         std::ostringstream os;
1249         os << host << OC_RSRVD_PRESENCE_URI;
1250
1251         if (!resourceType.empty())
1252         {
1253             os << "?rt=" << resourceType;
1254         }
1255
1256         if (!cLock)
1257         {
1258             delete ctx;
1259             return OC_STACK_ERROR;
1260         }
1261
1262         return OCDoResource(handle, OC_REST_PRESENCE,
1263                             os.str().c_str(), nullptr,
1264                             nullptr, connectivityType,
1265                             OC_LOW_QOS, &cbdata, NULL, 0);
1266     }
1267
1268     OCStackResult InProcClientWrapper::UnsubscribePresence(OCDoHandle handle)
1269     {
1270         OCStackResult result;
1271         auto cLock = m_csdkLock.lock();
1272
1273         if (cLock)
1274         {
1275             std::lock_guard<std::recursive_mutex> lock(*cLock);
1276             result = OCCancel(handle, OC_LOW_QOS, NULL, 0);
1277         }
1278         else
1279         {
1280             result = OC_STACK_ERROR;
1281         }
1282
1283         return result;
1284     }
1285
1286 #ifdef WITH_CLOUD
1287     OCStackResult InProcClientWrapper::SubscribeDevicePresence(OCDoHandle* handle,
1288                                                                const std::string& host,
1289                                                                const std::vector<std::string>& di,
1290                                                                OCConnectivityType connectivityType,
1291                                                                ObserveCallback& callback)
1292     {
1293         if (!callback)
1294         {
1295             return OC_STACK_INVALID_PARAM;
1296         }
1297         OCStackResult result;
1298
1299         ClientCallbackContext::ObserveContext* ctx =
1300             new ClientCallbackContext::ObserveContext(callback);
1301         OCCallbackData cbdata;
1302         cbdata.context = static_cast<void*>(ctx),
1303         cbdata.cb      = observeResourceCallback;
1304         cbdata.cd      = [](void* c){delete (ClientCallbackContext::ObserveContext*)c;};
1305
1306         auto cLock = m_csdkLock.lock();
1307
1308         if (cLock)
1309         {
1310             std::lock_guard<std::recursive_mutex> lock(*cLock);
1311
1312             std::ostringstream os;
1313             os << host << OC_RSRVD_DEVICE_PRESENCE_URI;
1314             QueryParamsList queryParams({{OC_RSRVD_DEVICE_ID, di}});
1315             std::string url = assembleSetResourceUri(os.str(), queryParams);
1316
1317             result = OCDoResource(handle, OC_REST_OBSERVE,
1318                                   url.c_str(), nullptr,
1319                                   nullptr, connectivityType,
1320                                   OC_LOW_QOS, &cbdata,
1321                                   nullptr, 0);
1322         }
1323         else
1324         {
1325             delete ctx;
1326             result = OC_STACK_ERROR;
1327         }
1328
1329         return result;
1330     }
1331 #endif
1332
1333     OCStackResult InProcClientWrapper::GetDefaultQos(QualityOfService& qos)
1334     {
1335         qos = m_cfg.QoS;
1336         return OC_STACK_OK;
1337     }
1338
1339     OCHeaderOption* InProcClientWrapper::assembleHeaderOptions(OCHeaderOption options[],
1340            const HeaderOptions& headerOptions)
1341     {
1342         int i = 0;
1343
1344         if ( headerOptions.size() == 0)
1345         {
1346             return nullptr;
1347         }
1348
1349         for (auto it=headerOptions.begin(); it != headerOptions.end(); ++it)
1350         {
1351             options[i] = OCHeaderOption();
1352             options[i].protocolID = OC_COAP_ID;
1353             options[i].optionID = it->getOptionID();
1354             options[i].optionLength = it->getOptionData().length() + 1;
1355             strcpy((char*)options[i].optionData, (it->getOptionData().c_str()));
1356             i++;
1357         }
1358
1359         return options;
1360     }
1361
1362     std::shared_ptr<OCDirectPairing> cloneDevice(const OCDPDev_t* dev)
1363     {
1364         if (!dev)
1365         {
1366             return nullptr;
1367         }
1368
1369         OCDPDev_t* result = new OCDPDev_t(*dev);
1370         result->prm = new OCPrm_t[dev->prmLen];
1371         memcpy(result->prm, dev->prm, sizeof(OCPrm_t)*dev->prmLen);
1372         return std::shared_ptr<OCDirectPairing>(new OCDirectPairing(result));
1373     }
1374
1375     void InProcClientWrapper::convert(const OCDPDev_t *list, PairedDevices& dpList)
1376     {
1377         while(list)
1378         {
1379             dpList.push_back(cloneDevice(list));
1380             list = list->next;
1381         }
1382     }
1383
1384     OCStackResult InProcClientWrapper::FindDirectPairingDevices(unsigned short waittime,
1385             GetDirectPairedCallback& callback)
1386     {
1387         if (!callback || 0 == waittime)
1388         {
1389             return OC_STACK_INVALID_PARAM;
1390         }
1391
1392         OCStackResult result = OC_STACK_ERROR;
1393         const OCDPDev_t *list = nullptr;
1394         PairedDevices dpDeviceList;
1395
1396         auto cLock = m_csdkLock.lock();
1397
1398         if (cLock)
1399         {
1400             std::lock_guard<std::recursive_mutex> lock(*cLock);
1401
1402             list = OCDiscoverDirectPairingDevices(waittime);
1403             if (NULL == list)
1404             {
1405                 result = OC_STACK_NO_RESOURCE;
1406                 oclog() << "findDirectPairingDevices(): No device found for direct pairing"
1407                     << std::flush;
1408             }
1409             else {
1410                 convert(list, dpDeviceList);
1411                 std::thread exec(callback, dpDeviceList);
1412                 exec.detach();
1413                 result = OC_STACK_OK;
1414             }
1415         }
1416         else
1417         {
1418             result = OC_STACK_ERROR;
1419         }
1420
1421         return result;
1422     }
1423
1424     OCStackResult InProcClientWrapper::GetDirectPairedDevices(GetDirectPairedCallback& callback)
1425     {
1426         if (!callback)
1427         {
1428             return OC_STACK_INVALID_PARAM;
1429         }
1430
1431         OCStackResult result = OC_STACK_ERROR;
1432         const OCDPDev_t *list = nullptr;
1433         PairedDevices dpDeviceList;
1434
1435         auto cLock = m_csdkLock.lock();
1436
1437         if (cLock)
1438         {
1439             std::lock_guard<std::recursive_mutex> lock(*cLock);
1440
1441             list = OCGetDirectPairedDevices();
1442             if (NULL == list)
1443             {
1444                 result = OC_STACK_NO_RESOURCE;
1445                 oclog() << "findDirectPairingDevices(): No device found for direct pairing"
1446                     << std::flush;
1447             }
1448             else {
1449                 convert(list, dpDeviceList);
1450                 std::thread exec(callback, dpDeviceList);
1451                 exec.detach();
1452                 result = OC_STACK_OK;
1453             }
1454         }
1455         else
1456         {
1457             result = OC_STACK_ERROR;
1458         }
1459
1460         return result;
1461     }
1462
1463     void directPairingCallback(void *ctx, OCDPDev_t *peer,
1464             OCStackResult result)
1465     {
1466
1467         ClientCallbackContext::DirectPairingContext* context =
1468             static_cast<ClientCallbackContext::DirectPairingContext*>(ctx);
1469
1470         std::thread exec(context->callback, cloneDevice(peer), result);
1471         exec.detach();
1472     }
1473
1474     OCStackResult InProcClientWrapper::DoDirectPairing(std::shared_ptr<OCDirectPairing> peer,
1475             const OCPrm_t& pmSel, const std::string& pinNumber, DirectPairingCallback& callback)
1476     {
1477         if (!peer || !callback)
1478         {
1479             oclog() << "Invalid parameters" << std::flush;
1480             return OC_STACK_INVALID_PARAM;
1481         }
1482
1483         OCStackResult result = OC_STACK_ERROR;
1484         ClientCallbackContext::DirectPairingContext* context =
1485             new ClientCallbackContext::DirectPairingContext(callback);
1486
1487         auto cLock = m_csdkLock.lock();
1488         if (cLock)
1489         {
1490             std::lock_guard<std::recursive_mutex> lock(*cLock);
1491             result = OCDoDirectPairing(static_cast<void*>(context), peer->getDev(),
1492                     pmSel, const_cast<char*>(pinNumber.c_str()), directPairingCallback);
1493         }
1494         else
1495         {
1496             delete context;
1497             result = OC_STACK_ERROR;
1498         }
1499         return result;
1500     }
1501 }