Fix an faulty logic in resource handler and clean up useless codes
[platform/upstream/iotivity.git] / service / easy-setup / mediator / richsdk / src / RemoteEnrollee.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 "RemoteEnrollee.h"
22 #include "EnrolleeResource.h"
23 #include "CloudResource.h"
24 #include "OCPlatform.h"
25 #include "ESException.h"
26 #include "logger.h"
27 #include "OCResource.h"
28 #ifdef __WITH_DTLS__
29 #include "EnrolleeSecurity.h"
30 #endif //__WITH_DTLS
31
32 namespace OIC
33 {
34     namespace Service
35     {
36         static const char ES_BASE_RES_URI[] = "/oic/res";
37         #define ES_REMOTE_ENROLLEE_TAG "ES_REMOTE_ENROLLEE"
38         #define DISCOVERY_TIMEOUT 5
39
40         RemoteEnrollee::RemoteEnrollee()
41         {
42             m_securityProvStatusCb = nullptr;
43             m_requestPropertyDataStatusCb = nullptr;
44             m_securityPinCb = nullptr;
45             m_secProvisioningDbPathCb = nullptr;
46             m_dataProvStatusCb = nullptr;
47             m_cloudProvStatusCb = nullptr;
48
49             //m_deviceId = nullptr;
50         }
51
52 #ifdef __WITH_DTLS__
53         ESResult RemoteEnrollee::registerSecurityCallbackHandler(SecurityPinCb securityPinCb,
54                 SecProvisioningDbPathCb secProvisioningDbPathCb)
55         {
56             // No need to check NULL for m_secProvisioningDbPathCB as this is not a mandatory
57             // callback function. If m_secProvisioningDbPathCB is NULL, provisioning manager
58             // in security layer will try to find the PDM.db file in the local path.
59             // If PDM.db is found, the provisioning manager operations will succeed.
60             // Otherwise all the provisioning manager operations will fail.
61             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
62             m_securityPinCb = securityPinCb;
63             return ES_OK;
64         }
65 #endif //__WITH_DTLS__
66
67         void RemoteEnrollee::securityStatusHandler(
68                         std::shared_ptr< SecProvisioningStatus > status)
69         {
70             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s, "
71                     "Status = %d", status->getDeviceUUID().c_str(),
72                     status->getESResult());
73
74             if(status->getESResult() == ES_OK)
75             {
76                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
77                         "Continue with Network information provisioning");
78
79                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
80
81                 m_securityProvStatusCb(status);
82             }
83             else
84             {
85                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are fail");
86
87                 m_securityProvStatusCb(status);
88             }
89         }
90
91         void RemoteEnrollee::RequestPropertyDataStatusHandler (
92                 std::shared_ptr< RequestPropertyDataStatus > status)
93         {
94             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering RequestPropertyDataStatusHandler");
95
96             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"RequestPropertyDataStatus = %d", status->getESResult());
97
98             if(status->getESResult() == ES_OK)
99             {
100                 m_propertyData = status->getPropertyData();
101             }
102
103             m_requestPropertyDataStatusCb(status);
104         }
105
106         void RemoteEnrollee::dataProvisioningStatusHandler(
107                 std::shared_ptr< DataProvisioningStatus > status)
108         {
109             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering dataProvisioningStatusHandler");
110
111             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
112
113             if (status->getESResult() == ES_OK)
114             {
115                 if (status->getESDataProvState() >= ESDataProvState::ES_PROVISIONED_ALREADY)
116                 {
117                     OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
118                 }
119             }
120             m_dataProvStatusCb(status);
121
122             return;
123         }
124
125         void RemoteEnrollee::cloudProvisioningStatusHandler (
126                 std::shared_ptr< CloudProvisioningStatus > status)
127         {
128             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudProvisioningStatusHandler");
129
130             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d", status->getESCloudState());
131
132             m_cloudProvStatusCb(status);
133             return;
134         }
135
136         ESResult RemoteEnrollee::ESDiscoveryTimeout(unsigned short waittime)
137         {
138             struct timespec startTime;
139             startTime.tv_sec=0;
140             startTime.tv_sec=0;
141             struct timespec currTime;
142             currTime.tv_sec=0;
143             currTime.tv_nsec=0;
144
145             ESResult res = ES_OK;
146             #ifdef _POSIX_MONOTONIC_CLOCK
147                 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
148             #else
149                 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
150             #endif
151
152             if (0 != clock_res)
153             {
154                 return ES_ERROR;
155             }
156
157             while (ES_OK == res || m_discoveryResponse == false)
158             {
159                 #ifdef _POSIX_MONOTONIC_CLOCK
160                         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
161                 #else
162                         clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
163                 #endif
164
165                 if (0 != clock_res)
166                 {
167                     return ES_ERROR;
168                 }
169                 long elapsed = (currTime.tv_sec - startTime.tv_sec);
170                 if (elapsed > waittime)
171                 {
172                     return ES_OK;
173                 }
174                 if (m_discoveryResponse)
175                 {
176                     res = ES_OK;
177                 }
178              }
179              return res;
180         }
181
182         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
183         {
184             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
185
186             std::string resourceURI;
187             std::string hostAddress;
188             std::string hostDeviceID;
189
190             try
191             {
192                 if(resource)
193                 {
194                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
195                     {
196                         // Get the resource URI
197                         resourceURI = resource->uri();
198                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
199                                 "URI of the resource: %s", resourceURI.c_str());
200
201                         // Get the resource host address
202                         hostAddress = resource->host();
203                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
204                                 "Host address of the resource: %s", hostAddress.c_str());
205
206                         hostDeviceID = resource->sid();
207                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
208                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
209
210                         if(m_deviceId .empty())
211                         {
212                             /*
213                              * Easysetup is always performed with a single Enrollee device and
214                              * in a private network (SoftAP or BLE), so the assumption is that
215                              * only the intended device will respond for the discovery.
216                              * With the above assumption the below two statements are written.
217                              */
218                             m_ocResource = resource;
219                             m_deviceId = resource->sid();
220                             m_discoveryResponse = true;
221                         }
222
223                         else if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
224                         {
225                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
226                             m_ocResource = resource;
227                             m_discoveryResponse = true;
228                         }
229                     }
230                 }
231             }
232             catch(std::exception& e)
233             {
234                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
235                         "Exception in foundResource: %s", e.what());
236             }
237         }
238
239         ESResult RemoteEnrollee::discoverResource()
240         {
241             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
242
243             if (m_ocResource != nullptr)
244             {
245                 throw ESBadRequestException("resource is already created");
246             }
247
248             std::string query("");
249             query.append(ES_BASE_RES_URI);
250             query.append("?rt=");
251             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
252
253             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
254
255             m_discoveryResponse = false;
256
257             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
258                     std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
259                                                     std::placeholders::_1);
260             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
261                     onDeviceDiscoveredCb);
262
263             if (result != OCStackResult::OC_STACK_OK)
264             {
265                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
266                         "Failed discoverResource");
267                 return ES_ERROR;
268             }
269
270             ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
271
272             if (foundResponse == ES_ERROR || !m_discoveryResponse)
273             {
274                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
275                         "Failed discoverResource because timeout");
276                 return ES_ERROR;
277             }
278             return ES_OK;
279         }
280
281         void RemoteEnrollee::initRemoteEnrollee()
282         {
283             ESResult result = ES_ERROR;
284
285             if (m_enrolleeResource != nullptr)
286             {
287                 throw ESBadRequestException ("Already created");
288             }
289
290             result = discoverResource();
291
292             if (result == ES_ERROR)
293             {
294                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
295                                     "Failed to create resource object using discoverResource");
296                 throw ESBadRequestException ("Resource object not created");
297             }
298
299             else
300             {
301                 if(m_ocResource != nullptr)
302                 {
303                     m_enrolleeResource = std::make_shared<EnrolleeResource>(std::move(m_ocResource));
304                 }
305                 else
306                 {
307                     throw ESBadGetException ("Resource handle is invalid");
308                 }
309             }
310         }
311
312         void RemoteEnrollee::startSecurityProvisioning(SecurityProvStatusCb callback)
313         {
314 #ifdef __WITH_DTLS__
315             m_securityProvStatusCb = callback;
316
317             SecurityProvStatusCb securityProvStatusCb = std::bind(
318                     &RemoteEnrollee::securityStatusHandler,
319                     this,
320                     std::placeholders::_1);
321             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
322             m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_enrolleeResource, "");
323
324             m_enrolleeSecurity->setTargetDevID(m_deviceId);
325             m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb, m_securityPinCb, m_secProvisioningDbPathCb);
326
327             try
328             {
329                 m_enrolleeSecurity->performOwnershipTransfer();
330             }
331             catch (OCException & e)
332             {
333                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
334                         "Exception for performOwnershipTransfer : %s", e.reason().c_str());
335
336                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Fail performOwnershipTransfer");
337                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
338                             std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
339                     m_securityProvStatusCb(securityProvisioningStatus);
340                 return ;
341             }
342 #else
343             (void) callback;
344             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
345
346             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
347                      std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
348             m_securityProvStatusCb(securityProvisioningStatus);
349 #endif
350         }
351
352         void RemoteEnrollee::requestPropertyData(RequestPropertyDataStatusCb callback)
353         {
354             if(!callback)
355             {
356                 throw ESInvalidParameterException("Callback is empty");
357             }
358
359             m_requestPropertyDataStatusCb = callback;
360
361             if (m_enrolleeResource == nullptr)
362             {
363                 throw ESBadRequestException ("Device not created");
364             }
365
366             RequestPropertyDataStatusCb RequestPropertyDataStatusCb = std::bind(
367                     &RemoteEnrollee::RequestPropertyDataStatusHandler, this, std::placeholders::_1);
368             m_enrolleeResource->registerRequestPropertyDataStatusCallback(RequestPropertyDataStatusCb);
369             m_enrolleeResource->RequestPropertyData();
370         }
371
372         void RemoteEnrollee::startDataProvisioning(DataProvStatusCb callback)
373         {
374             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter startDataProvisioning");
375
376             if(!callback)
377             {
378                 throw ESInvalidParameterException("Callback is empty");
379             }
380
381             m_dataProvStatusCb = callback;
382
383             if (m_enrolleeResource == nullptr)
384             {
385                 throw ESBadRequestException ("Device not created");
386             }
387
388             if(m_dataProvInfo.WIFI.ssid.empty())
389             {
390                 throw ESBadRequestException ("Invalid Provisiong Data.");
391             }
392
393             m_dataProvStatusCb = callback;
394
395             DataProvStatusCb dataProvStatusCb = std::bind(
396                     &RemoteEnrollee::dataProvisioningStatusHandler, this, std::placeholders::_1);
397
398             m_enrolleeResource->registerProvStatusCallback(dataProvStatusCb);
399             m_enrolleeResource->provisionEnrollee(m_dataProvInfo);
400         }
401
402         void RemoteEnrollee::initCloudResource()
403         {
404             ESResult result = ES_ERROR;
405
406             if (m_cloudResource != nullptr)
407             {
408                 throw ESBadRequestException ("Already created");
409             }
410
411             result = discoverResource();
412
413             if (result == ES_ERROR)
414             {
415                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
416                                     "Failed to create resource object using discoverResource");
417                 throw ESBadRequestException ("Resource object not created");
418             }
419
420             else
421             {
422                 if(m_ocResource != nullptr)
423                 {
424                     m_cloudResource = std::make_shared<CloudResource>(std::move(m_ocResource));
425
426                     std::shared_ptr< CloudProvisioningStatus > provStatus = std::make_shared<
427                         CloudProvisioningStatus >(ESResult::ES_OK, ESCloudProvState::ES_CLOUD_ENROLLEE_FOUND);
428
429                     m_cloudProvStatusCb(provStatus);
430                 }
431                 else
432                 {
433                     throw ESBadGetException ("Resource handle is invalid");
434                 }
435             }
436         }
437
438
439         void RemoteEnrollee::startCloudProvisioning(CloudProvStatusCb callback)
440         {
441             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter startCloudProvisioning");
442
443             if(!callback)
444             {
445                 throw ESInvalidParameterException("Callback is empty");
446             }
447
448             m_cloudProvStatusCb = callback;
449
450             try
451             {
452                 initCloudResource();
453             }
454
455             catch (const std::exception& e)
456             {
457                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
458                     "Exception caught in startCloudProvisioning = %s", e.what());
459
460                 std::shared_ptr< CloudProvisioningStatus > provStatus = std::make_shared<
461                         CloudProvisioningStatus >(ESResult::ES_ERROR, ESCloudProvState::ES_CLOUD_ENROLLEE_NOT_FOUND);
462                 m_cloudProvStatusCb(provStatus);
463             }
464
465             if (m_cloudResource == nullptr)
466             {
467                 throw ESBadRequestException ("Cloud Resource not created");
468             }
469
470             if(m_cloudProvInfo.authCode.empty()
471                 || m_cloudProvInfo.authProvider.empty()
472                 || m_cloudProvInfo.ciServer.empty())
473             {
474                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
475             }
476
477             CloudProvStatusCb cloudProvStatusCb = std::bind(
478                     &RemoteEnrollee::cloudProvisioningStatusHandler, this, std::placeholders::_1);
479
480             m_cloudResource->registerCloudProvisioningStatusCallback(cloudProvStatusCb);
481             m_cloudResource->provisionEnrollee(m_cloudProvInfo);
482         }
483
484         void RemoteEnrollee::setDataProvInfo(const DataProvInfo& dataProvInfo)
485         {
486             m_dataProvInfo = dataProvInfo;
487         }
488
489         void RemoteEnrollee::setCloudProvInfo(const CloudProvInfo& cloudProvInfo)
490         {
491             m_cloudProvInfo = cloudProvInfo;
492         }
493
494         DataProvInfo RemoteEnrollee::getDataProvInfo()
495         {
496             return m_dataProvInfo;
497         }
498     }
499 }