79c63f5f4e4ab9393343fbba1aa7d447553b5cce
[platform/upstream/iotivity.git] / service / easy-setup / mediator / richsdk / src / RemoteEnrolleeResource.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 <functional>
22 #include <time.h>
23
24 #include "RemoteEnrolleeResource.h"
25
26 #include "OCPlatform.h"
27 #include "ESException.h"
28 #include "OCResource.h"
29 #include "logger.h"
30
31 namespace OIC
32 {
33     namespace Service
34     {
35         #define ES_REMOTE_ENROLLEE_RES_TAG "ES_REMOTE_ENROLLEE_RES"
36         #define DISCOVERY_TIMEOUT 5
37
38         static const char ES_BASE_RES_URI[] = "/oic/res";
39         static const char ES_PROV_RES_URI[] = "/oic/prov";
40         static const char ES_PROV_RES_TYPE[] = "oic.r.prov";
41
42         RemoteEnrolleeResource::RemoteEnrolleeResource(ProvConfig provConfig,
43                                                   WiFiOnboadingConnection onboardingconn)
44         {
45             m_ProvConfig = provConfig;
46             m_wifiOnboardingconn = onboardingconn;
47             m_discoveryResponse = false;
48         }
49
50         void RemoteEnrolleeResource::checkProvInformationCb(const HeaderOptions& /*headerOptions*/,
51                 const OCRepresentation& rep, const int eCode)
52         {
53             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
54                     rep.getUri().c_str(),
55                     eCode);
56
57             if (eCode != 0)
58             {
59                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
60                         "checkProvInformationCb : Provisioning is failed ");
61                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
62                         ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
63                 m_provStatusCb(provStatus);
64                 return;
65             }
66
67             int ps = -1;
68             std::string tnn = "";
69             std::string cd = "";
70
71             rep.getValue(OC_RSRVD_ES_PS, ps);
72             rep.getValue(OC_RSRVD_ES_TNN, tnn);
73             rep.getValue(OC_RSRVD_ES_CD, cd);
74
75             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : ps - %d", ps);
76             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
77                     "checkProvInformationCb : tnn - %s", tnn.c_str());
78             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
79                     "checkProvInformationCb : cd - %s", cd.c_str());
80
81             //Provisioning status check
82             if (ps == ES_PS_PROVISIONING_COMPLETED)
83             {
84                 if (tnn != std::string(m_ProvConfig.provData.WIFI.ssid))
85                 {
86                     OC_LOG_V (ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
87                             "checkProvInformationCb : Network SSID is not the same as the "
88                             "SSID provisioned");
89                     std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
90                             ProvisioningStatus >(ESResult::ES_ERROR,
91                             ESState::ES_PROVISIONING_ERROR);
92                     m_provStatusCb(provStatus);
93                     return;
94                 }
95
96                 if (cd != std::string(m_ProvConfig.provData.WIFI.pwd))
97                 {
98                     OC_LOG_V (ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
99                             "checkProvInformationCb : Network PWD is not the same as the "
100                             "PWD provisioned");
101                     std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
102                             ProvisioningStatus >(ESResult::ES_ERROR,
103                             ESState::ES_PROVISIONING_ERROR);
104                     m_provStatusCb(provStatus);
105                     return;
106                 }
107
108                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
109                         "checkProvInformationCb : Provisioning is success ");
110                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
111                         ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONING_SUCCESS);
112                 m_provStatusCb(provStatus);
113                 return;
114             }
115             else
116             {
117                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
118                         "checkProvInformationCb : Provisioning is failed ");
119                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
120                         ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
121                 m_provStatusCb(provStatus);
122                 return;
123             }
124         }
125
126         void RemoteEnrolleeResource::getProvStatusResponse(const HeaderOptions& /*headerOptions*/,
127                 const OCRepresentation& rep, const int eCode)
128         {
129             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : %s, eCode = %d",
130                     rep.getUri().c_str(),
131                     eCode);
132
133             if (eCode != 0)
134             {
135                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
136                         "getProvStatusResponse : Provisioning is failed ");
137                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
138                         ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
139                 m_provStatusCb(provStatus);
140                 return;
141             }
142
143             int ps = -1;
144             std::string tnn = "";
145             std::string cd = "";
146
147             rep.getValue(OC_RSRVD_ES_PS, ps);
148             rep.getValue(OC_RSRVD_ES_TNN, tnn);
149             rep.getValue(OC_RSRVD_ES_CD, cd);
150
151             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ps - %d",
152                     ps);
153             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : tnn - %s",
154                     tnn.c_str());
155             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : cd - %s",
156                     cd.c_str());
157
158             if (ps == ES_PS_NEED_PROVISIONING) //Indicates the need for provisioning
159             {
160                 OCRepresentation provisioningRepresentation;
161
162                 provisioningRepresentation.setValue(OC_RSRVD_ES_TNN,
163                 std::string(m_ProvConfig.provData.WIFI.ssid));
164                 provisioningRepresentation.setValue(OC_RSRVD_ES_CD,
165                 std::string(m_ProvConfig.provData.WIFI.pwd));
166
167                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ssid - %s",
168                         m_ProvConfig.provData.WIFI.ssid);
169                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : pwd - %s",
170                         m_ProvConfig.provData.WIFI.pwd);
171
172                 m_ocResource->put(provisioningRepresentation, QueryParamsMap(),
173                         std::function<
174                                 void(const HeaderOptions& headerOptions,
175                                         const OCRepresentation& rep, const int eCode) >(
176                         std::bind(&RemoteEnrolleeResource::checkProvInformationCb, this,
177                         std::placeholders::_1, std::placeholders::_2,
178                         std::placeholders::_3)));
179             }
180             else if (ps == ES_PS_PROVISIONING_COMPLETED) //Indicates that provisioning is completed
181             {
182                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
183                         "getProvStatusResponse : Provisioning is successful");
184                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
185                         ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONED_ALREADY);
186                 m_provStatusCb(provStatus);
187             }
188         }
189
190         void RemoteEnrolleeResource::registerProvStatusCallback(ProvStatusCb provStatusCb)
191         {
192             m_provStatusCb = provStatusCb;
193         }
194
195         ESResult RemoteEnrolleeResource::ESDiscoveryTimeout(unsigned short waittime)
196         {
197             struct timespec startTime;
198             startTime.tv_sec=0;
199             startTime.tv_sec=0;
200             struct timespec currTime;
201             currTime.tv_sec=0;
202             currTime.tv_nsec=0;
203
204             ESResult res = ES_OK;
205             #ifdef _POSIX_MONOTONIC_CLOCK
206                 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
207             #else
208                 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
209             #endif
210
211             if (0 != clock_res)
212             {
213                 return ES_ERROR;
214             }
215
216             while (ES_OK == res || m_discoveryResponse == false)
217             {
218                 #ifdef _POSIX_MONOTONIC_CLOCK
219                         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
220                 #else
221                         clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
222                 #endif
223
224                 if (0 != clock_res)
225                 {
226                     return ES_ERROR;
227                 }
228                 long elapsed = (currTime.tv_sec - startTime.tv_sec);
229                 if (elapsed > waittime)
230                 {
231                     return ES_OK;
232                 }
233                 if (m_discoveryResponse)
234                 {
235                     res = ES_OK;
236                 }
237              }
238              return res;
239         }
240
241         void RemoteEnrolleeResource::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
242         {
243             OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "onDeviceDiscovered");
244
245             std::string resourceURI;
246             std::string hostAddress;
247             try
248             {
249                 if(resource)
250                 {
251                     // Get the resource URI
252                     resourceURI = resource->uri();
253                     OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
254                             "URI of the resource: %s", resourceURI.c_str());
255
256                     // Get the resource host address
257                     hostAddress = resource->host();
258                     OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
259                             "Host address of the resource: %s", hostAddress.c_str());
260
261                     std::size_t foundIP =
262                         hostAddress.find(
263                                 std::string(m_wifiOnboardingconn.ipAddress));
264
265                     if(resourceURI == ES_PROV_RES_URI && foundIP!=std::string::npos)
266                     {
267                         m_ocResource = resource;
268                         m_discoveryResponse = true;
269
270                         OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
271                                 "Found the device with the resource");
272
273                         return;
274                     }
275                     else
276                     {
277                         OC_LOG (ERROR, ES_REMOTE_ENROLLEE_RES_TAG, "NOT the intended resource.");
278                     }
279                 }
280                 else
281                 {
282                     OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Resource is invalid");
283                 }
284
285             }
286             catch(std::exception& e)
287             {
288                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
289                         "Exception in foundResource: %s", e.what());
290             }
291         }
292
293
294         ESResult RemoteEnrolleeResource::constructResourceObject()
295         {
296             if (m_ocResource != nullptr)
297             {
298                 throw ESBadRequestException("Remote resource is already created");
299             }
300
301 #ifdef REMOTE_ARDUINO_ENROLEE
302             //This process will create OCResource with port 55555 which is specific
303             // to Arduino WiFi enrollee
304             try
305             {
306
307                 std::vector< std::string > interface =
308                 {   DEFAULT_INTERFACE};
309                 std::vector< std::string > resTypes =
310                 {   ES_PROV_RES_TYPE};
311
312                 OC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
313
314                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_host = %s",
315                         m_wifiOnboardingconn.ipAddress);
316                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "ES_PROV_RES_URI = %s", ES_PROV_RES_URI);
317                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
318                         m_ProvConfig.connType);
319                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "resTypes = %s",
320                         resTypes.at(0).c_str());
321                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "interface = %s", interface.at(0).c_str());
322
323                 std::string host;
324                 if(m_wifiOnboardingconn.isSecured)
325                 {
326                     host.append("coaps://");
327                 }
328                 else
329                 {
330                     host.append("coap://");
331                 }
332
333                 if(m_ProvConfig.connType == CT_ADAPTER_IP)
334                 {
335                     // TODO : RemoteEnrollee is current handling easysetup on IP transport.
336                     // WiFiRemoteEnrollee need to extend RemoteEnrollee for providing IP specific
337                     // Enrollee easysetup.
338
339                     host.append(m_wifiOnboardingconn.ipAddress);
340                     //TODO : If the target Enrollee is not a Arduino Wi-Fi device,
341                     // then the port number will be found during resource discovery instead of
342                     // using 55555
343                     host.append(":55555");
344                 }
345
346                 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "HOST = %s", host.c_str());
347
348                 m_ocResource = OC::OCPlatform::constructResourceObject(host,
349                         ES_PROV_RES_URI,
350                         m_ProvConfig.connType,
351                         true,
352                         resTypes,
353                         interface);
354                 OC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
355                         "created OCResource : %s", m_ocResource->uri().c_str());
356
357                 return ES_OK;
358             }
359             catch (OCException & e)
360             {
361                 OC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
362                         "Exception for constructResourceObject : %s", e.reason().c_str());
363             }
364
365 #else
366             std::string host("");
367             std::string query("");
368
369             if (m_wifiOnboardingconn.isSecured)
370             {
371                 host.append("coaps://");
372             }
373             else
374             {
375                 host.append("coap://");
376             }
377
378             if (m_ProvConfig.connType == CT_ADAPTER_IP)
379             {
380                 // TODO : RemoteEnrollee is current handling easysetup on IP transport.
381                 // WiFiRemoteEnrollee need to extend RemoteEnrollee for providing IP specific
382                 // Enrollee easysetup.
383
384                 host.append(m_wifiOnboardingconn.ipAddress);
385             }
386
387             query.append(ES_BASE_RES_URI);
388             query.append("?rt=");
389             query.append(ES_PROV_RES_TYPE);
390
391             OC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
392
393             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "host = %s",
394                     host.c_str());
395             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "query = %s", query.c_str());
396             OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
397                     m_ProvConfig.connType);
398
399             m_discoveryResponse = false;
400             std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
401                     std::bind(&RemoteEnrolleeResource::onDeviceDiscovered, this,
402                                                     std::placeholders::_1);
403             OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
404                     onDeviceDiscoveredCb);
405
406             if (result != OCStackResult::OC_STACK_OK)
407             {
408                 OC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
409                         "Failed to create device using constructResourceObject");
410                 return ES_ERROR;
411             }
412
413
414             ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
415
416             if (!m_discoveryResponse)
417             {
418                 OC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
419                         "Failed to create device using constructResourceObject");
420                 return ES_ERROR;
421             }
422
423             return ES_OK;
424 #endif
425         }
426
427         void RemoteEnrolleeResource::provisionEnrollee()
428
429         {
430             if (m_ocResource == nullptr)
431             {
432                 throw ESBadRequestException("Resource is not initialized");
433             }
434
435             OC::QueryParamsMap query;
436             OC::OCRepresentation rep;
437
438             std::function< OCStackResult(void) > getProvisioingStatus = [&]
439             {   return m_ocResource->get(m_ocResource->getResourceTypes().at(0),
440                         m_ocResource->getResourceInterfaces().at(0), query,
441                         std::function<
442                         void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
443                                 const int eCode) >(
444                                 std::bind(&RemoteEnrolleeResource::getProvStatusResponse, this,
445                                         std::placeholders::_1, std::placeholders::_2,
446                                         std::placeholders::_3)));
447             };
448
449             OCStackResult result = getProvisioingStatus();
450
451             if (result != OCStackResult::OC_STACK_OK)
452             {
453                 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
454                         ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
455                 m_provStatusCb(provStatus);
456                 return;
457             }
458         }
459
460         void RemoteEnrolleeResource::unprovisionEnrollee()
461         {
462             if (m_ocResource == nullptr)
463             {
464                 throw ESBadRequestException("Resource is not initialized");
465             }
466
467             OCRepresentation provisioningRepresentation;
468
469             provisioningRepresentation.setValue(OC_RSRVD_ES_TNN, "");
470             provisioningRepresentation.setValue(OC_RSRVD_ES_CD, "");
471
472             m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
473                     std::function<
474                             void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
475                                     const int eCode) >(
476                     std::bind(&RemoteEnrolleeResource::checkProvInformationCb, this,
477                     std::placeholders::_1, std::placeholders::_2,
478                     std::placeholders::_3)));
479         }
480     }
481 }