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