Merge branch 'master' into extended-easysetup
[platform/upstream/iotivity.git] / service / easy-setup / mediator / richsdk / src / RemoteEnrollee.cpp
index cb6cb7a..24c9705 100755 (executable)
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
 #include "RemoteEnrollee.h"
-#include "RemoteEnrolleeResource.h"
+#include "EnrolleeResource.h"
+#include "CloudResource.h"
+#include "OCPlatform.h"
 #include "ESException.h"
 #include "logger.h"
+#include "OCResource.h"
 #ifdef __WITH_DTLS__
 #include "EnrolleeSecurity.h"
 #endif //__WITH_DTLS
 
 namespace OIC
 {
-    #define ES_REMOTE_ENROLLEE_TAG "ES_REMOTE_ENROLLEE"
-
     namespace Service
     {
-        RemoteEnrollee::RemoteEnrollee(const ProvConfig& provConfig, const WiFiOnboadingConnection& connection) :
-                m_ProvConfig(provConfig), m_wifiOnboardingconn(connection)
-        {
-            m_currentESState = CurrentESState::ES_UNKNOWN;
-            m_isSecured = connection.isSecured; //enrolleeNWProvInfo.needSecuredEasysetup;
+        static const char ES_BASE_RES_URI[] = "/oic/res";
+        #define ES_REMOTE_ENROLLEE_TAG "ES_REMOTE_ENROLLEE"
+        #define DISCOVERY_TIMEOUT 5
 
-            OIC_LOG ( DEBUG, ES_REMOTE_ENROLLEE_TAG, "Inside RemoteEnrollee constr");
+        RemoteEnrollee::RemoteEnrollee(std::shared_ptr< OC::OCResource > resource)
+        {
+            m_ocResource = resource;
+            m_enrolleeResource = std::make_shared<EnrolleeResource>(m_ocResource);
+            m_securityProvStatusCb = nullptr;
+            m_getConfigurationStatusCb = nullptr;
+            m_securityPinCb = nullptr;
+            m_secProvisioningDbPathCb = nullptr;
+            m_devicePropProvStatusCb = nullptr;
+            m_cloudPropProvStatusCb = nullptr;
+
+            m_deviceId = resource->sid();
         }
 
 #ifdef __WITH_DTLS__
@@ -56,249 +66,358 @@ namespace OIC
         }
 #endif //__WITH_DTLS__
 
-        void RemoteEnrollee::registerEasySetupStatusHandler(EasySetupStatusCB callback)
+        void RemoteEnrollee::securityStatusHandler(
+                        std::shared_ptr< SecProvisioningStatus > status)
         {
-            OIC_LOG ( DEBUG, ES_REMOTE_ENROLLEE_TAG, "Entered registerStatusHandler");
-            if(!callback)
-            {
-                throw ESInvalidParameterException("Callback is empty");
-            }
+            OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s, "
+                    "Status = %d", status->getDeviceUUID().c_str(),
+                    status->getESResult());
 
-            if (m_easySetupStatusCb)
+            if(status->getESResult() == ES_OK)
             {
-                throw ESBadRequestException("Callback handler already registered");
+                OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
+                        "Continue with Network information provisioning");
+
+                OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
+
+                m_securityProvStatusCb(status);
             }
             else
             {
-                m_easySetupStatusCb = callback;
+                OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are fail");
 
-                m_remoteResource = std::make_shared< RemoteEnrolleeResource >(m_ProvConfig, m_wifiOnboardingconn);
+                m_securityProvStatusCb(status);
             }
         }
 
-        void RemoteEnrollee::easySetupSecurityStatusCallback(
-                        std::shared_ptr< SecProvisioningResult > secProvisioningResult)
+        void RemoteEnrollee::getConfigurationStatusHandler (
+                std::shared_ptr< GetConfigurationStatus > status)
         {
-            OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG, "easySetupStatusCallback status is, UUID = %s, "
-                    "Status = %d", secProvisioningResult->getDeviceUUID().c_str(),
-                    secProvisioningResult->getResult());
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering getConfigurationStatusHandler");
 
-            if(secProvisioningResult->getResult() == ES_OK)
-            {
-                OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful. "
-                        "Continue with Network information provisioning");
+            OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"GetConfigurationStatus = %d", status->getESResult());
 
-                m_currentESState = CurrentESState::ES_OWNED;
+            m_getConfigurationStatusCb(status);
+        }
 
-                OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
+        void RemoteEnrollee::devicePropProvisioningStatusHandler(
+                std::shared_ptr< DevicePropProvisioningStatus > status)
+        {
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering DevicePropProvisioningStatusHandler");
 
-                RemoteEnrolleeResource::ProvStatusCb provStatusCb = std::bind(
-                        &RemoteEnrollee::provisioningStatusHandler, this, std::placeholders::_1);
+            OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", status->getESResult());
 
-                m_remoteResource->registerProvStatusCallback(provStatusCb);
-                m_remoteResource->provisionEnrollee();
-            }
-            else
-            {
-                OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Ownership and ACL are successful");
-                std::shared_ptr< EasySetupStatus > easySetupStatus = nullptr;
-                easySetupStatus = std::make_shared< EasySetupStatus >(DEVICE_NOT_PROVISIONED,
-                                            m_ProvConfig);
-                if (m_easySetupStatusCb)
-                {
-                    if (easySetupStatus)
-                    {
-                        m_easySetupStatusCb(easySetupStatus);
-                    }
-                    else
-                    {
-                        m_easySetupStatusCb(nullptr);
-                    }
-                }
-            }
+            m_devicePropProvStatusCb(status);
+
+            return;
         }
 
-        void RemoteEnrollee::provisioningStatusHandler(
-                std::shared_ptr< ProvisioningStatus > provStatus)
+        void RemoteEnrollee::cloudPropProvisioningStatusHandler (
+                std::shared_ptr< CloudPropProvisioningStatus > status)
         {
-            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering ProvisioningStatusHandler");
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering cloudPropProvisioningStatusHandler");
 
-            OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"ProvStatus = %d", provStatus->getESResult());
+            OIC_LOG_V(DEBUG,ES_REMOTE_ENROLLEE_TAG,"CloudProvStatus = %d", status->getESCloudState());
 
-            std::shared_ptr< EasySetupStatus > easySetupStatus = nullptr;
+            m_cloudPropProvStatusCb(status);
+            return;
+        }
+
+        ESResult RemoteEnrollee::ESDiscoveryTimeout(unsigned short waittime)
+        {
+            struct timespec startTime;
+            startTime.tv_sec=0;
+            startTime.tv_sec=0;
+            struct timespec currTime;
+            currTime.tv_sec=0;
+            currTime.tv_nsec=0;
+
+            ESResult res = ES_OK;
+            #ifdef _POSIX_MONOTONIC_CLOCK
+                int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
+            #else
+                int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
+            #endif
+
+            if (0 != clock_res)
+            {
+                return ES_ERROR;
+            }
 
-            if (m_isSecured)
+            while (ES_OK == res || m_discoveryResponse == false)
             {
-                if (m_currentESState >= CurrentESState::ES_OWNED)
+                #ifdef _POSIX_MONOTONIC_CLOCK
+                        clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
+                #else
+                        clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
+                #endif
+
+                if (0 != clock_res)
                 {
-                    goto CALLBACK_CHECK;
+                    return ES_ERROR;
                 }
-                else
+                long elapsed = (currTime.tv_sec - startTime.tv_sec);
+                if (elapsed > waittime)
                 {
-                    goto FAILURE;
+                    return ES_OK;
                 }
-            }
-            else
-            {
-                goto CALLBACK_CHECK;
-            }
+                if (m_discoveryResponse)
+                {
+                    res = ES_OK;
+                }
+             }
+             return res;
+        }
 
-            CALLBACK_CHECK:
+        void RemoteEnrollee::onDeviceDiscovered(std::shared_ptr<OC::OCResource> resource)
+        {
+            OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "onDeviceDiscovered");
+
+            std::string resourceURI;
+            std::string hostAddress;
+            std::string hostDeviceID;
 
-            if (provStatus->getESResult() == ES_OK)
+            try
             {
-                if (provStatus->getESState() >= ESState::ES_PROVISIONED_ALREADY)
-                {
-                    easySetupStatus = std::make_shared< EasySetupStatus >(DEVICE_PROVISIONED,
-                            m_ProvConfig);
-                }
-                else
+                if(resource)
                 {
-                    easySetupStatus = std::make_shared< EasySetupStatus >(DEVICE_NOT_PROVISIONED,
-                            m_ProvConfig);
+                    if(!(resource->connectivityType() & CT_ADAPTER_TCP))
+                    {
+                        // Get the resource URI
+                        resourceURI = resource->uri();
+                        OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
+                                "URI of the resource: %s", resourceURI.c_str());
+
+                        // Get the resource host address
+                        hostAddress = resource->host();
+                        OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
+                                "Host address of the resource: %s", hostAddress.c_str());
+
+                        hostDeviceID = resource->sid();
+                        OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
+                                "Host DeviceID of the resource: %s", hostDeviceID.c_str());
+
+                        if(!m_deviceId.empty() && m_deviceId == hostDeviceID)
+                        {
+                            OIC_LOG (DEBUG, ES_REMOTE_ENROLLEE_TAG, "Find matched CloudResource");
+                            m_ocResource = resource;
+                            m_discoveryResponse = true;
+                        }
+                    }
                 }
             }
-            else
+            catch(std::exception& e)
             {
-                easySetupStatus = std::make_shared< EasySetupStatus >(DEVICE_NOT_PROVISIONED,
-                        m_ProvConfig);
+                OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG,
+                        "Exception in foundResource: %s", e.what());
             }
+        }
 
-            if (m_easySetupStatusCb)
+        ESResult RemoteEnrollee::discoverResource()
+        {
+            OIC_LOG(DEBUG, ES_REMOTE_ENROLLEE_TAG, "Enter discoverResource");
+
+            std::string query("");
+            query.append(ES_BASE_RES_URI);
+            query.append("?rt=");
+            query.append(OC_RSRVD_ES_RES_TYPE_PROV);
+
+            OIC_LOG_V (DEBUG, ES_REMOTE_ENROLLEE_TAG, "query = %s", query.c_str());
+
+            m_discoveryResponse = false;
+
+            std::function< void (std::shared_ptr<OC::OCResource>) > onDeviceDiscoveredCb =
+                    std::bind(&RemoteEnrollee::onDeviceDiscovered, this,
+                                                    std::placeholders::_1);
+            OCStackResult result = OC::OCPlatform::findResource("", query, CT_DEFAULT,
+                    onDeviceDiscoveredCb);
+
+            if (result != OCStackResult::OC_STACK_OK)
             {
-                if (easySetupStatus)
-                {
-                    m_easySetupStatusCb(easySetupStatus);
-                }
-                else
-                {
-                    m_easySetupStatusCb(nullptr);
-                }
+                OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
+                        "Failed discoverResource");
+                return ES_ERROR;
             }
 
-            return;
+            ESResult foundResponse = ESDiscoveryTimeout (DISCOVERY_TIMEOUT);
+
+            if (foundResponse == ES_ERROR || !m_discoveryResponse)
+            {
+                OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
+                        "Failed discoverResource because timeout");
+                return ES_ERROR;
+            }
+            return ES_OK;
+        }
 
-            FAILURE:
+        void RemoteEnrollee::provisionSecurity(SecurityProvStatusCb callback)
+        {
+#ifdef __WITH_DTLS__
+            m_securityProvStatusCb = callback;
 
-            easySetupStatus = std::make_shared< EasySetupStatus >(DEVICE_NOT_PROVISIONED,
-                                    m_ProvConfig);
+            SecurityProvStatusCb securityProvStatusCb = std::bind(
+                    &RemoteEnrollee::securityStatusHandler,
+                    this,
+                    std::placeholders::_1);
+            //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
+            m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_ocResource, "");
 
-            if (easySetupStatus)
+            m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb, m_securityPinCb, m_secProvisioningDbPathCb);
+
+            try
             {
-                m_easySetupStatusCb(easySetupStatus);
+                m_enrolleeSecurity->performOwnershipTransfer();
             }
-            else
+            catch (OCException & e)
             {
-                m_easySetupStatusCb(nullptr);
+                OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
+                        "Exception for performOwnershipTransfer : %s", e.reason().c_str());
+
+                OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Fail performOwnershipTransfer");
+                    std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
+                            std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
+                    m_securityProvStatusCb(securityProvisioningStatus);
+                return ;
             }
-            return;
+#else
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Mediator is unsecured.");
+
+            std::shared_ptr< SecProvisioningStatus > securityProvisioningStatus =
+                     std::make_shared< SecProvisioningStatus >(nullptr, ES_ERROR);
+            m_securityProvStatusCb(securityProvisioningStatus);
+#endif
         }
 
-        void RemoteEnrollee::startProvisioning()
+        void RemoteEnrollee::getConfiguration(GetConfigurationStatusCb callback)
         {
-            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Entering startProvisioning");
-            if (m_remoteResource == nullptr)
+            if(!callback)
+            {
+                throw ESInvalidParameterException("Callback is empty");
+            }
+
+            m_getConfigurationStatusCb = callback;
+
+            if (m_enrolleeResource == nullptr)
             {
                 throw ESBadRequestException ("Device not created");
             }
 
-            ESResult result = ES_ERROR;
+            GetConfigurationStatusCb getConfigurationStatusCb = std::bind(
+                    &RemoteEnrollee::getConfigurationStatusHandler, this, std::placeholders::_1);
+            m_enrolleeResource->registerGetConfigurationStatusCallback(getConfigurationStatusCb);
+            m_enrolleeResource->getConfiguration();
+        }
 
-            result = m_remoteResource->constructResourceObject();
+        void RemoteEnrollee::provisionDeviceProperties(const DeviceProp& devProp, DevicePropProvStatusCb callback)
+        {
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionDeviceProperties");
 
-            if (result == ES_ERROR)
+            if(!callback)
+            {
+                throw ESInvalidParameterException("Callback is empty");
+            }
+
+            m_devicePropProvStatusCb = callback;
+
+            if (m_enrolleeResource == nullptr)
             {
-                OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
-                                    "Failed to create device using constructResourceObject");
                 throw ESBadRequestException ("Device not created");
             }
 
-            m_currentESState = CurrentESState::ES_ONBOARDED;
+            if(devProp.WIFI.ssid.empty())
+            {
+                throw ESBadRequestException ("Invalid Provisiong Data.");
+            }
+
+            DevicePropProvStatusCb devicePropProvStatusCb = std::bind(
+                    &RemoteEnrollee::devicePropProvisioningStatusHandler, this, std::placeholders::_1);
 
-#ifdef __WITH_DTLS__
-            if (m_isSecured && m_currentESState < CurrentESState::ES_OWNED)
+            m_enrolleeResource->registerDevicePropProvStatusCallback(devicePropProvStatusCb);
+            m_enrolleeResource->provisionEnrollee(devProp);
+        }
+
+        void RemoteEnrollee::initCloudResource()
+        {
+            ESResult result = ES_ERROR;
+
+            if (m_cloudResource != nullptr)
             {
-                EnrolleeSecStatusCb securityProvStatusCb = std::bind(
-                        &RemoteEnrollee::easySetupSecurityStatusCallback,
-                        this,
-                        std::placeholders::_1);
-                //TODO : DBPath is passed empty as of now. Need to take dbpath from application.
-                m_enrolleeSecurity = std::make_shared <EnrolleeSecurity> (m_remoteResource, "");
+                throw ESBadRequestException ("Already created");
+            }
+
+            result = discoverResource();
 
-                m_enrolleeSecurity->registerCallbackHandler(securityProvStatusCb,
-                        m_securityPinCb, m_secProvisioningDbPathCb);
+            if (result == ES_ERROR)
+            {
+                OIC_LOG(ERROR,ES_REMOTE_ENROLLEE_TAG,
+                                    "Failed to create resource object using discoverResource");
+                throw ESBadRequestException ("Resource object not created");
+            }
 
-                try
+            else
+            {
+                if(m_ocResource != nullptr)
                 {
-                    EasySetupState easySetupState = m_enrolleeSecurity->performOwnershipTransfer();
-                    if (easySetupState == DEVICE_NOT_OWNED)
-                    {
-                        OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG,
-                                "performOwnershipTransfer returned : %d",
-                                easySetupState);
-                        return;
-                    }
-                    else if (easySetupState == DEVICE_OWNED)
-                    {
-                        OIC_LOG_V(DEBUG, ES_REMOTE_ENROLLEE_TAG,
-                                "performOwnershipTransfer returned : %d",
-                                easySetupState);
-                        OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
+                    m_cloudResource = std::make_shared<CloudResource>(std::move(m_ocResource));
 
-                        RemoteEnrolleeResource::ProvStatusCb provStatusCb = std::bind(
-                                &RemoteEnrollee::provisioningStatusHandler,
-                                this, std::placeholders::_1);
+                    std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
+                        CloudPropProvisioningStatus >(ESResult::ES_OK, ESCloudProvState::ES_CLOUD_ENROLLEE_FOUND);
 
-                        m_remoteResource->registerProvStatusCallback(provStatusCb);
-                        m_remoteResource->provisionEnrollee();
-                    }
+                    m_cloudPropProvStatusCb(provStatus);
                 }
-                catch (OCException & e)
+                else
                 {
-                    OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
-                            "Exception for performOwnershipTransfer : %s", e.reason().c_str());
-                    return ;
+                    throw ESBadGetException ("Resource handle is invalid");
                 }
             }
-#else
-            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Before ProvisionEnrollee");
-
-            RemoteEnrolleeResource::ProvStatusCb provStatusCb = std::bind(
-                    &RemoteEnrollee::provisioningStatusHandler, this, std::placeholders::_1);
-
-            m_remoteResource->registerProvStatusCallback(provStatusCb);
-            m_remoteResource->provisionEnrollee();
-#endif
         }
 
-        void RemoteEnrollee::stopProvisioning()
+
+        void RemoteEnrollee::provisionCloudProperties(const CloudProp& cloudProp, CloudPropProvStatusCb callback)
         {
-            m_currentESState = CurrentESState::ES_UNKNOWN;
+            OIC_LOG(DEBUG,ES_REMOTE_ENROLLEE_TAG,"Enter provisionCloudProperties");
 
-            m_remoteResource->unprovisionEnrollee();
-        }
+            ESResult result = ES_ERROR;
 
-        bool RemoteEnrollee::isEnrolleeProvisioned()
-        {
-            if(m_currentESState >= CurrentESState::ES_PROVISIONED)
+            if(!callback)
             {
-                return true;
+                throw ESInvalidParameterException("Callback is empty");
             }
-            else
+
+            m_cloudPropProvStatusCb = callback;
+
+            if(cloudProp.authCode.empty()
+                || cloudProp.authProvider.empty()
+                || cloudProp.ciServer.empty())
             {
-                return false;
+                throw ESBadRequestException ("Invalid Cloud Provisiong Info.");
             }
-        }
 
-        ProvConfig RemoteEnrollee::getProvConfig ()
-        {
-            return m_ProvConfig;
-        }
+            try
+            {
+                initCloudResource();
+            }
 
-       WiFiOnboadingConnection RemoteEnrollee::getOnboardConn()
-       {
-         return m_wifiOnboardingconn;
-       }
+            catch (const std::exception& e)
+            {
+                OIC_LOG_V(ERROR, ES_REMOTE_ENROLLEE_TAG,
+                    "Exception caught in provisionCloudProperties = %s", e.what());
 
+                std::shared_ptr< CloudPropProvisioningStatus > provStatus = std::make_shared<
+                        CloudPropProvisioningStatus >(ESResult::ES_ERROR, ESCloudProvState::ES_CLOUD_ENROLLEE_NOT_FOUND);
+                m_cloudPropProvStatusCb(provStatus);
+            }
+
+            if (m_cloudResource == nullptr)
+            {
+                throw ESBadRequestException ("Cloud Resource not created");
+            }
+
+            CloudPropProvStatusCb cloudPropProvStatusCb = std::bind(
+                    &RemoteEnrollee::cloudPropProvisioningStatusHandler, this, std::placeholders::_1);
+
+            m_cloudResource->registerCloudPropProvisioningStatusCallback(cloudPropProvStatusCb);
+            m_cloudResource->provisionEnrollee(cloudProp);
+        }
     }
 }