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 "EnrolleeResource.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 EnrolleeResource::EnrolleeResource(const WiFiOnboadingConnection &onboardingconn)
44 m_wifiOnboardingconn = onboardingconn;
45 m_discoveryResponse = false;
48 EnrolleeResource::EnrolleeResource(const ProvConfig &provConfig,
49 const WiFiOnboadingConnection &onboardingconn)
51 m_ProvConfig = provConfig;
52 m_wifiOnboardingconn = onboardingconn;
53 m_discoveryResponse = false;
56 void EnrolleeResource::triggerNetworkConnectionCb(
57 const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep,
60 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
66 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
67 "triggerNetworkConnectionCb : Trigger action failed ");
68 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
69 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
70 m_dataProvStatusCb(provStatus);
75 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
76 "triggerNetworkConnectionCb : Provisioning is success ");
77 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
78 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONING_SUCCESS);
79 m_dataProvStatusCb(provStatus);
84 void EnrolleeResource::triggerNetworkConnection()
86 if (m_ocResource == nullptr)
88 throw ESBadRequestException("Resource is not initialized");
91 OCRepresentation provisioningRepresentation;
93 provisioningRepresentation.setValue(OC_RSRVD_ES_TRIGGER, 1);
95 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
97 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
99 std::bind(&EnrolleeResource::triggerNetworkConnectionCb, this,
100 std::placeholders::_1, std::placeholders::_2,
101 std::placeholders::_3)));
104 void EnrolleeResource::checkProvInformationCb(const HeaderOptions& /*headerOptions*/,
105 const OCRepresentation& rep, const int eCode)
107 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : %s, eCode = %d",
108 rep.getUri().c_str(),
113 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
114 "checkProvInformationCb : Provisioning is failed ");
115 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
116 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
117 m_dataProvStatusCb(provStatus);
123 rep.getValue(OC_RSRVD_ES_PROVSTATUS, ps);
125 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "checkProvInformationCb : ps - %d", ps);
127 //Provisioning status check
128 if (ps == ES_PS_PROVISIONING_COMPLETED)
130 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
131 "checkProvInformationCb : Provisioning is success. "
132 "Now trigger network connection ");
134 #ifdef REMOTE_ARDUINO_ENROLEE
135 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
136 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONING_SUCCESS);
137 m_dataProvStatusCb(provStatus);
140 triggerNetworkConnection();
145 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
146 "checkProvInformationCb : Provisioning is failed ");
147 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
148 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
149 m_dataProvStatusCb(provStatus);
154 void EnrolleeResource::getCapabilityResponse(const HeaderOptions& /*headerOptions*/,
155 const OCRepresentation& rep, const int eCode)
157 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getCapabilityResponse : %s, eCode = %d",
158 rep.getUri().c_str(), eCode);
162 ESResult result = ESResult::ES_ERROR;
164 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,"getCapabilityResponse : getCapabilityResponse is failed ");
166 if (eCode == OCStackResult::OC_STACK_UNAUTHORIZED_REQ)
168 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
169 "Mediator is unauthorized from Enrollee.");
170 result = ESResult::ES_UNAUTHORIZED;
173 CapabilityData capabilityData;
174 std::shared_ptr< RequestCapabilityStatus > requestCapabilityStatus = std::make_shared<
175 RequestCapabilityStatus >(result, capabilityData);
176 m_requestCapabilityStatusCb(requestCapabilityStatus);
181 CapabilityData capabilityData = CapabilityData();
182 std::shared_ptr< RequestCapabilityStatus > requestCapabilityStatus = std::make_shared<
183 RequestCapabilityStatus >(ESResult::ES_OK, capabilityData);
184 m_requestCapabilityStatusCb(requestCapabilityStatus);
187 void EnrolleeResource::getProvStatusResponse(const HeaderOptions& /*headerOptions*/,
188 const OCRepresentation& rep, const int eCode)
190 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : %s, eCode = %d",
191 rep.getUri().c_str(),
196 ESResult result = ESResult::ES_ERROR;
198 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,"getProvStatusResponse : Provisioning is failed ");
200 if (eCode == OCStackResult::OC_STACK_UNAUTHORIZED_REQ)
202 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
203 "Mediator is unauthorized from Enrollee.");
204 result = ESResult::ES_UNAUTHORIZED;
206 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
207 ProvisioningStatus >(result, ESState::ES_PROVISIONING_ERROR);
208 m_dataProvStatusCb(provStatus);
215 rep.getValue(OC_RSRVD_ES_PROVSTATUS, ps);
217 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ps - %d",
220 if (ps == ES_PS_NEED_PROVISIONING) //Indicates the need for provisioning
222 OCRepresentation provisioningRepresentation;
224 provisioningRepresentation.setValue(OC_RSRVD_ES_SSID,
225 std::string(m_ProvConfig.provData.WIFI.ssid));
226 provisioningRepresentation.setValue(OC_RSRVD_ES_CRED,
227 std::string(m_ProvConfig.provData.WIFI.pwd));
228 provisioningRepresentation.setValue(OC_RSRVD_ES_AUTHCODE,
229 std::string(m_ProvConfig.provData.WIFI.authcode));
230 provisioningRepresentation.setValue(OC_RSRVD_ES_AUTHPROVIDER,
231 std::string(m_ProvConfig.provData.WIFI.authserverUrl));
232 provisioningRepresentation.setValue(OC_RSRVD_ES_CISERVER,
233 std::string(m_ProvConfig.provData.WIFI.apiserverUrl));
234 provisioningRepresentation.setValue( OC_RSRVD_ES_AUTHTYPE,
235 m_ProvConfig.provData.WIFI.authtype);
236 provisioningRepresentation.setValue(OC_RSRVD_ES_ENCTYPE,
237 m_ProvConfig.provData.WIFI.enctype);
239 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : ssid - %s",
240 m_ProvConfig.provData.WIFI.ssid);
241 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : pwd - %s",
242 m_ProvConfig.provData.WIFI.pwd);
243 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : AuthCode - %s",
244 m_ProvConfig.provData.WIFI.authcode);
245 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : AuthServerUrl - %s",
246 m_ProvConfig.provData.WIFI.authserverUrl);
247 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : APIServerUrl - %s",
248 m_ProvConfig.provData.WIFI.apiserverUrl);
249 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : authtype - %d",
250 m_ProvConfig.provData.WIFI.authtype);
251 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "getProvStatusResponse : enctype - %d",
252 m_ProvConfig.provData.WIFI.enctype);
254 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
256 void(const HeaderOptions& headerOptions,
257 const OCRepresentation& rep, const int eCode) >(
258 std::bind(&EnrolleeResource::checkProvInformationCb, this,
259 std::placeholders::_1, std::placeholders::_2,
260 std::placeholders::_3)));
262 else if (ps == ES_PS_PROVISIONING_COMPLETED) //Indicates that provisioning is completed
264 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
265 "getProvStatusResponse : Provisioning is successful");
266 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
267 ProvisioningStatus >(ESResult::ES_OK, ESState::ES_PROVISIONED_ALREADY);
268 m_dataProvStatusCb(provStatus);
272 void EnrolleeResource::registerInitRemoteEnrolleeStatusCallback (InitRemoteEnrolleeStatusCb callback)
274 m_initRemoteEnrolleeStatusCb = callback;
277 void EnrolleeResource::registerCapabilityStatusCallback(RequestCapabilityStatusCb callback)
279 m_requestCapabilityStatusCb = callback;
282 void EnrolleeResource::registerProvStatusCallback(DataProvStatusCb callback)
284 m_dataProvStatusCb = callback;
287 ESResult EnrolleeResource::ESDiscoveryTimeout(unsigned short waittime)
289 struct timespec startTime;
292 struct timespec currTime;
296 ESResult res = ES_OK;
297 #ifdef _POSIX_MONOTONIC_CLOCK
298 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
300 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
308 while (ES_OK == res || m_discoveryResponse == false)
310 #ifdef _POSIX_MONOTONIC_CLOCK
311 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
313 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
318 std::shared_ptr< InitRemoteEnrolleeStatus > initRemoteEnrolleeStatus = std::make_shared<
319 InitRemoteEnrolleeStatus >(ESResult::ES_ERROR);
320 m_initRemoteEnrolleeStatusCb(initRemoteEnrolleeStatus);
323 long elapsed = (currTime.tv_sec - startTime.tv_sec);
324 if (elapsed > waittime)
328 if (m_discoveryResponse)
336 void EnrolleeResource::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
338 OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "onDeviceDiscovered");
340 std::string resourceURI;
341 std::string hostAddress;
342 std::string hostDeviceID;
347 // Get the resource URI
348 resourceURI = resource->uri();
349 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
350 "URI of the resource: %s", resourceURI.c_str());
352 // Get the resource host address
353 hostAddress = resource->host();
354 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
355 "Host address of the resource: %s", hostAddress.c_str());
357 hostDeviceID = resource->sid();
358 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
359 "Host DeviceID of the resource: %s", hostDeviceID.c_str());
361 * Easysetup is always performed with a single Enrollee device and
362 * in a private network (SoftAP or BLE), so the assumption is that
363 * only the intended device will respond for the discovery.
364 * With the above assumption the below two statements are written.
366 m_ocResource = resource;
367 m_discoveryResponse = true;
369 std::shared_ptr< InitRemoteEnrolleeStatus > initRemoteEnrolleeStatus = std::make_shared<
370 InitRemoteEnrolleeStatus >(ESResult::ES_OK);
371 m_initRemoteEnrolleeStatusCb(initRemoteEnrolleeStatus);
375 OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Resource is invalid");
377 std::shared_ptr< InitRemoteEnrolleeStatus > initRemoteEnrolleeStatus = std::make_shared<
378 InitRemoteEnrolleeStatus >(ESResult::ES_ERROR);
379 m_initRemoteEnrolleeStatusCb(initRemoteEnrolleeStatus);
383 catch(std::exception& e)
385 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
386 "Exception in foundResource: %s", e.what());
391 ESResult EnrolleeResource::constructResourceObject()
393 if (m_ocResource != nullptr)
395 throw ESBadRequestException("Remote resource is already created");
398 #ifdef REMOTE_ARDUINO_ENROLEE
399 //This process will create OCResource with port 55555 which is specific
400 // to Arduino WiFi enrollee
404 std::vector< std::string > interface =
405 { DEFAULT_INTERFACE};
406 std::vector< std::string > resTypes =
409 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
411 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_host = %s",
412 m_wifiOnboardingconn.ipAddress);
413 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "ES_PROV_RES_URI = %s", ES_PROV_RES_URI);
414 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
415 m_ProvConfig.connType);
416 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "resTypes = %s",
417 resTypes.at(0).c_str());
418 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "interface = %s", interface.at(0).c_str());
421 if(m_wifiOnboardingconn.isSecured)
423 host.append("coaps://");
427 host.append("coap://");
430 if(m_ProvConfig.connType == CT_ADAPTER_IP)
432 // TODO : RemoteEnrollee is current handling easysetup on IP transport.
433 // WiFiRemoteEnrollee need to extend RemoteEnrollee for providing IP specific
434 // Enrollee easysetup.
436 host.append(m_wifiOnboardingconn.ipAddress);
437 //TODO : If the target Enrollee is not a Arduino Wi-Fi device,
438 // then the port number will be found during resource discovery instead of
440 host.append(":55555");
443 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "HOST = %s", host.c_str());
445 m_ocResource = OC::OCPlatform::constructResourceObject(host,
447 m_ProvConfig.connType,
451 OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG,
452 "created OCResource : %s", m_ocResource->uri().c_str());
456 catch (OCException & e)
458 OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_RES_TAG,
459 "Exception for constructResourceObject : %s", e.reason().c_str());
463 std::string host("");
464 std::string query("");
466 if (m_wifiOnboardingconn.isSecured)
468 host.append("coaps://");
472 host.append("coap://");
475 query.append(ES_BASE_RES_URI);
476 query.append("?rt=");
477 query.append(ES_PROV_RES_TYPE);
479 OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "Before OCPlatform::constructResourceObject");
481 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "host = %s", host.c_str());
482 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "query = %s", query.c_str());
483 OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_RES_TAG, "m_connectivityType = %d",
484 m_ProvConfig.connType);
486 m_discoveryResponse = false;
487 std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
488 std::bind(&EnrolleeResource::onDeviceDiscovered, this,
489 std::placeholders::_1);
490 OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
491 onDeviceDiscoveredCb);
493 if (result != OCStackResult::OC_STACK_OK)
495 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
496 "Failed to create device using constructResourceObject");
501 ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
503 if (foundResponse ==ES_ERROR || !m_discoveryResponse)
505 OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_RES_TAG,
506 "Failed to create device using constructResourceObject");
514 void EnrolleeResource::getCapabilityData()
516 if (m_ocResource == nullptr)
518 throw ESBadRequestException("Resource is not initialized");
521 OC::QueryParamsMap query;
522 OC::OCRepresentation rep;
524 std::function< OCStackResult(void) > getCapabilityStatus = [&]
525 { return m_ocResource->get(m_ocResource->getResourceTypes().at(0),
526 BATCH_INTERFACE, query, std::function<void(const HeaderOptions& headerOptions,
527 const OCRepresentation& rep, const int eCode) >(
528 std::bind(&EnrolleeResource::getCapabilityResponse, this,
529 std::placeholders::_1, std::placeholders::_2,
530 std::placeholders::_3)));
533 OCStackResult result = getCapabilityStatus();
535 if (result != OCStackResult::OC_STACK_OK)
537 CapabilityData capabilityData;
538 std::shared_ptr< RequestCapabilityStatus > requestCapabilityStatus = std::make_shared<
539 RequestCapabilityStatus >(ESResult::ES_ERROR, capabilityData);
540 m_requestCapabilityStatusCb(requestCapabilityStatus);
545 void EnrolleeResource::provisionEnrollee()
548 if (m_ocResource == nullptr)
550 throw ESBadRequestException("Resource is not initialized");
553 OC::QueryParamsMap query;
554 OC::OCRepresentation rep;
556 std::function< OCStackResult(void) > getProvisioingStatus = [&]
557 { return m_ocResource->get(m_ocResource->getResourceTypes().at(0),
558 m_ocResource->getResourceInterfaces().at(0), query,
560 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
562 std::bind(&EnrolleeResource::getProvStatusResponse, this,
563 std::placeholders::_1, std::placeholders::_2,
564 std::placeholders::_3)));
567 OCStackResult result = getProvisioingStatus();
569 if (result != OCStackResult::OC_STACK_OK)
571 std::shared_ptr< ProvisioningStatus > provStatus = std::make_shared<
572 ProvisioningStatus >(ESResult::ES_ERROR, ESState::ES_PROVISIONING_ERROR);
573 m_dataProvStatusCb(provStatus);
578 void EnrolleeResource::unprovisionEnrollee()
580 if (m_ocResource == nullptr)
582 throw ESBadRequestException("Resource is not initialized");
585 OCRepresentation provisioningRepresentation;
587 provisioningRepresentation.setValue(OC_RSRVD_ES_SSID, "");
588 provisioningRepresentation.setValue(OC_RSRVD_ES_CRED, "");
590 m_ocResource->post(provisioningRepresentation, QueryParamsMap(),
592 void(const HeaderOptions& headerOptions, const OCRepresentation& rep,
594 std::bind(&EnrolleeResource::checkProvInformationCb, this,
595 std::placeholders::_1, std::placeholders::_2,
596 std::placeholders::_3)));