1 //******************************************************************
\r
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
\r
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\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
11 // http://www.apache.org/licenses/LICENSE-2.0
\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
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
21 #include <functional>
\r
24 #include "RemoteEnrolleeResource.h"
\r
26 #include "OCPlatform.h"
\r
27 #include "ESException.h"
\r
28 #include "OCResource.h"
\r
35 #define ES_REMOTE_ENROLLEE_RES_TAG "ES_REMOTE_ENROLLEE_RES"
\r
36 #define DISCOVERY_TIMEOUT 5
\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
42 RemoteEnrolleeResource::RemoteEnrolleeResource(EnrolleeNWProvInfo enrolleeNWProvInfo)
\r
44 m_enrolleeNWProvInfo = enrolleeNWProvInfo;
\r
45 m_discoveryResponse = false;
\r
48 void RemoteEnrolleeResource::checkProvInformationCb(const HeaderOptions& /*headerOptions*/,
\r
49 const OCRepresentation& rep, const int eCode)
\r
51 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
\r
52 rep.getUri().c_str(),
\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
66 std::string tnn = "";
\r
67 std::string cd = "";
\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
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
79 //Provisioning status check
\r
80 if (ps == ES_PS_PROVISIONING_COMPLETED)
\r
82 if (tnn != std::string(m_enrolleeNWProvInfo.netAddressInfo.WIFI.ssid))
\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
94 if (cd != std::string(m_enrolleeNWProvInfo.netAddressInfo.WIFI.pwd))
\r
96 OC_LOG_V (ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
\r
97 "checkProvInformationCb : Network PWD is not the same as the "
\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
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
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
124 void RemoteEnrolleeResource::getProvStatusResponse(const HeaderOptions& /*headerOptions*/,
\r
125 const OCRepresentation& rep, const int eCode)
\r
127 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : %s, eCode = %d",
\r
128 rep.getUri().c_str(),
\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
142 std::string tnn = "";
\r
143 std::string cd = "";
\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
149 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ps - %d",
\r
151 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : tnn - %s",
\r
153 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : cd - %s",
\r
156 if (ps == ES_PS_NEED_PROVISIONING) //Indicates the need for provisioning
\r
158 OCRepresentation provisioningRepresentation;
\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
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
170 m_ocResource->put(provisioningRepresentation, QueryParamsMap(),
\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
178 else if (ps == ES_PS_PROVISIONING_COMPLETED) //Indicates that provisioning is completed
\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
188 void RemoteEnrolleeResource::registerProvStatusCallback(ProvStatusCb provStatusCb)
\r
190 m_provStatusCb = provStatusCb;
\r
193 ESResult RemoteEnrolleeResource::ESDiscoveryTimeout(unsigned short waittime)
\r
195 struct timespec startTime;
\r
196 startTime.tv_sec=0;
\r
197 startTime.tv_sec=0;
\r
198 struct timespec currTime;
\r
200 currTime.tv_nsec=0;
\r
202 ESResult res = ES_OK;
\r
203 #ifdef _POSIX_MONOTONIC_CLOCK
\r
204 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
\r
206 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
\r
209 if (0 != clock_res)
\r
214 while (ES_OK == res || m_discoveryResponse == false)
\r
216 #ifdef _POSIX_MONOTONIC_CLOCK
\r
217 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
\r
219 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
\r
222 if (0 != clock_res)
\r
226 long elapsed = (currTime.tv_sec - startTime.tv_sec);
\r
227 if (elapsed > waittime)
\r
231 if (m_discoveryResponse)
\r
239 void RemoteEnrolleeResource::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
\r
241 OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "onDeviceDiscovered");
\r
243 std::string resourceURI;
\r
244 std::string hostAddress;
\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
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
259 std::size_t foundIP =
\r
261 std::string(m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress));
\r
263 if(resourceURI == ES_PROV_RES_URI && foundIP!=std::string::npos)
\r
265 m_ocResource = resource;
\r
266 m_discoveryResponse = true;
\r
268 OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
\r
269 "Found the device with the resource");
\r
275 OC_LOG (ERROR, ES_REMOTE_ENROLLEE_RES_TAG, "NOT the intended resource.");
\r
280 OC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Resource is invalid");
\r
284 catch(std::exception& e)
\r
286 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
\r
287 "Exception in foundResource: %s", e.what());
\r
292 ESResult RemoteEnrolleeResource::constructResourceObject()
\r
294 if (m_ocResource != nullptr)
\r
296 throw ESBadRequestException("Remote resource is already created");
\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
305 std::vector< std::string > interface =
\r
306 { DEFAULT_INTERFACE};
\r
307 std::vector< std::string > resTypes =
\r
308 { ES_PROV_RES_TYPE};
\r
310 OC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
\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
322 if(m_enrolleeNWProvInfo.needSecuredEasysetup)
\r
324 host.append("coaps://");
\r
328 host.append("coap://");
\r
331 if(m_enrolleeNWProvInfo.connType == CT_ADAPTER_IP)
\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
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
341 host.append(":55555");
\r
344 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "HOST = %s", host.c_str());
\r
346 m_ocResource = OC::OCPlatform::constructResourceObject(host,
\r
348 m_enrolleeNWProvInfo.connType,
\r
352 OC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
\r
353 "created OCResource : %s", m_ocResource->uri().c_str());
\r
357 catch (OCException & e)
\r
359 OC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
\r
360 "Exception for constructResourceObject : %s", e.reason().c_str());
\r
364 std::string host("");
\r
365 std::string query("");
\r
367 if (m_enrolleeNWProvInfo.needSecuredEasysetup)
\r
369 host.append("coaps://");
\r
373 host.append("coap://");
\r
376 if (m_enrolleeNWProvInfo.connType == CT_ADAPTER_IP)
\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
382 host.append(m_enrolleeNWProvInfo.netAddressInfo.WIFI.ipAddress);
\r
385 query.append(ES_BASE_RES_URI);
\r
386 query.append("?rt=");
\r
387 query.append(ES_PROV_RES_TYPE);
\r
389 OC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
\r
391 OC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "host = %s",
\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
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
404 if (result != OCStackResult::OC_STACK_OK)
\r
406 OC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
\r
407 "Failed to create device using constructResourceObject");
\r
412 ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
\r
414 if (!m_discoveryResponse)
\r
416 OC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
\r
417 "Failed to create device using constructResourceObject");
\r
425 void RemoteEnrolleeResource::provisionEnrollee()
\r
428 if (m_ocResource == nullptr)
\r
430 throw ESBadRequestException("Resource is not initialized");
\r
433 OC::QueryParamsMap query;
\r
434 OC::OCRepresentation rep;
\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
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
447 OCStackResult result = getProvisioingStatus();
\r
449 if (result != OCStackResult::OC_STACK_OK)
\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
458 void RemoteEnrolleeResource::unprovisionEnrollee()
\r
460 if (m_ocResource == nullptr)
\r
462 throw ESBadRequestException("Resource is not initialized");
\r
465 OCRepresentation provisioningRepresentation;
\r
467 provisioningRepresentation.setValue(OC_RSRVD_ES_TNN, "");
\r
468 provisioningRepresentation.setValue(OC_RSRVD_ES_CD, "");
\r
470 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
\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