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