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