1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
24 #include "RemoteEnrolleeResource.h"
26 #include "OCPlatform.h"
27 #include "ESException.h"
28 #include "OCResource.h"
35 #define ES_REMOTE_ENROLLEE_RES_TAG "ES_REMOTE_ENROLLEE_RES"
36 #define DISCOVERY_TIMEOUT 5
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";
42 RemoteEnrolleeResource::RemoteEnrolleeResource(const ProvConfig &provConfig,
43 const WiFiOnboadingConnection &onboardingconn)
45 m_ProvConfig = provConfig;
46 m_wifiOnboardingconn = onboardingconn;
47 m_discoveryResponse = false;
50 void RemoteEnrolleeResource::triggerNetworkConnectionCb(
51 const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep,
54 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
60 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
61 "triggerNetworkConnectionCb : Trigger action failed ");
62 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
63 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
64 m_provStatusCb(provStatus);
69 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
70 "triggerNetworkConnectionCb : Provisioning is success ");
71 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
72 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONING_SUCCESS);
73 m_provStatusCb(provStatus);
78 void RemoteEnrolleeResource::triggerNetworkConnection()
80 if (m_ocResource == nullptr)
82 throw ESBadRequestException("Resource is not initialized");
85 OCRepresentation provisioningRepresentation;
87 provisioningRepresentation.setValue(OC_RSRVD_ES_TR, 1);
89 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
91 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
93 std::bind(&RemoteEnrolleeResource::triggerNetworkConnectionCb, this,
94 std::placeholders::_1, std::placeholders::_2,
95 std::placeholders::_3)));
98 void RemoteEnrolleeResource::checkProvInformationCb(const HeaderOptions& /*headerOptions*/,
99 const OCRepresentation& rep, const int eCode)
101 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
102 rep.getUri().c_str(),
107 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
108 "checkProvInformationCb : Provisioning is failed ");
109 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
110 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
111 m_provStatusCb(provStatus);
117 rep.getValue(OC_RSRVD_ES_PS, ps);
119 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : ps - %d", ps);
121 //Provisioning status check
122 if (ps == ES_PS_PROVISIONING_COMPLETED)
124 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
125 "checkProvInformationCb : Provisioning is success. "
126 "Now trigger network connection ");
128 #ifdef REMOTE_ARDUINO_ENROLEE
129 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
130 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONING_SUCCESS);
131 m_provStatusCb(provStatus);
134 triggerNetworkConnection();
139 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
140 "checkProvInformationCb : Provisioning is failed ");
141 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
142 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
143 m_provStatusCb(provStatus);
148 void RemoteEnrolleeResource::getProvStatusResponse(const HeaderOptions& /*headerOptions*/,
149 const OCRepresentation& rep, const int eCode)
151 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : %s, eCode = %d",
152 rep.getUri().c_str(),
157 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
158 "getProvStatusResponse : Provisioning is failed ");
159 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
160 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
161 m_provStatusCb(provStatus);
167 rep.getValue(OC_RSRVD_ES_PS, ps);
169 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ps - %d",
172 if (ps == ES_PS_NEED_PROVISIONING) //Indicates the need for provisioning
174 OCRepresentation provisioningRepresentation;
176 provisioningRepresentation.setValue(OC_RSRVD_ES_TNN,
177 std::string(m_ProvConfig.provData.WIFI.ssid));
178 provisioningRepresentation.setValue(OC_RSRVD_ES_CD,
179 std::string(m_ProvConfig.provData.WIFI.pwd));
181 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ssid - %s",
182 m_ProvConfig.provData.WIFI.ssid);
183 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : pwd - %s",
184 m_ProvConfig.provData.WIFI.pwd);
186 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
188 void(const HeaderOptions& headerOptions,
189 const OCRepresentation& rep, const int eCode) >(
190 std::bind(&RemoteEnrolleeResource::checkProvInformationCb, this,
191 std::placeholders::_1, std::placeholders::_2,
192 std::placeholders::_3)));
194 else if (ps == ES_PS_PROVISIONING_COMPLETED) //Indicates that provisioning is completed
196 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
197 "getProvStatusResponse : Provisioning is successful");
198 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
199 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONED_ALREADY);
200 m_provStatusCb(provStatus);
204 void RemoteEnrolleeResource::registerProvStatusCallback(ProvStatusCb provStatusCb)
206 m_provStatusCb = provStatusCb;
209 ESResult RemoteEnrolleeResource::ESDiscoveryTimeout(unsigned short waittime)
211 struct timespec startTime;
214 struct timespec currTime;
218 ESResult res = ES_OK;
219 #ifdef _POSIX_MONOTONIC_CLOCK
220 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
222 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
230 while (ES_OK == res || m_discoveryResponse == false)
232 #ifdef _POSIX_MONOTONIC_CLOCK
233 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
235 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
242 long elapsed = (currTime.tv_sec - startTime.tv_sec);
243 if (elapsed > waittime)
247 if (m_discoveryResponse)
255 void RemoteEnrolleeResource::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
257 OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "onDeviceDiscovered");
259 std::string resourceURI;
260 std::string hostAddress;
265 // Get the resource URI
266 resourceURI = resource->uri();
267 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
268 "URI of the resource: %s", resourceURI.c_str());
270 // Get the resource host address
271 hostAddress = resource->host();
272 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
273 "Host address of the resource: %s", hostAddress.c_str());
276 * Easysetup is always performed with a single Enrollee device and
277 * in a private network (SoftAP or BLE), so the assumption is that
278 * only the intended device will respond for the discovery.
279 * With the above assumption the below two statements are written.
281 m_ocResource = resource;
282 m_discoveryResponse = true;
286 OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Resource is invalid");
290 catch(std::exception& e)
292 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
293 "Exception in foundResource: %s", e.what());
298 ESResult RemoteEnrolleeResource::constructResourceObject()
300 if (m_ocResource != nullptr)
302 throw ESBadRequestException("Remote resource is already created");
305 #ifdef REMOTE_ARDUINO_ENROLEE
306 //This process will create OCResource with port 55555 which is specific
307 // to Arduino WiFi enrollee
311 std::vector< std::string > interface =
312 { DEFAULT_INTERFACE};
313 std::vector< std::string > resTypes =
316 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
318 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_host = %s",
319 m_wifiOnboardingconn.ipAddress);
320 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "ES_PROV_RES_URI = %s", ES_PROV_RES_URI);
321 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
322 m_ProvConfig.connType);
323 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "resTypes = %s",
324 resTypes.at(0).c_str());
325 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "interface = %s", interface.at(0).c_str());
328 if(m_wifiOnboardingconn.isSecured)
330 host.append("coaps://");
334 host.append("coap://");
337 if(m_ProvConfig.connType == CT_ADAPTER_IP)
339 // TODO : RemoteEnrollee is current handling easysetup on IP transport.
340 // WiFiRemoteEnrollee need to extend RemoteEnrollee for providing IP specific
341 // Enrollee easysetup.
343 host.append(m_wifiOnboardingconn.ipAddress);
344 //TODO : If the target Enrollee is not a Arduino Wi-Fi device,
345 // then the port number will be found during resource discovery instead of
347 host.append(":55555");
350 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "HOST = %s", host.c_str());
352 m_ocResource = OC::OCPlatform::constructResourceObject(host,
354 m_ProvConfig.connType,
358 OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
359 "created OCResource : %s", m_ocResource->uri().c_str());
363 catch (OCException & e)
365 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
366 "Exception for constructResourceObject : %s", e.reason().c_str());
370 std::string host("");
371 std::string query("");
373 if (m_wifiOnboardingconn.isSecured)
375 host.append("coaps://");
379 host.append("coap://");
382 if (m_ProvConfig.connType == CT_ADAPTER_IP)
384 // TODO : RemoteEnrollee is current handling easysetup on IP transport.
385 // WiFiRemoteEnrollee need to extend RemoteEnrollee for providing IP specific
386 // Enrollee easysetup.
388 host.append(m_wifiOnboardingconn.ipAddress);
391 query.append(ES_BASE_RES_URI);
392 query.append("?rt=");
393 query.append(ES_PROV_RES_TYPE);
395 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
397 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "host = %s",
399 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "query = %s", query.c_str());
400 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
401 m_ProvConfig.connType);
403 m_discoveryResponse = false;
404 std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
405 std::bind(&RemoteEnrolleeResource::onDeviceDiscovered, this,
406 std::placeholders::_1);
407 OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
408 onDeviceDiscoveredCb);
410 if (result != OCStackResult::OC_STACK_OK)
412 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
413 "Failed to create device using constructResourceObject");
418 ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
420 if (foundResponse ==ES_ERROR || !m_discoveryResponse)
422 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
423 "Failed to create device using constructResourceObject");
431 void RemoteEnrolleeResource::provisionEnrollee()
434 if (m_ocResource == nullptr)
436 throw ESBadRequestException("Resource is not initialized");
439 OC::QueryParamsMap query;
440 OC::OCRepresentation rep;
442 std::function< OCStackResult(void) > getProvisioingStatus = [&]
443 { return m_ocResource->get(m_ocResource->getResourceTypes().at(0),
444 m_ocResource->getResourceInterfaces().at(0), query,
446 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
448 std::bind(&RemoteEnrolleeResource::getProvStatusResponse, this,
449 std::placeholders::_1, std::placeholders::_2,
450 std::placeholders::_3)));
453 OCStackResult result = getProvisioingStatus();
455 if (result != OCStackResult::OC_STACK_OK)
457 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
458 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
459 m_provStatusCb(provStatus);
464 void RemoteEnrolleeResource::unprovisionEnrollee()
466 if (m_ocResource == nullptr)
468 throw ESBadRequestException("Resource is not initialized");
471 OCRepresentation provisioningRepresentation;
473 provisioningRepresentation.setValue(OC_RSRVD_ES_TNN, "");
474 provisioningRepresentation.setValue(OC_RSRVD_ES_CD, "");
476 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
478 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
480 std::bind(&RemoteEnrolleeResource::checkProvInformationCb, this,
481 std::placeholders::_1, std::placeholders::_2,
482 std::placeholders::_3)));