[Update] change Api desgin and modify function & data structure naming issue.
[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
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::getConfigurationStatusHandler (
92                 std::shared_ptr< GetConfigurationStatus > status)
93         {
94             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getConfigurationStatusHandler");
95
96             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d", status->getESResult());
97
98             m_getConfigurationStatusCb(status);
99         }
100
101         void RemoteEnrollee::devicePropProvisioningStatusHandler(
102                 std::shared_ptr< DevicePropProvisioningStatus > status)
103         {
104             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering DevicePropProvisioningStatusHandler");
105
106             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
107
108             m_devicePropProvStatusCb(status);
109
110             return;
111         }
112
113         void RemoteEnrollee::cloudPropProvisioningStatusHandler (
114                 std::shared_ptr< CloudPropProvisioningStatus > status)
115         {
116             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudPropProvisioningStatusHandler");
117
118             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d", status->getESCloudState());
119
120             m_cloudPropProvStatusCb(status);
121             return;
122         }
123
124         ESResult RemoteEnrollee::ESDiscoveryTimeout(unsigned short waittime)
125         {
126             struct timespec startTime;
127             startTime.tv_sec=0;
128             startTime.tv_sec=0;
129             struct timespec currTime;
130             currTime.tv_sec=0;
131             currTime.tv_nsec=0;
132
133             ESResult res = ES_OK;
134             #ifdef _POSIX_MONOTONIC_CLOCK
135                 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
136             #else
137                 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
138             #endif
139
140             if (0 != clock_res)
141             {
142                 return ES_ERROR;
143             }
144
145             while (ES_OK == res || m_discoveryResponse == false)
146             {
147                 #ifdef _POSIX_MONOTONIC_CLOCK
148                         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
149                 #else
150                         clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
151                 #endif
152
153                 if (0 != clock_res)
154                 {
155                     return ES_ERROR;
156                 }
157                 long elapsed = (currTime.tv_sec - startTime.tv_sec);
158                 if (elapsed > waittime)
159                 {
160                     return ES_OK;
161                 }
162                 if (m_discoveryResponse)
163                 {
164                     res = ES_OK;
165                 }
166              }
167              return res;
168         }
169
170         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
171         {
172             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
173
174             std::string resourceURI;
175             std::string hostAddress;
176             std::string hostDeviceID;
177
178             try
179             {
180                 if(resource)
181                 {
182                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
183                     {
184                         // Get the resource URI
185                         resourceURI = resource->uri();
186                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
187                                 "URI of the resource: %s", resourceURI.c_str());
188
189                         // Get the resource host address
190                         hostAddress = resource->host();
191                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
192                                 "Host address of the resource: %s", hostAddress.c_str());
193
194                         hostDeviceID = resource->sid();
195                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
196                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
197
198                         if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
199                         {
200                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
201                             m_ocResource = resource;
202                             m_discoveryResponse = true;
203                         }
204                     }
205                 }
206             }
207             catch(std::exception& e)
208             {
209                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
210                         "Exception in foundResource: %s", e.what());
211             }
212         }
213
214         ESResult RemoteEnrollee::discoverResource()
215         {
216             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
217
218             std::string query("");
219             query.append(ES_BASE_RES_URI);
220             query.append("?rt=");
221             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
222
223             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
224
225             m_discoveryResponse = false;
226
227             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
228                     std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
229                                                     std::placeholders::_1);
230             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
231                     onDeviceDiscoveredCb);
232
233             if (result != OCStackResult::OC_STACK_OK)
234             {
235                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
236                         "Failed discoverResource");
237                 return ES_ERROR;
238             }
239
240             ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
241
242             if (foundResponse == ES_ERROR || !m_discoveryResponse)
243             {
244                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
245                         "Failed discoverResource because timeout");
246                 return ES_ERROR;
247             }
248             return ES_OK;
249         }
250
251         void RemoteEnrollee::configureSecurity(SecurityProvStatusCb callback)
252         {
253 #ifdef __WITH_DTLS__
254             m_securityProvStatusCb = callback;
255
256             SecurityProvStatusCb securityProvStatusCb = std::bind(
257                     &RemoteEnrollee::securityStatusHandler,
258                     this,
259                     std::placeholders::_1);
260             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
261             m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
262
263             m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb, m_securityPinCb, m_secProvisioningDbPathCb);
264
265             try
266             {
267                 m_enrolleeSecurity->performOwnershipTransfer();
268             }
269             catch (OCException & e)
270             {
271                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
272                         "Exception for performOwnershipTransfer : %s", e.reason().c_str());
273
274                 OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Fail performOwnershipTransfer");
275                     std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
276                             std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
277                     m_securityProvStatusCb(securityProvisioningStatus);
278                 return ;
279             }
280 #else
281             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
282
283             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
284                      std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
285             m_securityProvStatusCb(securityProvisioningStatus);
286 #endif
287         }
288
289         void RemoteEnrollee::getConfiguration(GetConfigurationStatusCb callback)
290         {
291             if(!callback)
292             {
293                 throw ESInvalidParameterException("Callback is empty");
294             }
295
296             m_getConfigurationStatusCb = callback;
297
298             if (m_enrolleeResource == nullptr)
299             {
300                 throw ESBadRequestException ("Device not created");
301             }
302
303             GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
304                     &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
305             m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
306             m_enrolleeResource->getConfiguration();
307         }
308
309         void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& devProp, DevicePropProvStatusCb callback)
310         {
311             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionDeviceProperties");
312
313             if(!callback)
314             {
315                 throw ESInvalidParameterException("Callback is empty");
316             }
317
318             m_devicePropProvStatusCb = callback;
319
320             if (m_enrolleeResource == nullptr)
321             {
322                 throw ESBadRequestException ("Device not created");
323             }
324
325             if(devProp.WIFI.ssid.empty())
326             {
327                 throw ESBadRequestException ("Invalid Provisiong Data.");
328             }
329
330             DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
331                     &RemoteEnrollee::devicePropProvisioningStatusHandler, this, std::placeholders::_1);
332
333             m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
334             m_enrolleeResource->provisionEnrollee(devProp);
335         }
336
337         void RemoteEnrollee::initCloudResource()
338         {
339             ESResult result = ES_ERROR;
340
341             if (m_cloudResource != nullptr)
342             {
343                 throw ESBadRequestException ("Already created");
344             }
345
346             result = discoverResource();
347
348             if (result == ES_ERROR)
349             {
350                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
351                                     "Failed to create resource object using discoverResource");
352                 throw ESBadRequestException ("Resource object not created");
353             }
354
355             else
356             {
357                 if(m_ocResource != nullptr)
358                 {
359                     m_cloudResource = std::make_shared<CloudResource>(std::move(m_ocResource));
360
361                     std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
362                         CloudPropProvisioningStatus >(ESResult::ES_OK, ESCloudProvState::ES_CLOUD_ENROLLEE_FOUND);
363
364                     m_cloudPropProvStatusCb(provStatus);
365                 }
366                 else
367                 {
368                     throw ESBadGetException ("Resource handle is invalid");
369                 }
370             }
371         }
372
373
374         void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp, CloudPropProvStatusCb callback)
375         {
376             OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionCloudProperties");
377
378             ESResult result = ES_ERROR;
379
380             if(!callback)
381             {
382                 throw ESInvalidParameterException("Callback is empty");
383             }
384
385             m_cloudPropProvStatusCb = callback;
386
387             if(cloudProp.authCode.empty()
388                 || cloudProp.authProvider.empty()
389                 || cloudProp.ciServer.empty())
390             {
391                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
392             }
393
394             try
395             {
396                 initCloudResource();
397             }
398
399             catch (const std::exception& e)
400             {
401                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
402                     "Exception caught in provisionCloudProperties = %s", e.what());
403
404                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
405                         CloudPropProvisioningStatus >(ESResult::ES_ERROR, ESCloudProvState::ES_CLOUD_ENROLLEE_NOT_FOUND);
406                 m_cloudPropProvStatusCb(provStatus);
407             }
408
409             if (m_cloudResource == nullptr)
410             {
411                 throw ESBadRequestException ("Cloud Resource not created");
412             }
413
414             CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
415                     &RemoteEnrollee::cloudPropProvisioningStatusHandler, this, std::placeholders::_1);
416
417             m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
418             m_cloudResource->provisionEnrollee(cloudProp);
419         }
420
421         void RemoteEnrollee::setDevID(const std::string devId)
422         {
423             m_deviceId = devId;
424         }
425     }
426 }