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