Asynchronous User Confirm 99/201699/1 accepted/tizen/5.0/unified/20190319.051623 submit/tizen_5.0/20190319.025841
authorOleksii Beketov <ol.beketov@samsung.com>
Wed, 13 Mar 2019 11:04:52 +0000 (13:04 +0200)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 19 Mar 2019 02:15:19 +0000 (11:15 +0900)
API for asynchronous user confirmation added

https://github.sec.samsung.net/RS7-IOTIVITY/IoTivity/pull/373
(cherry picked from adaebd8edd926ae3ddc34f9a21edc793af7b0c1f)

Change-Id: Ib5db1b9cafa5700b9ffe8c669677126e7637c818
Signed-off-by: Oleksii Beketov <ol.beketov@samsung.com>
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
resource/c_common/octhread/include/octhread.h
resource/c_common/octhread/src/posix/octhread.c
resource/csdk/security/include/oxmverifycommon.h
resource/csdk/security/provisioning/sample/sampleserver_mfg.cpp
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/oxmverifycommon.c

index 95728d1..8f96de8 100644 (file)
@@ -59,7 +59,8 @@ typedef enum
     OC_THREAD_INVALID = 3,
     OC_THREAD_WAIT_FAILURE = 4,
     OC_THREAD_INVALID_PARAMETER = 5,
-    OC_THREAD_CANCEL_FAILURE = 6
+    OC_THREAD_CANCEL_FAILURE = 6,
+    OC_THREAD_DETACH_FAILURE = 7
 } OCThreadResult_t;
 
 /**
@@ -103,6 +104,17 @@ OCThreadResult_t oc_thread_free(oc_thread t);
  */
 OCThreadResult_t oc_thread_wait(oc_thread t);
 
+/**
+ * Detach the thread
+ *
+ * @param[in] t The thread to be detached
+ * @return OCThreadResult_t An enumeration of possible outcomes
+ * @retval OC_THREAD_SUCCESS If the thread successfully detached
+ * @retval OC_THREAD_DETACH_FAILURE If a problem occured while detaching
+ *
+ */
+OCThreadResult_t oc_thread_detach(oc_thread t);
+
 #ifdef __TIZEN__
 /**
  * Cancel the thread without block
index 2e9781a..4a0ca43 100644 (file)
@@ -176,6 +176,21 @@ OCThreadResult_t oc_thread_wait(oc_thread t)
     return res;
 }
 
+OCThreadResult_t oc_thread_detach(oc_thread t)
+{
+    OCThreadResult_t res = OC_THREAD_SUCCESS;
+#ifndef __TIZENRT__
+    oc_thread_internal *threadInfo = (oc_thread_internal*) t;
+    int detachres = pthread_detach(threadInfo->thread);
+    if (0 != detachres)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to detach thread with error %d", detachres);
+        res = OC_THREAD_DETACH_FAILURE;
+    }
+#endif
+    return res;
+}
+
 #ifdef __TIZEN__
 OCThreadResult_t oc_thread_cancel(oc_thread t)
 {
index bab6aa2..ecf50a6 100644 (file)
@@ -84,6 +84,17 @@ typedef struct UserConfirmContext
 } UserConfirmContext_t;
 
 /**
+ * Context for getting user confirmation
+ */
+typedef struct UserAsyncConfirmContext
+{
+    UserConfirmCallback callback;
+    void * context;
+    bool userConfirmResult;
+    bool userConfirm;
+} UserAsyncConfirmContext_t;
+
+/**
  * Context for notifying user input state
  */
 typedef struct InputStateContext
@@ -108,11 +119,21 @@ void* UnsetDisplayNumCB();
 void SetUserConfirmCB(void * ptr, UserConfirmCallback userConfirmCB);
 
 /**
+ * Set asynchronous callback for getting user confirmation
+ */
+void SetAsyncUserConfirmCB(void * ptr, UserConfirmCallback userConfirmCB);
+
+/**
  * Unset Callback for getting user confirmation
  */
 void* UnsetUserConfirmCB();
 
 /**
+ * Unset asynchronous callback for getting user confirmation
+ */
+void* UnsetAsyncUserConfirmCB();
+
+/**
  * Set Callback for notifying user input state
  */
 void SetInputStateCB(void * ptr, UserConfirmCallback userConfirmCB);
@@ -145,10 +166,30 @@ OCStackResult VerifyOwnershipTransfer(uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LE
                                 VerifyOptionBitmask_t verifyOption);
 
 /**
+ * Call the Asynchronius Callback for Verifying Ownership Transfer process.
+ */
+OCStackResult VerifyUserConfirm();
+
+/**
+ * Get user asynchronous verification result
+ */
+void GetAsyncVerifyUserResult(bool * result, bool * confirm);
+
+/**
  * Call the Callback for notifying user input state
  */
 OCStackResult NotifyInputState(void);
 
+/**
+ * Callback to set user confirmation result.
+ *
+ * @param ctx       Asynchronous confirmation context.
+ * @param confirmed User confirmation result.
+ *
+ * @retVal ::OC_STACK_OK
+ */
+OCStackResult SendUserConfirm(bool confirmed);
+
 #ifdef __cplusplus
 }
 #endif
index a1923fe..88ff489 100644 (file)
@@ -406,9 +406,8 @@ void handleSigInt(int signum)
     }
 }
 
-OCStackResult confirmCB(void * ctx)
+OCStackResult confirmCB_thread()
 {
-    OC_UNUSED(ctx);
     for (;;)
     {
         int userConfirm;
@@ -424,17 +423,27 @@ OCStackResult confirmCB(void * ctx)
         }
         if (1 == userConfirm)
         {
+            SendUserConfirm(true);
             break;
         }
         else if (0 == userConfirm)
         {
-            return OC_STACK_USER_DENIED_REQ;
+            SendUserConfirm(false);
+            break;
         }
         printf("   Entered Wrong Number. Please Enter Again\n");
     }
     return OC_STACK_OK;
 }
 
+OCStackResult confirmCB(void * ctx)
+{
+    OC_UNUSED(ctx);
+    pthread_t threadId;
+    pthread_create (&threadId, NULL, &confirmCB_thread, NULL);
+    return OC_STACK_OK;
+}
+
 void confirmNoCertCB(CACertificateVerificationStatus_t status)
 {
     if (CA_CERTIFICATE_VERIFY_SUCCESS_MUTUAL == status)
@@ -499,7 +508,7 @@ int main(int argc, char **argv)
     // Initialize Persistent Storage for SVR database
     OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink, NULL, NULL};
 
-    SetUserConfirmCB(NULL, confirmCB);
+    SetAsyncUserConfirmCB(NULL, confirmCB);
     SetInformOxmSelCB(informOxmSelCB);
     CAsetCertificateVerificationCallback(confirmNoCertCB);
 
index 320425f..811fa89 100644 (file)
@@ -49,6 +49,8 @@
 #include "pinoxmcommon.h"
 #include "oxmverifycommon.h"
 #include "octhread.h"
+#include "oic_time.h"
+#include "oic_string.h"
 
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 #include "pkix_interface.h"
@@ -95,6 +97,9 @@ static OicSecDoxm_t        *gDoxm = NULL;
 static oc_mutex            g_mutexDoxm = NULL;
 static bool                g_isDoxmNull = false;
 static OCResourceHandle    gDoxmHandle = NULL;
+static oc_mutex            g_mutexWait;
+static oc_thread           g_waitConfirmThreadId;
+oc_cond                    g_condWait;
 static InformOxmSelectedCallback_t g_InformOxmSelectedCallback = NULL;
 
 static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
@@ -1096,6 +1101,122 @@ void UnsetInformOxmSelCB()
     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
 }
 
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest);
+
+void * WaitConfirm(OCEntityHandlerRequest * ehRequest)
+{
+    bool confirmResult = false, confirmState = false;
+
+    oc_mutex_lock(g_mutexWait);
+    oc_cond_wait(g_condWait, g_mutexWait);
+    oc_cond_free(g_condWait);
+    oc_mutex_free(g_mutexWait);
+
+    GetAsyncVerifyUserResult(&confirmResult, &confirmState);
+    if (confirmResult == true)
+    {
+        gConfirmState = CONFIRM_STATE_ACCEPTED;
+        HandleDoxmPostRequest(ehRequest);
+        return NULL;
+    }
+    else
+    {
+        gConfirmState = CONFIRM_STATE_DENIED;
+        HandleDoxmPostRequest(ehRequest);
+        return NULL;
+    }
+}
+
+static OCEntityHandlerRequest *CopyRequest(OCEntityHandlerRequest *entityHandlerRequest)
+{
+    OIC_LOG(INFO, TAG, "Copying received request for slow response");
+
+    if (!entityHandlerRequest)
+    {
+        OIC_LOG_V(ERROR, TAG, "%s: entityHandlerRequest is NULL", __func__);
+        return NULL;
+    }
+
+    OCEntityHandlerRequest *copyOfRequest =
+            (OCEntityHandlerRequest *)OICMalloc(sizeof(OCEntityHandlerRequest));
+    if(!copyOfRequest)
+    {
+        OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+        return NULL;
+    }
+
+    memcpy(copyOfRequest, entityHandlerRequest, sizeof(OCEntityHandlerRequest));
+
+    if (entityHandlerRequest->query)
+    {
+        copyOfRequest->query = OICStrdup(entityHandlerRequest->query);
+        if(!copyOfRequest->query)
+        {
+            OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+            OICFree(copyOfRequest);
+            return NULL;
+        }
+    }
+
+    if (entityHandlerRequest->payload)
+    {
+        copyOfRequest->payload =
+                (OCSecurityPayload *)OICMalloc(sizeof(OCSecurityPayload));
+        if(!copyOfRequest->payload)
+        {
+            OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+            OICFree(copyOfRequest->query);
+            OICFree(copyOfRequest);
+            return NULL;
+        }
+
+        if (((OCSecurityPayload *)copyOfRequest->payload)->securityData &&
+            ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize)
+        {
+            ((OCSecurityPayload *)copyOfRequest->payload)->securityData =
+                    (uint8_t *)OICMalloc(((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+            if(!((OCSecurityPayload *)copyOfRequest->payload)->securityData)
+            {
+                OIC_LOG(ERROR, TAG, "Copy failed due to allocation failure");
+                OICFree(copyOfRequest->payload);
+                OICFree(copyOfRequest->query);
+                OICFree(copyOfRequest);
+                return NULL;
+            }
+
+            memcpy(((OCSecurityPayload *)copyOfRequest->payload)->securityData,
+                  ((OCSecurityPayload *)entityHandlerRequest->payload)->securityData,
+                  ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+
+            ((OCSecurityPayload *)(copyOfRequest->payload))->payloadSize =
+                    ((OCSecurityPayload *)(entityHandlerRequest->payload))->payloadSize;
+
+            memcpy(((OCSecurityPayload *)copyOfRequest->payload)->securityData,
+                   ((OCSecurityPayload *)entityHandlerRequest->payload)->securityData,
+                   ((OCSecurityPayload *)entityHandlerRequest->payload)->payloadSize);
+        }
+
+        copyOfRequest->payload->type = entityHandlerRequest->payload->type;
+        copyOfRequest->messageID = entityHandlerRequest->messageID;
+    }
+
+    // Ignore vendor specific header options for example
+    copyOfRequest->numRcvdVendorSpecificHeaderOptions = 0;
+    copyOfRequest->rcvdVendorSpecificHeaderOptions = NULL;
+
+    if (copyOfRequest)
+    {
+        OIC_LOG(INFO, TAG, "Copied client request");
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Error copying client request");
+    }
+    return copyOfRequest;
+}
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
 static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
 {
     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
@@ -1473,25 +1594,45 @@ static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRe
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
                 else if (OIC_MANUFACTURER_CERTIFICATE ==  newDoxm->oxmSel || OIC_CON_MFG_CERT == newDoxm->oxmSel)
                 {
-                    //Get user confirmation
-                    if (false == newDoxm->owned &&
-                        false == isDuplicatedMsg &&
-                        memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
+                    if (CONFIRM_STATE_ACCEPTED != gConfirmState && CONFIRM_STATE_DENIED != gConfirmState)
                     {
-                        gConfirmMsgId = ehRequest->messageID;
-                        gConfirmState = CONFIRM_STATE_WAIT;
-                        if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
+                        //Get user confirmation
+                        if (false == newDoxm->owned &&
+                            false == isDuplicatedMsg &&
+                            memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
                         {
-                            ehRet = OC_EH_NOT_ACCEPTABLE;
-                            gConfirmState = CONFIRM_STATE_DENIED;
-                            goto exit;
-                        }
-                        else
-                        {
-                            ehRet = OC_EH_OK;
-                            gConfirmState = CONFIRM_STATE_ACCEPTED;
+                            gConfirmMsgId = ehRequest->messageID;
+                            gConfirmState = CONFIRM_STATE_WAIT;
+
+                            if (OC_STACK_OK != VerifyUserConfirm())
+                            {
+                                if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
+                                {
+                                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                                    gConfirmState = CONFIRM_STATE_DENIED;
+                                    goto exit;
+                                }
+                            }
+                            else
+                            {
+                                OCEntityHandlerRequest * ehRequestCopy = CopyRequest(ehRequest);
+                                VERIFY_NON_NULL(TAG, ehRequestCopy, ERROR);
+
+                                g_condWait = oc_cond_new();
+                                g_mutexWait = oc_mutex_new();
+                                if (oc_thread_new (&g_waitConfirmThreadId, WaitConfirm, ehRequestCopy))
+                                {
+                                    oc_thread_detach(g_waitConfirmThreadId);
+                                }
+                                return OC_EH_SLOW;
+                            }
                         }
                     }
+                    else if (CONFIRM_STATE_DENIED == gConfirmState)
+                    {
+                        ehRet = OC_EH_NOT_ACCEPTABLE;
+                        goto exit;
+                    }
 
                     //Save the owner's UUID to derive owner credential
                     memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
index b8470e9..8f5f946 100644 (file)
@@ -25,6 +25,7 @@
 #include "srmresourcestrings.h"
 #include "cainterface.h"
 #include "oxmverifycommon.h"
+#include "octhread.h"
 
 #define TAG "OIC_VERIFY_COMMON"
 
@@ -32,7 +33,9 @@ static VerifyOptionBitmask_t gVerifyOption = (DISPLAY_NUM | USER_CONFIRM);
 
 static DisplayNumContext_t gDisplayNumContext = { .callback = NULL, .context = NULL };
 static UserConfirmContext_t gUserConfirmContext = { .callback = NULL, .context = NULL };
+static UserAsyncConfirmContext_t gUserAsyncConfirmContext = { .callback = NULL, .context = NULL, .userConfirm = false, .userConfirmResult = false };
 static InputStateContext_t gInputStateContext = { .callback = NULL, .context = NULL };
+extern oc_cond g_condWait;
 
 void SetDisplayNumCB(void * ptr, DisplayNumCallback displayNumCB)
 {
@@ -149,6 +152,62 @@ OCStackResult VerifyOwnershipTransfer(uint8_t mutualVerifNum [MUTUAL_VERIF_NUM_L
     return OC_STACK_OK;
 }
 
+OCStackResult VerifyUserConfirm()
+{
+    OIC_LOG(DEBUG, TAG, "IN VerifyUserConfirm");
+    OIC_LOG_V(DEBUG, TAG, "gVerifyOption: %d", (int) gVerifyOption);
+    if (gVerifyOption)
+    {
+        if (!gUserAsyncConfirmContext.callback)
+        {
+            OIC_LOG(ERROR, TAG, "Callback to get user confirmation not registered");
+            return OC_STACK_ERROR;
+        }
+        OIC_LOG(DEBUG, TAG, "calling userAsyncConfirmCallback");
+        gUserAsyncConfirmContext.callback(&gUserAsyncConfirmContext);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT VerifyUserConfirm");
+    return OC_STACK_OK;
+}
+
+void GetAsyncVerifyUserResult(bool * result, bool * confirm)
+{
+    *result = gUserAsyncConfirmContext.userConfirmResult;
+    *confirm = gUserAsyncConfirmContext.userConfirm;
+    return;
+}
+
+void SetAsyncUserConfirmCB(void * ptr, UserConfirmCallback userConfirmCB)
+{
+    OIC_LOG(DEBUG, TAG, "IN SetAsyncUserConfirmCB");
+    if (NULL == userConfirmCB)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to set callback to confirm mutualVerifNum");
+        return;
+    }
+    gUserAsyncConfirmContext.callback = userConfirmCB;
+    gUserAsyncConfirmContext.context = ptr;
+    OIC_LOG(DEBUG, TAG, "OUT SetAsyncUserConfirmCB");
+}
+
+void* UnsetAsyncUserConfirmCB()
+{
+    OIC_LOG(DEBUG, TAG, "IN UnsetAsyncUserConfirmCB");
+    void *prevctx = gUserAsyncConfirmContext.context;
+    gUserAsyncConfirmContext.callback = NULL;
+    gUserAsyncConfirmContext.context = NULL;
+    OIC_LOG(DEBUG, TAG, "OUT UnsetAsyncUserConfirmCB");
+    return prevctx;
+}
+
+OCStackResult SendUserConfirm(bool confirmed)
+{
+    gUserAsyncConfirmContext.userConfirmResult = confirmed;
+    gUserAsyncConfirmContext.userConfirm = true;
+    oc_cond_signal(g_condWait);
+    return OC_STACK_OK;
+}
+
 OCStackResult NotifyInputState(void)
 {
     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);