Merge branch 'master' into extended-easysetup
[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(std::shared_ptr< OC::OCResource > resource)
41         {
42             m_ocResource = resource;
43             m_enrolleeResource = std::make_shared<EnrolleeResource>(m_ocResource);
44             m_securityProvStatusCb = nullptr;
45             m_getConfigurationStatusCb = nullptr;
46             m_securityPinCb = nullptr;
47             m_secProvisioningDbPathCb = nullptr;
48             m_devicePropProvStatusCb = nullptr;
49             m_cloudPropProvStatusCb = nullptr;
50
51             m_deviceId = resource->sid();
52         }
53
54 #ifdef __WITH_DTLS__
55         ESResult RemoteEnrollee::registerSecurityCallbackHandler(SecurityPinCb securityPinCb,
56                 SecProvisioningDbPathCb secProvisioningDbPathCb)
57         {
58             // No need to check NULL for m_secProvisioningDbPathCB as this is not a mandatory
59             // callback function. If m_secProvisioningDbPathCB is NULL, provisioning manager
60             // in security layer will try to find the PDM.db file in the local path.
61             // If PDM.db is found, the provisioning manager operations will succeed.
62             // Otherwise all the provisioning manager operations will fail.
63             m_secProvisioningDbPathCb = secProvisioningDbPathCb;
64             m_securityPinCb = securityPinCb;
65             return ES_OK;
66         }
67 #endif //__WITH_DTLS__
68
69         void RemoteEnrollee::securityStatusHandler(
70                         std::shared_ptr< SecProvisioningStatus > status)
71         {
72             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s, "
73                     "Status = %d", status->getDeviceUUID().c_str(),
74                     status->getESResult());
75
76             if(status->getESResult() == ES_OK)
77             {
78                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
79                         "Continue with Network information provisioning");
80
81                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
82
83                 m_securityProvStatusCb(status);
84             }
85             else
86             {
87                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are fail");
88
89                 m_securityProvStatusCb(status);
90             }
91         }
92
93         void RemoteEnrollee::getStatusHandler(std::shared_ptr< GetEnrolleeStatus > status)
94         {
95             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getStatusHandler");
96
97             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"getStatusHandler = %d", status->getESResult());
98
99             m_getStatusCb(status);
100         }
101
102         void RemoteEnrollee::getConfigurationStatusHandler (
103                 std::shared_ptr< GetConfigurationStatus > status)
104         {
105             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getConfigurationStatusHandler");
106
107             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d", status->getESResult());
108
109             m_getConfigurationStatusCb(status);
110         }
111
112         void RemoteEnrollee::devicePropProvisioningStatusHandler(
113                 std::shared_ptr< DevicePropProvisioningStatus > status)
114         {
115             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering DevicePropProvisioningStatusHandler");
116
117             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
118
119             m_devicePropProvStatusCb(status);
120
121             return;
122         }
123
124         void RemoteEnrollee::cloudPropProvisioningStatusHandler (
125                 std::shared_ptr< CloudPropProvisioningStatus > status)
126         {
127             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudPropProvisioningStatusHandler");
128
129             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d", status->getESCloudState());
130
131             m_cloudPropProvStatusCb(status);
132             return;
133         }
134
135         ESResult RemoteEnrollee::ESDiscoveryTimeout(unsigned short waittime)
136         {
137             struct timespec startTime;
138             startTime.tv_sec=0;
139             startTime.tv_sec=0;
140             struct timespec currTime;
141             currTime.tv_sec=0;
142             currTime.tv_nsec=0;
143
144             ESResult res = ES_OK;
145             #ifdef _POSIX_MONOTONIC_CLOCK
146                 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
147             #else
148                 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
149             #endif
150
151             if (0 != clock_res)
152             {
153                 return ES_ERROR;
154             }
155
156             while (ES_OK == res || m_discoveryResponse == false)
157             {
158                 #ifdef _POSIX_MONOTONIC_CLOCK
159                         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
160                 #else
161                         clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
162                 #endif
163
164                 if (0 != clock_res)
165                 {
166                     return ES_ERROR;
167                 }
168                 long elapsed = (currTime.tv_sec - startTime.tv_sec);
169                 if (elapsed > waittime)
170                 {
171                     return ES_OK;
172                 }
173                 if (m_discoveryResponse)
174                 {
175                     res = ES_OK;
176                 }
177              }
178              return res;
179         }
180
181         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
182         {
183             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
184
185             std::string resourceURI;
186             std::string hostAddress;
187             std::string hostDeviceID;
188
189             try
190             {
191                 if(resource)
192                 {
193                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
194                     {
195                         // Get the resource URI
196                         resourceURI = resource->uri();
197                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
198                                 "URI of the resource: %s", resourceURI.c_str());
199
200                         // Get the resource host address
201                         hostAddress = resource->host();
202                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
203                                 "Host address of the resource: %s", hostAddress.c_str());
204
205                         hostDeviceID = resource->sid();
206                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
207                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
208
209                         if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
210                         {
211                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
212                             m_ocResource = resource;
213                             m_discoveryResponse = true;
214                         }
215                     }
216                 }
217             }
218             catch(std::exception& e)
219             {
220                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
221                         "Exception in foundResource: %s", e.what());
222             }
223         }
224
225         ESResult RemoteEnrollee::discoverResource()
226         {
227             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
228
229             std::string query("");
230             query.append(ES_BASE_RES_URI);
231             query.append("?rt=");
232             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
233
234             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
235
236             m_discoveryResponse = false;
237
238             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
239                     std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
240                                                     std::placeholders::_1);
241             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
242                     onDeviceDiscoveredCb);
243
244             if (result != OCStackResult::OC_STACK_OK)
245             {
246                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
247                         "Failed discoverResource");
248                 return ES_ERROR;
249             }
250
251             ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
252
253             if (foundResponse == ES_ERROR || !m_discoveryResponse)
254             {
255                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
256                         "Failed discoverResource because timeout");
257                 return ES_ERROR;
258             }
259             return ES_OK;
260         }
261
262         void RemoteEnrollee::provisionSecurity(SecurityProvStatusCb callback)
263         {
264 #ifdef __WITH_DTLS__
265             m_securityProvStatusCb = callback;
266
267             SecurityProvStatusCb securityProvStatusCb = std::bind(
268                     &RemoteEnrollee::securityStatusHandler,
269                     this,
270                     std::placeholders::_1);
271             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
272             m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
273
274             m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb, m_securityPinCb, m_secProvisioningDbPathCb);
275
276             try
277             {
278                 m_enrolleeSecurity->performOwnershipTransfer();
279             }
280             catch (OCException & e)
281             {
282                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
283                         "Exception for performOwnershipTransfer : %s", e.reason().c_str());
284
285                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Fail performOwnershipTransfer");
286                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
287                             std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
288                     m_securityProvStatusCb(securityProvisioningStatus);
289                 return ;
290             }
291 #else
292             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
293
294             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
295                      std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
296             m_securityProvStatusCb(securityProvisioningStatus);
297 #endif
298         }
299
300         void RemoteEnrollee::getStatus(GetStatusCb callback)
301         {
302             if(!callback)
303             {
304                 throw ESInvalidParameterException("Callback is empty");
305             }
306
307             if (m_enrolleeResource == nullptr)
308             {
309                 throw ESBadRequestException ("Device not created");
310             }
311
312             m_getStatusCb = callback;
313
314             GetStatusCb getStatusCb = std::bind(
315                 &RemoteEnrollee::getStatusHandler, this, std::placeholders::_1);
316             m_enrolleeResource->registerGetStatusCallback(getStatusCb);
317             m_enrolleeResource->getStatus();
318
319         }
320
321         void RemoteEnrollee::getConfiguration(GetConfigurationStatusCb callback)
322         {
323             if(!callback)
324             {
325                 throw ESInvalidParameterException("Callback is empty");
326             }
327
328             if (m_enrolleeResource == nullptr)
329             {
330                 throw ESBadRequestException ("Device not created");
331             }
332
333             m_getConfigurationStatusCb = callback;
334
335             GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
336                     &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
337             m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
338             m_enrolleeResource->getConfiguration();
339         }
340
341         void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& devProp, DevicePropProvStatusCb callback)
342         {
343             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionDeviceProperties");
344
345             if(!callback)
346             {
347                 throw ESInvalidParameterException("Callback is empty");
348             }
349
350             m_devicePropProvStatusCb = callback;
351
352             if (m_enrolleeResource == nullptr)
353             {
354                 throw ESBadRequestException ("Device not created");
355             }
356
357             if(devProp.WIFI.ssid.empty())
358             {
359                 throw ESBadRequestException ("Invalid Provisiong Data.");
360             }
361
362             DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
363                     &RemoteEnrollee::devicePropProvisioningStatusHandler, this, std::placeholders::_1);
364
365             m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
366             m_enrolleeResource->provisionEnrollee(devProp);
367         }
368
369         void RemoteEnrollee::initCloudResource()
370         {
371             ESResult result = ES_ERROR;
372
373             if (m_cloudResource != nullptr)
374             {
375                 throw ESBadRequestException ("Already created");
376             }
377
378             result = discoverResource();
379
380             if (result == ES_ERROR)
381             {
382                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
383                                     "Failed to create resource object using discoverResource");
384                 throw ESBadRequestException ("Resource object not created");
385             }
386
387             else
388             {
389                 if(m_ocResource != nullptr)
390                 {
391                     m_cloudResource = std::make_shared<CloudResource>(std::move(m_ocResource));
392
393                     std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
394                         CloudPropProvisioningStatus >(ESResult::ES_OK, ESCloudProvState::ES_CLOUD_ENROLLEE_FOUND);
395
396                     m_cloudPropProvStatusCb(provStatus);
397                 }
398                 else
399                 {
400                     throw ESBadGetException ("Resource handle is invalid");
401                 }
402             }
403         }
404
405
406         void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp, CloudPropProvStatusCb callback)
407         {
408             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionCloudProperties");
409
410             ESResult result = ES_ERROR;
411
412             if(!callback)
413             {
414                 throw ESInvalidParameterException("Callback is empty");
415             }
416
417             m_cloudPropProvStatusCb = callback;
418
419             if(cloudProp.authCode.empty()
420                 || cloudProp.authProvider.empty()
421                 || cloudProp.ciServer.empty())
422             {
423                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
424             }
425
426             try
427             {
428                 initCloudResource();
429             }
430
431             catch (const std::exception& e)
432             {
433                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
434                     "Exception caught in provisionCloudProperties = %s", e.what());
435
436                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
437                         CloudPropProvisioningStatus >(ESResult::ES_ERROR, ESCloudProvState::ES_CLOUD_ENROLLEE_NOT_FOUND);
438                 m_cloudPropProvStatusCb(provStatus);
439             }
440
441             if (m_cloudResource == nullptr)
442             {
443                 throw ESBadRequestException ("Cloud Resource not created");
444             }
445
446             CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
447                     &RemoteEnrollee::cloudPropProvisioningStatusHandler, this, std::placeholders::_1);
448
449             m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
450             m_cloudResource->provisionEnrollee(cloudProp);
451         }
452     }
453 }