Change a timeout for resource discovery in cloud provisioning
[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 #include "base64.h"
31 #include "oic_malloc.h"
32 #endif //__WITH_DTLS
33
34 namespace OIC
35 {
36     namespace Service
37     {
38         static const char ES_BASE_RES_URI[] = "/oic/res";
39         #define ES_REMOTE_ENROLLEE_TAG "ES_REMOTE_ENROLLEE"
40         #define DISCOVERY_TIMEOUT 1
41
42         RemoteEnrollee::RemoteEnrollee(const std::shared_ptr< OC::OCResource > resource)
43         {
44             m_ocResource = resource;
45             m_enrolleeResource = std::make_shared<EnrolleeResource>(m_ocResource);
46             m_securityProvStatusCb = nullptr;
47             m_getConfigurationStatusCb = nullptr;
48             m_securityPinCb = nullptr;
49             m_secProvisioningDbPathCb = nullptr;
50             m_devicePropProvStatusCb = nullptr;
51             m_cloudPropProvStatusCb = nullptr;
52
53             m_deviceId = resource->sid();
54         }
55
56         void RemoteEnrollee::securityStatusHandler(
57                 const std::shared_ptr< SecProvisioningStatus > status) const
58         {
59             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "securityStatusHandlr IN");
60             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "UUID = %s, ESResult = %d",
61                     status->getDeviceUUID().c_str(), status->getESResult());
62
63             if(status->getESResult() == ES_OK)
64             {
65                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership transfer is successfully done.");
66                 m_securityProvStatusCb(status);
67             }
68             else
69             {
70                 OIC_LOG(ERROR, ES_REMOTE_ENROLLEE_TAG, "Ownership transfer is failed.");
71                 m_securityProvStatusCb(status);
72             }
73             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "securityStatusHandlr OUT");
74         }
75
76         void RemoteEnrollee::getStatusHandler(
77                 const std::shared_ptr< GetEnrolleeStatus > status) const
78         {
79             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getStatusHandler IN");
80
81             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getStatusHandler = %d",
82                                                     status->getESResult());
83             m_getStatusCb(status);
84
85             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getStatusHandler OUT");
86         }
87
88         void RemoteEnrollee::getConfigurationStatusHandler (
89                 const std::shared_ptr< GetConfigurationStatus > status) const
90         {
91             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getConfigurationStatusHandler IN");
92
93             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d",
94                                                     status->getESResult());
95             m_getConfigurationStatusCb(status);
96
97             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getConfigurationStatusHandler OUT");
98         }
99
100         void RemoteEnrollee::devicePropProvisioningStatusHandler(
101                 const std::shared_ptr< DevicePropProvisioningStatus > status) const
102         {
103             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "devicePropProvisioningStatusHandler IN");
104
105             OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "ProvStatus = %d", status->getESResult());
106             m_devicePropProvStatusCb(status);
107
108             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "devicePropProvisioningStatusHandler OUT");
109         }
110
111         void RemoteEnrollee::cloudPropProvisioningStatusHandler (
112                 const std::shared_ptr< CloudPropProvisioningStatus > status) const
113         {
114             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "cloudPropProvisioningStatusHandler IN");
115
116             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d",
117                                                     status->getESResult());
118             m_cloudPropProvStatusCb(status);
119
120             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "cloudPropProvisioningStatusHandler OUT");
121         }
122
123         void RemoteEnrollee::onDiscoveredCallback(const std::shared_ptr<OC::OCResource> resource,
124             std::weak_ptr<RemoteEnrollee> this_ptr)
125         {
126             OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"onDiscoveredCallback()");
127             std::shared_ptr<RemoteEnrollee> Ptr = this_ptr.lock();
128             if(Ptr)
129             {
130                 Ptr->onDeviceDiscovered(resource);
131             }
132         }
133
134         void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
135         {
136             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered IN");
137
138             try
139             {
140                 if(resource)
141                 {
142                     if(!(resource->connectivityType() & CT_ADAPTER_TCP))
143                     {
144                         std::string resourceURI;
145                         std::string hostAddress;
146                         std::string hostDeviceID;
147
148                         // Get the resource URI
149                         resourceURI = resource->uri();
150                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
151                                 "URI of the resource: %s", resourceURI.c_str());
152
153                         // Get the resource host address
154                         hostAddress = resource->host();
155                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
156                                 "Host address of the resource: %s", hostAddress.c_str());
157
158                         hostDeviceID = resource->sid();
159                         OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
160                                 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
161
162                         if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
163                         {
164                             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched resource for cloud provisioning");
165                             m_ocResource = resource;
166                             m_discoveryResponse = true;
167                             m_cond.notify_all();
168                         }
169                     }
170                 }
171             }
172             catch(std::exception& e)
173             {
174                 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
175                         "Exception in foundResource: %s", e.what());
176             }
177
178             OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered OUT");
179         }
180
181         ESResult RemoteEnrollee::discoverResource()
182         {
183             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "discoverResource IN");
184
185             std::string query("");
186             query.append(ES_BASE_RES_URI);
187             query.append("?rt=");
188             query.append(OC_RSRVD_ES_RES_TYPE_PROV);
189
190             OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
191
192             m_discoveryResponse = false;
193
194             onDeviceDiscoveredCb cb = std::bind(&RemoteEnrollee::onDiscoveredCallback,
195                                                 std::placeholders::_1,
196                                                 shared_from_this());
197
198             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT, cb);
199
200             if (result != OCStackResult::OC_STACK_OK)
201             {
202                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
203                         "Failed discoverResource");
204                 return ES_ERROR;
205             }
206
207             std::unique_lock<std::mutex> lck(m_discoverymtx);
208             m_cond.wait_for(lck, std::chrono::seconds(DISCOVERY_TIMEOUT));
209
210             if (!m_discoveryResponse)
211             {
212                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
213                         "Failed discoverResource because timeout");
214                 return ES_ERROR;
215             }
216
217             return ES_OK;
218         }
219
220         void RemoteEnrollee::provisionSecurity(const SecurityProvStatusCb callback)
221         {
222             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionSecurity IN");
223 #ifdef __WITH_DTLS__
224             ESResult res = ESResult::ES_ERROR;
225             if(!callback)
226             {
227                 throw ESInvalidParameterException("Callback is empty");
228             }
229             m_securityProvStatusCb = callback;
230
231             SecurityProvStatusCb securityProvStatusCb = std::bind(
232                     &RemoteEnrollee::securityStatusHandler,
233                     this,
234                     std::placeholders::_1);
235             //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
236             if(!m_enrolleeSecurity.get())
237             {
238                 m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
239             }
240
241             res = m_enrolleeSecurity->provisionOwnership();
242
243             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
244                             std::make_shared< SecProvisioningStatus >(m_enrolleeSecurity->getUUID(), res);
245             m_securityProvStatusCb(securityProvisioningStatus);
246             m_enrolleeSecurity.reset();
247 #else
248             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured built.");
249
250             if(!callback)
251             {
252                 throw ESInvalidParameterException("Callback is empty");
253             }
254             std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
255                      std::make_shared< SecProvisioningStatus >
256                                    ("", ESResult::ES_SEC_OPERATION_IS_NOT_SUPPORTED);
257             callback(securityProvisioningStatus);
258 #endif
259             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionSecurity OUT");
260         }
261
262         void RemoteEnrollee::getStatus(const GetStatusCb callback)
263         {
264             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getStatus IN");
265
266             if(!callback)
267             {
268                 throw ESInvalidParameterException("Callback is empty");
269             }
270
271             if (m_enrolleeResource == nullptr)
272             {
273                 throw ESBadRequestException ("Device not created");
274             }
275
276             m_getStatusCb = callback;
277
278             GetStatusCb getStatusCb = std::bind(
279                 &RemoteEnrollee::getStatusHandler, this, std::placeholders::_1);
280             m_enrolleeResource->registerGetStatusCallback(getStatusCb);
281             m_enrolleeResource->getStatus();
282
283             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getStatus OUT");
284         }
285
286         void RemoteEnrollee::getConfiguration(const GetConfigurationStatusCb callback)
287         {
288             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getConfiguration IN");
289
290             if(!callback)
291             {
292                 throw ESInvalidParameterException("Callback is empty");
293             }
294
295             if (m_enrolleeResource == nullptr)
296             {
297                 throw ESBadRequestException ("Device not created");
298             }
299
300             m_getConfigurationStatusCb = callback;
301
302             GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
303                     &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
304             m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
305             m_enrolleeResource->getConfiguration();
306
307             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "getConfiguration OUT");
308         }
309
310         void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& deviceProp,
311                                                             const DevicePropProvStatusCb callback)
312         {
313             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionDeviceProperties IN");
314
315             if(!callback)
316             {
317                 throw ESInvalidParameterException("Callback is empty");
318             }
319
320             m_devicePropProvStatusCb = callback;
321
322             if (m_enrolleeResource == nullptr)
323             {
324                 throw ESBadRequestException ("Device not created");
325             }
326
327             if(deviceProp.getSsid().empty())
328             {
329                 throw ESBadRequestException ("Invalid Provisiong Data.");
330             }
331
332             DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
333                     &RemoteEnrollee::devicePropProvisioningStatusHandler,
334                     this, std::placeholders::_1);
335
336             m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
337             m_enrolleeResource->provisionProperties(deviceProp);
338
339             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionDeviceProperties OUT");
340         }
341
342         void RemoteEnrollee::initCloudResource()
343         {
344             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "initCloudResource IN");
345
346             ESResult result = ES_ERROR;
347
348             result = discoverResource();
349
350             if (result == ES_ERROR)
351             {
352                 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
353                                     "Failed to create resource object using discoverResource");
354                 throw ESBadRequestException ("Resource object not created");
355             }
356
357             else
358             {
359                 if(m_ocResource != nullptr)
360                 {
361                     m_cloudResource = std::make_shared<CloudResource>(m_ocResource);
362                 }
363                 else
364                 {
365                     throw ESBadGetException ("Resource handle is invalid");
366                 }
367             }
368
369             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "initCloudResource OUT");
370         }
371
372         void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp,
373                                                             const CloudPropProvStatusCb callback)
374         {
375             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionCloudProperties IN");
376
377             if(!callback)
378             {
379                 throw ESInvalidParameterException("Callback is empty");
380             }
381
382             m_cloudPropProvStatusCb = callback;
383
384             if(cloudProp.getAuthCode().empty() ||
385                 cloudProp.getAuthProvider().empty() ||
386                 cloudProp.getCiServer().empty())
387             {
388                 throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
389             }
390
391             try
392             {
393                 initCloudResource();
394             }
395
396             catch (const std::exception& e)
397             {
398                 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
399                     "Exception caught in provisionCloudProperties = %s", e.what());
400
401                 std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
402                         CloudPropProvisioningStatus >(ESResult::ES_ENROLLEE_DISCOVERY_FAILURE);
403                 m_cloudPropProvStatusCb(provStatus);
404                 return;
405             }
406 #if defined(__WITH_DTLS__) && defined(__WITH_TLS__)
407             if(!(cloudProp.getCloudID().empty() && cloudProp.getCredID() <= 0))
408             {
409                 ESResult res = ESResult::ES_ERROR;
410                 if(!m_enrolleeSecurity.get())
411                 {
412                     m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
413                 }
414
415
416                 res = m_enrolleeSecurity->provisionSecurityForCloudServer(cloudProp.getCloudID(),
417                                                                           cloudProp.getCredID());
418                 m_enrolleeSecurity.reset();
419                 if(res != ESResult::ES_OK)
420                 {
421                     m_cloudResource = nullptr;
422                     std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
423                             CloudPropProvisioningStatus >(res);
424                     m_cloudPropProvStatusCb(provStatus);
425                     return;
426                 }
427             }
428             else
429             {
430                 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "ACL and Cert. provisioning are skipped.");
431             }
432 #endif //defined(__WITH_DTLS__) && defined(__WITH_TLS__)
433
434             if (m_cloudResource == nullptr)
435             {
436                 throw ESBadRequestException ("Cloud Resource not created");
437             }
438
439             CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
440                     &RemoteEnrollee::cloudPropProvisioningStatusHandler,
441                                     this, std::placeholders::_1);
442
443             m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
444             m_cloudResource->provisionProperties(cloudProp);
445
446             OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "provisionCloudProperties OUT");
447         }
448     }
449 }