[IOT-1884] Allow IoTivity to generate and persist PIID
authorAlex Kelley <alexke@microsoft.com>
Mon, 13 Feb 2017 19:57:20 +0000 (11:57 -0800)
committerDan Mihai <Daniel.Mihai@microsoft.com>
Thu, 9 Mar 2017 17:21:34 +0000 (17:21 +0000)
 1. Generate a PIID for the device so that one is always available.
 2. Add the ability to store and retrieve the PIID from a new .dat
    file so it remains persistent across reboots of the device.
    - This .dat file can be updated to handle other information
      relevant to the device in the future.
 3. Update the PIID in the .dat file if the application wants to
    use a specific PIID.
 4. Update PSInterface to handle different databases instead of
    just the security database.
 5. Update the json2cbor tool to make it easy for developers to
    generate .dat files to specify PIID.
 6. Add example JSON and .dat files for specifying a PIID.

Change-Id: Ic556508ea0fb053386d76b2578721debea8ac046
Signed-off-by: Alex Kelley <alexke@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17667
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
resource/csdk/security/include/internal/psinterface.h
resource/csdk/security/src/psinterface.c
resource/csdk/security/tool/json2cbor.c
resource/csdk/stack/include/internal/ocresourcehandler.h
resource/csdk/stack/samples/linux/SimpleClientServer/SConscript
resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.dat [new file with mode: 0644]
resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.json [new file with mode: 0644]
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocstack.c
resource/csdk/stack/test/stacktests.cpp

index ea7e986..0962611 100644 (file)
 #define IOTVT_SRM_PSI_H
 
 /**
+ * Reads the database from PS
+ *
+ * @note Caller of this method MUST use OICFree() method to release memory
+ *       referenced by the data argument.
+ *
+ * @param databaseName is the name of the database to access through persistent storage.
+ * @param resourceName is the name of the field for which file content are read.
+ *                     if the value is NULL it will send the content of the whole file.
+ * @param data         is the pointer to the file contents read from the database.
+ * @param size         is the size of the file contents read.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult ReadDatabaseFromPS(const char *databaseName, const char *resourceName, uint8_t **data, size_t *size);
+
+/**
+ * This method updates the database in PS
+ *
+ * @param databaseName  is the name of the database to access through persistent storage.
+ * @param resourceName  is the name of the resource that will be updated.
+ * @param payload       is the pointer to memory where the CBOR payload is located.
+ * @param size          is the size of the CBOR payload.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult UpdateResourceInPS(const char *databaseName, const char *resourceName, const uint8_t *payload, size_t size);
+
+/**
  * Reads the Secure Virtual Database from PS into dynamically allocated
  * memory buffer.
  *
- * @note Caller of this method MUST use OCFree() method to release memory
+ * @note Caller of this method MUST use OICFree() method to release memory
  *       referenced by return value.
  *
  * @return char * reference to memory buffer containing SVR database.
@@ -35,28 +63,28 @@ char * GetSVRDatabase();
 /**
  * Reads the Secure Virtual Database from PS
  *
- * @note Caller of this method MUST use OCFree() method to release memory
+ * @note Caller of this method MUST use OICFree() method to release memory
  *       referenced by return value.
  *
- * @param rsrcName is the name of the field for which file content are read.
-                   if the value is NULL it will send the content of the whole file.
- * @param data is the pointer to the file contents read from the database.
- * @param size is the size to the file contents read.
+ * @param resourceName is the name of the field for which file content are read.
*                     if the value is NULL it will send the content of the whole file.
+ * @param data         is the pointer to the file contents read from the database.
+ * @param size         is the size of the file contents read.
  *
  * @return ::OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult GetSecureVirtualDatabaseFromPS(const char *rsrcName, uint8_t **data, size_t *size);
+OCStackResult GetSecureVirtualDatabaseFromPS(const char *resourceName, uint8_t **data, size_t *size);
 
 /**
- * This method converts updates the persistent storage.
+ * This method updates the Secure Virtual Database in PS
  *
- * @param rsrcName is the name of the secure resource that will be updated.
- * @param cborPayload is the pointer holding cbor payload.
- * @param size is the size of the cbor payload.
+ * @param resourceName  is the name of the secure resource that will be updated.
+ * @param payload       is the pointer to memory where the CBOR payload is located.
+ * @param size          is the size of the CBOR payload.
  *
  * @return ::OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult UpdateSecureResourceInPS(const char* rsrcName, uint8_t* cborPayload, size_t size);
+OCStackResult UpdateSecureResourceInPS(const char *resourceName, const uint8_t *payload, size_t size);
 
 /**
  * This method resets the secure resources according to the reset profile.
index 0bd6cca..e525c6f 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 
 #include "cainterface.h"
 #include "logger.h"
 #include "srmutility.h"
 #include "pstatresource.h"
 #include "doxmresource.h"
+#include "ocresourcehandler.h"
 
 #define TAG  "OIC_SRM_PSI"
 
-//SVR database buffer block size
+/**
+ * Helps cover adding the name of the resource, map addition, and ending while
+ * performing CBOR encoding.
+ */
+#define CBOR_ENCODING_SIZE_ADDITION 255
+
+/**
+ * Virtual database buffer block size
+ */
 #ifdef _WIN32
 #define DB_FILE_SIZE_BLOCK 1023
 #else
 const size_t DB_FILE_SIZE_BLOCK = 1023;
 #endif
 
+typedef enum _PSDatabase
+{
+    PS_DATABASE_SECURITY = 0,
+    PS_DATABASE_DEVICEPROPERTIES
+} PSDatabase;
+
+/**
+ * Writes CBOR payload to the specified database in persistent storage.
+ *
+ * @param databaseName is the name of the database to access through persistent storage.
+ * @param payload      is the CBOR payload to write to the database in persistent storage.
+ * @param size         is the size of payload.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+static OCStackResult WritePayloadToPS(const char *databaseName, uint8_t *payload, size_t size)
+{
+    if (!databaseName || !payload || (size <= 0))
+    {
+        OC_STACK_INVALID_PARAM;
+    }
+
+    OCStackResult result = OC_STACK_ERROR;
+
+    OIC_LOG_V(DEBUG, TAG, "Writing in the file: %" PRIuPTR, size);
+
+    OCPersistentStorage* ps = OCGetPersistentStorageHandler();
+    if (ps)
+    {
+        FILE *fp = ps->open(databaseName, "wb");
+        if (fp)
+        {
+            size_t numberItems = ps->write(payload, 1, size, fp);
+            if (size == numberItems)
+            {
+                OIC_LOG_V(DEBUG, TAG, "Written %" PRIuPTR " bytes into %s", size, databaseName);
+                result = OC_STACK_OK;
+            }
+            else
+            {
+                OIC_LOG_V(ERROR, TAG, "Failed writing %" PRIuPTR " in %s", numberItems, databaseName);
+            }
+            ps->close(fp);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "File open failed.");
+        }
+    }
+
+    return result;
+}
+
 /**
- * Gets the Secure Virtual Database size
+ * Gets the database size
  *
- * @param ps - pointer of OCPersistentStorage for the Secure Virtual Resource(s)
+ * @param ps            is a pointer to OCPersistentStorage for the Virtual Resource(s).
+ * @param databaseName  is the name of the database to access through persistent storage.
  *
- * @return size_t - total size of the SVR database
+ * @return size_t - total size of the database
  */
-static size_t GetSVRDatabaseSize(const OCPersistentStorage *ps)
+static size_t GetDatabaseSize(const OCPersistentStorage *ps, const char *databaseName)
 {
     if (!ps)
     {
@@ -64,7 +128,7 @@ static size_t GetSVRDatabaseSize(const OCPersistentStorage *ps)
     size_t size = 0;
     char buffer[DB_FILE_SIZE_BLOCK];  // can not initialize with declaration
                                       // but maybe not needed to initialize
-    FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "rb");
+    FILE *fp = ps->open(databaseName, "rb");
     if (fp)
     {
         size_t bytesRead = 0;
@@ -79,18 +143,24 @@ static size_t GetSVRDatabaseSize(const OCPersistentStorage *ps)
 }
 
 /**
- * Gets the Secure Virtual Database from the Persistent Storage
+ * Reads the database from PS
+ * 
+ * @note Caller of this method MUST use OICFree() method to release memory
+ *       referenced by the data argument.
  *
- * @param rsrcName - pointer of character string for the SVR name (e.g. "acl")
- * @param data - pointer of the returned Secure Virtual Resource(s)
- * @param size - pointer of the returned size of Secure Virtual Resource(s)
+ * @param databaseName is the name of the database to access through persistent storage.
+ * @param resourceName is the name of the field for which file content are read.
+ *                     if the value is NULL it will send the content of the whole file.
+ * @param data         is the pointer to the file contents read from the database.
+ * @param size         is the size of the file contents read.
  *
- * @return OCStackResult - result of getting Secure Virtual Resource(s)
+ * @return ::OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult GetSecureVirtualDatabaseFromPS(const char *rsrcName, uint8_t **data, size_t *size)
+OCStackResult ReadDatabaseFromPS(const char *databaseName, const char *resourceName, uint8_t **data, size_t *size)
 {
-    OIC_LOG(DEBUG, TAG, "GetSecureVirtualDatabaseFromPS IN");
-    if (!data || *data || !size)
+    OIC_LOG(DEBUG, TAG, "ReadDatabaseFromPS IN");
+
+    if (!databaseName || !data || *data || !size)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -100,36 +170,36 @@ OCStackResult GetSecureVirtualDatabaseFromPS(const char *rsrcName, uint8_t **dat
     size_t fileSize = 0;
     OCStackResult ret = OC_STACK_ERROR;
 
-    OCPersistentStorage *ps = SRMGetPersistentStorageHandler();
+    OCPersistentStorage *ps = OCGetPersistentStorageHandler();
     VERIFY_NOT_NULL(TAG, ps, ERROR);
 
-    fileSize = GetSVRDatabaseSize(ps);
+    fileSize = GetDatabaseSize(ps, databaseName);
     OIC_LOG_V(DEBUG, TAG, "File Read Size: %zu", fileSize);
     if (fileSize)
     {
         fsData = (uint8_t *) OICCalloc(1, fileSize);
         VERIFY_NOT_NULL(TAG, fsData, ERROR);
 
-        fp = ps->open(SVR_DB_DAT_FILE_NAME, "rb");
+        fp = ps->open(databaseName, "rb");
         VERIFY_NOT_NULL(TAG, fp, ERROR);
         if (ps->read(fsData, 1, fileSize, fp) == fileSize)
         {
-            if (rsrcName)
+            if (resourceName)
             {
                 CborParser parser;  // will be initialized in |cbor_parser_init|
                 CborValue cbor;     // will be initialized in |cbor_parser_init|
                 cbor_parser_init(fsData, fileSize, 0, &parser, &cbor);
                 CborValue cborValue = {0};
-                CborError cborFindResult = cbor_value_map_find_value(&cbor, rsrcName, &cborValue);
+                CborError cborFindResult = cbor_value_map_find_value(&cbor, resourceName, &cborValue);
                 if (CborNoError == cborFindResult && cbor_value_is_byte_string(&cborValue))
                 {
                     cborFindResult = cbor_value_dup_byte_string(&cborValue, data, size, NULL);
-                    VERIFY_SUCCESS(TAG, CborNoError==cborFindResult, ERROR);
+                    VERIFY_SUCCESS(TAG, CborNoError == cborFindResult, ERROR);
                     ret = OC_STACK_OK;
                 }
                 // in case of |else (...)|, svr_data not found
             }
-            // return everything in case rsrcName is NULL
+            // return everything in case resourceName is NULL
             else
             {
                 *size = fileSize;
@@ -140,7 +210,7 @@ OCStackResult GetSecureVirtualDatabaseFromPS(const char *rsrcName, uint8_t **dat
             }
         }
     }
-    OIC_LOG(DEBUG, TAG, "GetSecureVirtualDatabaseFromPS OUT");
+    OIC_LOG(DEBUG, TAG, "ReadDatabaseFromPS OUT");
 
 exit:
     if (fp)
@@ -152,20 +222,19 @@ exit:
 }
 
 /**
- * Updates the Secure Virtual Resource(s) into the Persistent Storage.
- * This function stores cbor-payload of each resource by appending resource name,
- * and empty payload implies deleting the value
+ * This method updates the database in PS
  *
- * @param rsrcName - pointer of character string for the SVR name (e.g. "acl")
- * @param psPayload - pointer of the updated Secure Virtual Resource(s)
- * @param psSize - the updated size of Secure Virtual Resource(s)
+ * @param databaseName  is the name of the database to access through persistent storage.
+ * @param resourceName  is the name of the resource that will be updated.
+ * @param payload       is the pointer to memory where the CBOR payload is located.
+ * @param size          is the size of the CBOR payload.
  *
- * @return OCStackResult - result of updating Secure Virtual Resource(s)
+ * @return ::OC_STACK_OK for Success, otherwise some error value
  */
-OCStackResult UpdateSecureResourceInPS(const char *rsrcName, const uint8_t *psPayload, size_t psSize)
+OCStackResult UpdateResourceInPS(const char *databaseName, const char *resourceName, const uint8_t *payload, size_t size)
 {
-    OIC_LOG(DEBUG, TAG, "UpdateSecureResourceInPS IN");
-    if (!rsrcName)
+    OIC_LOG(DEBUG, TAG, "UpdateResourceInPS IN");
+    if (!databaseName || !resourceName)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -179,25 +248,33 @@ OCStackResult UpdateSecureResourceInPS(const char *rsrcName, const uint8_t *psPa
     uint8_t *pstatCbor = NULL;
     uint8_t *doxmCbor = NULL;
     uint8_t *amaclCbor = NULL;
-    uint8_t *svcCbor = NULL;
     uint8_t *credCbor = NULL;
     uint8_t *pconfCbor = NULL;
     uint8_t *resetPfCbor = NULL;
     uint8_t *crlCbor = NULL;
+    uint8_t *dpCbor = NULL;
 
     int64_t cborEncoderResult = CborNoError;
-    OCStackResult ret = GetSecureVirtualDatabaseFromPS(NULL, &dbData, &dbSize);
+    OCStackResult ret = ReadDatabaseFromPS(databaseName, NULL, &dbData, &dbSize);
     if (dbData && dbSize)
     {
+        PSDatabase database = PS_DATABASE_SECURITY;
+        size_t allocSize = 0;
         size_t aclCborLen = 0;
         size_t pstatCborLen = 0;
         size_t doxmCborLen = 0;
         size_t amaclCborLen = 0;
-        size_t svcCborLen = 0;
         size_t credCborLen = 0;
         size_t pconfCborLen = 0;
         size_t resetPfCborLen = 0;
         size_t crlCborLen = 0;
+        size_t dpCborLen = 0;
+
+        // Determine which database we are working with so we can scope our operations
+        if (0 == strcmp(OC_DEVICE_PROPS_FILE_NAME, databaseName))
+        {
+            database = PS_DATABASE_DEVICEPROPERTIES;
+        }
 
         // Gets each secure virtual resource from persistent storage
         // this local scoping intended, for destroying large cbor instances after use
@@ -208,200 +285,212 @@ OCStackResult UpdateSecureResourceInPS(const char *rsrcName, const uint8_t *psPa
             CborValue curVal = {0};
             CborError cborFindResult = CborNoError;
 
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_ACL_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &aclCbor, &aclCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ACL Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_PSTAT_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &pstatCbor, &pstatCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_DOXM_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &doxmCbor, &doxmCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult,  "Failed Finding DOXM Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_AMACL_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &amaclCbor, &amaclCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding AMACL Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_CRED_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &credCbor, &credCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CRED Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_PCONF_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &pconfCbor, &pconfCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PCONF Name Value.");
-            }
-            cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_RESET_PF_NAME, &curVal);
-            if (CborNoError == cborFindResult && cbor_value_is_byte_string(&curVal))
+            // Only search for and copy resources owned by the target database
+            if (PS_DATABASE_SECURITY == database)
             {
-                cborFindResult = cbor_value_dup_byte_string(&curVal, &resetPfCbor, &resetPfCborLen, NULL);
-                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Reset Profile Name Value.");
-            }
-            int64_t cborFindCrlResult = cbor_value_map_find_value(&cbor, OIC_JSON_CRL_NAME, &curVal);
-            if (CborNoError == cborFindCrlResult && cbor_value_is_byte_string(&curVal))
-            {
-                cborFindCrlResult = cbor_value_dup_byte_string(&curVal, &crlCbor, &crlCborLen, NULL);
-                if (CborNoError != cborFindCrlResult && CborErrorOutOfMemory != cborFindCrlResult)
+                // Security database
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_ACL_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &aclCbor, &aclCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ACL Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_PSTAT_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &pstatCbor, &pstatCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_DOXM_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &doxmCbor, &doxmCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DOXM Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_AMACL_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &amaclCbor, &amaclCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding AMACL Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_CRED_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
                 {
-                    OIC_LOG(ERROR, TAG, "Failed Finding optional CRL Name Value.");
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &credCbor, &credCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CRED Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_PCONF_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &pconfCbor, &pconfCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PCONF Name Value.");
+                }
+                cborFindResult = cbor_value_map_find_value(&cbor, OIC_JSON_RESET_PF_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &resetPfCbor, &resetPfCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Reset Profile Name Value.");
+                }
+                int64_t cborFindCrlResult = cbor_value_map_find_value(&cbor, OIC_JSON_CRL_NAME, &curVal);
+                if ((CborNoError == cborFindCrlResult) && cbor_value_is_byte_string(&curVal))
+                {
+                    cborFindCrlResult = cbor_value_dup_byte_string(&curVal, &crlCbor, &crlCborLen, NULL);
+                    if ((CborNoError != cborFindCrlResult) && (CborErrorOutOfMemory != cborFindCrlResult))
+                    {
+                        OIC_LOG(ERROR, TAG, "Failed Finding optional CRL Name Value.");
+                    }
+                    else
+                    {
+                        OIC_LOG(INFO, TAG, "Successfully Finding optional CRL Name Value.");
+                    }
                 }
-                else
+            }
+            else
+            {
+                // Device Properties database
+                cborFindResult = cbor_value_map_find_value(&cbor, OC_JSON_DEVICE_PROPS_NAME, &curVal);
+                if ((CborNoError == cborFindResult) && cbor_value_is_byte_string(&curVal))
                 {
-                    OIC_LOG(INFO, TAG, "Successfully Finding optional CRL Name Value.");
+                    cborFindResult = cbor_value_dup_byte_string(&curVal, &dpCbor, &dpCborLen, NULL);
+                    VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Properties Name Value.");
                 }
             }
         }
 
-        // Updates the added |psPayload| with the existing secure virtual resource(s)
+        // Updates the added |payload| with the existing secure virtual resource(s)
         // this local scoping intended, for destroying large cbor instances after use
         {
-            size_t size = aclCborLen + pstatCborLen + doxmCborLen + amaclCborLen
-                        + svcCborLen + credCborLen + pconfCborLen + resetPfCborLen + crlCborLen
-                        + psSize + 255;
-            // This added '255' is arbitrary value that is added to cover the name of the resource, map addition and ending
+            if (PS_DATABASE_SECURITY == database)
+            {
+                allocSize = aclCborLen + pstatCborLen + doxmCborLen + amaclCborLen
+                          + credCborLen + pconfCborLen + resetPfCborLen + crlCborLen
+                          + size + CBOR_ENCODING_SIZE_ADDITION;
+            }
+            else
+            {
+                allocSize = dpCborLen + size + CBOR_ENCODING_SIZE_ADDITION;
+            }
 
-            outPayload = (uint8_t *) OICCalloc(1, size);
+
+            outPayload = (uint8_t *)OICCalloc(1, allocSize);
             VERIFY_NOT_NULL(TAG, outPayload, ERROR);
             CborEncoder encoder;  // will be initialized in |cbor_parser_init|
-            cbor_encoder_init(&encoder, outPayload, size, 0);
-            CborEncoder secRsrc;  // will be initialized in |cbor_encoder_create_map|
-            cborEncoderResult |= cbor_encoder_create_map(&encoder, &secRsrc, CborIndefiniteLength);
+            cbor_encoder_init(&encoder, outPayload, allocSize, 0);
+            CborEncoder resource;  // will be initialized in |cbor_encoder_create_map|
+            cborEncoderResult |= cbor_encoder_create_map(&encoder, &resource, CborIndefiniteLength);
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PS Map.");
 
-            if (psPayload && psSize)
+            if (payload && size)
             {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, rsrcName, strlen(rsrcName));
+                cborEncoderResult |= cbor_encode_text_string(&resource, resourceName, strlen(resourceName));
                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Value Tag");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, psPayload, psSize);
+                cborEncoderResult |= cbor_encode_byte_string(&resource, payload, size);
                 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Value.");
             }
-            if (strcmp(OIC_JSON_ACL_NAME, rsrcName) && aclCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_ACL_NAME, strlen(OIC_JSON_ACL_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ACL Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, aclCbor, aclCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ACL Value.");
-            }
-            if (strcmp(OIC_JSON_PSTAT_NAME, rsrcName) && pstatCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_PSTAT_NAME, strlen(OIC_JSON_PSTAT_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PSTAT Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, pstatCbor, pstatCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PSTAT Value.");
-            }
-            if (strcmp(OIC_JSON_DOXM_NAME, rsrcName) && doxmCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_DOXM_NAME, strlen(OIC_JSON_DOXM_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, doxmCbor, doxmCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Value.");
-            }
-            if (strcmp(OIC_JSON_AMACL_NAME, rsrcName) && amaclCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_AMACL_NAME, strlen(OIC_JSON_AMACL_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Amacl Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, amaclCbor, amaclCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Amacl Value.");
-            }
-            if (strcmp(OIC_JSON_CRED_NAME, rsrcName) && credCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_CRED_NAME, strlen(OIC_JSON_CRED_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, credCbor, credCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Value.");
-            }
-            if (strcmp(OIC_JSON_PCONF_NAME, rsrcName) && pconfCborLen)
-            {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_PCONF_NAME, strlen(OIC_JSON_PCONF_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pconf Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, pconfCbor, pconfCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pconf Value.");
-            }
-            if (strcmp(OIC_JSON_RESET_PF_NAME, rsrcName) && resetPfCborLen)
+
+            if (PS_DATABASE_SECURITY == database)
             {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_RESET_PF_NAME, strlen(OIC_JSON_RESET_PF_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Reset Profile Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, resetPfCbor, resetPfCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Reset Profile Value.");
+                // Security database
+                if (strcmp(OIC_JSON_ACL_NAME, resourceName) && aclCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_ACL_NAME, strlen(OIC_JSON_ACL_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ACL Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, aclCbor, aclCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ACL Value.");
+                }
+                else if (strcmp(OIC_JSON_PSTAT_NAME, resourceName) && pstatCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_PSTAT_NAME, strlen(OIC_JSON_PSTAT_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PSTAT Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, pstatCbor, pstatCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PSTAT Value.");
+                }
+                else if (strcmp(OIC_JSON_DOXM_NAME, resourceName) && doxmCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_DOXM_NAME, strlen(OIC_JSON_DOXM_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, doxmCbor, doxmCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Value.");
+                }
+                else if (strcmp(OIC_JSON_AMACL_NAME, resourceName) && amaclCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_AMACL_NAME, strlen(OIC_JSON_AMACL_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Amacl Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, amaclCbor, amaclCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Amacl Value.");
+                }
+                else if (strcmp(OIC_JSON_CRED_NAME, resourceName) && credCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_CRED_NAME, strlen(OIC_JSON_CRED_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, credCbor, credCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Value.");
+                }
+                else if (strcmp(OIC_JSON_PCONF_NAME, resourceName) && pconfCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_PCONF_NAME, strlen(OIC_JSON_PCONF_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pconf Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, pconfCbor, pconfCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pconf Value.");
+                }
+                else if (strcmp(OIC_JSON_RESET_PF_NAME, resourceName) && resetPfCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_RESET_PF_NAME, strlen(OIC_JSON_RESET_PF_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Reset Profile Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, resetPfCbor, resetPfCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Reset Profile Value.");
+                }
+                else if (strcmp(OIC_JSON_CRL_NAME, resourceName) && crlCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OIC_JSON_CRL_NAME, strlen(OIC_JSON_CRL_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Crl Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, crlCbor, crlCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Crl Value.");
+                }
             }
-            if (strcmp(OIC_JSON_CRL_NAME, rsrcName) && crlCborLen)
+            else
             {
-                cborEncoderResult |= cbor_encode_text_string(&secRsrc, OIC_JSON_CRL_NAME, strlen(OIC_JSON_CRL_NAME));
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Crl Name.");
-                cborEncoderResult |= cbor_encode_byte_string(&secRsrc, crlCbor, crlCborLen);
-                VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Crl Value.");
+                // Device Properties database
+                if (strcmp(OC_JSON_DEVICE_PROPS_NAME, resourceName) && dpCborLen)
+                {
+                    cborEncoderResult |= cbor_encode_text_string(&resource, OC_JSON_DEVICE_PROPS_NAME, strlen(OC_JSON_DEVICE_PROPS_NAME));
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Properties Name.");
+                    cborEncoderResult |= cbor_encode_byte_string(&resource, dpCbor, dpCborLen);
+                    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Properties Value.");
+                }
             }
 
-            cborEncoderResult |= cbor_encoder_close_container(&encoder, &secRsrc);
+            cborEncoderResult |= cbor_encoder_close_container(&encoder, &resource);
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Array.");
             outSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
         }
     }
-    else if (psPayload && psSize)
+    else if (payload && size)
     {
-        size_t size = psSize + 255;
-        // This added '255' is arbitrary value that is added to cover the name of the resource, map addition and ending
+        size_t allocSize = size + CBOR_ENCODING_SIZE_ADDITION;
 
-        outPayload = (uint8_t *) OICCalloc(1, size);
+        outPayload = (uint8_t *)OICCalloc(1, allocSize);
         VERIFY_NOT_NULL(TAG, outPayload, ERROR);
         CborEncoder encoder;  // will be initialized in |cbor_parser_init|
-        cbor_encoder_init(&encoder, outPayload, size, 0);
-        CborEncoder secRsrc;  // will be initialized in |cbor_encoder_create_map|
-        cborEncoderResult |= cbor_encoder_create_map(&encoder, &secRsrc, CborIndefiniteLength);
+        cbor_encoder_init(&encoder, outPayload, allocSize, 0);
+        CborEncoder resource;  // will be initialized in |cbor_encoder_create_map|
+        cborEncoderResult |= cbor_encoder_create_map(&encoder, &resource, CborIndefiniteLength);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PS Map.");
 
-        cborEncoderResult |= cbor_encode_text_string(&secRsrc, rsrcName, strlen(rsrcName));
+        cborEncoderResult |= cbor_encode_text_string(&resource, resourceName, strlen(resourceName));
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Value Tag");
-        cborEncoderResult |= cbor_encode_byte_string(&secRsrc, psPayload, psSize);
+        cborEncoderResult |= cbor_encode_byte_string(&resource, payload, size);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Value.");
 
-        cborEncoderResult |= cbor_encoder_close_container(&encoder, &secRsrc);
+        cborEncoderResult |= cbor_encoder_close_container(&encoder, &resource);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Array.");
         outSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
     }
 
-    if (outPayload && outSize)
-    {
-        OIC_LOG_V(DEBUG, TAG, "Writing in the file: %zu", outSize);
-        OCPersistentStorage* ps = SRMGetPersistentStorageHandler();
-        if (ps)
-        {
-            FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "wb");
-            if (fp)
-            {
-                size_t numberItems = ps->write(outPayload, 1, outSize, fp);
-                if (outSize == numberItems)
-                {
-                    OIC_LOG_V(DEBUG, TAG, "Written %zu bytes into SVR database file", outSize);
-                    ret = OC_STACK_OK;
-                }
-                else
-                {
-                    OIC_LOG_V(ERROR, TAG, "Failed writing %zu in the database", numberItems);
-                }
-                ps->close(fp);
-            }
-            else
-            {
-                OIC_LOG(ERROR, TAG, "File open failed.");
-            }
-        }
-    }
+    ret = WritePayloadToPS(databaseName, outPayload, outSize);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR);
 
-    OIC_LOG(DEBUG, TAG, "UpdateSecureResourceInPS OUT");
+    OIC_LOG(DEBUG, TAG, "UpdateResourceInPS OUT");
 
 exit:
     OICFree(dbData);
@@ -410,15 +499,47 @@ exit:
     OICFree(pstatCbor);
     OICFree(doxmCbor);
     OICFree(amaclCbor);
-    OICFree(svcCbor);
     OICFree(credCbor);
     OICFree(pconfCbor);
     OICFree(resetPfCbor);
     OICFree(crlCbor);
+    OICFree(dpCbor);
     return ret;
 }
 
 /**
+ * Reads the Secure Virtual Database from PS
+ *
+ * @note Caller of this method MUST use OICFree() method to release memory
+ *       referenced by return value.
+ *
+ * @param resourceName is the name of the field for which file content are read.
+ *                     if the value is NULL it will send the content of the whole file.
+ * @param data         is the pointer to the file contents read from the database.
+ * @param size         is the size of the file contents read.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult GetSecureVirtualDatabaseFromPS(const char *resourceName, uint8_t **data, size_t *size)
+{
+    return ReadDatabaseFromPS(SVR_DB_DAT_FILE_NAME, resourceName, data, size);
+}
+
+/**
+ * This method updates the Secure Virtual Database in PS
+ *
+ * @param resourceName  is the name of the secure resource that will be updated.
+ * @param payload       is the pointer to memory where the CBOR payload is located.
+ * @param size          is the size of the CBOR payload.
+ *
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult UpdateSecureResourceInPS(const char *resourceName, const uint8_t *payload, size_t size)
+{
+    return UpdateResourceInPS(SVR_DB_DAT_FILE_NAME, resourceName, payload, size);
+}
+
+/**
  * Resets the Secure Virtual Resource(s).
  * This function reads the Reset Profile
  * and resets the secure virtual resources accordingly.
@@ -442,7 +563,6 @@ OCStackResult ResetSecureResourceInPS(void)
 
     int64_t cborEncoderResult = CborNoError;
     OCStackResult ret = GetSecureVirtualDatabaseFromPS(NULL, &dbData, &dbSize);
-
     if(dbData && dbSize)
     {
         size_t aclCborLen = 0;
@@ -500,8 +620,7 @@ OCStackResult ResetSecureResourceInPS(void)
         }
 
         {
-            size_t size = aclCborLen + credCborLen + pstatCborLen + doxmCborLen + resetPfCborLen + 255;
-            // This added '255' is arbitrary value added to cover the name of the resource, map addition, and ending
+            size_t size = aclCborLen + credCborLen + pstatCborLen + doxmCborLen + resetPfCborLen + CBOR_ENCODING_SIZE_ADDITION;
 
             outPayload = (uint8_t *) OICCalloc(1, size);
             VERIFY_NOT_NULL(TAG, outPayload, ERROR);
@@ -543,34 +662,8 @@ OCStackResult ResetSecureResourceInPS(void)
             outSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
         }
 
-        if (outPayload && outSize)
-        {
-            OIC_LOG_V(DEBUG, TAG, "Writing in the file: %zu", outSize);
-            OCPersistentStorage *ps = SRMGetPersistentStorageHandler();
-            if (ps)
-            {
-                FILE *fp = ps->open(SVR_DB_DAT_FILE_NAME, "wb");
-                if (fp)
-                {
-                    size_t numberItems = ps->write(outPayload, 1, outSize, fp);
-                    if (outSize == numberItems)
-                    {
-                        OIC_LOG_V(DEBUG, TAG, "Written %zu bytes into SVR database file", outSize);
-                        ret= OC_STACK_OK;
-                    }
-                    else
-                    {
-                        OIC_LOG_V(ERROR, TAG, "Failed writing %zu in the database", numberItems);
-                    }
-                    ps->close(fp);
-                }
-                else
-                {
-                    OIC_LOG(ERROR, TAG, "File open failed.");
-                }
-
-            }
-        }
+        ret = WritePayloadToPS(SVR_DB_DAT_FILE_NAME, outPayload, outSize);
+        VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR);
     }
 
     SRMDeInitSecureResources();
@@ -662,7 +755,7 @@ OCStackResult CreateResetProfile(void)
         }
 
         {
-            size_t size = aclCborLen + credCborLen + pstatCborLen + doxmCborLen + 255;
+            size_t size = aclCborLen + credCborLen + pstatCborLen + doxmCborLen + CBOR_ENCODING_SIZE_ADDITION;
             resetPfCbor = (uint8_t *) OICCalloc(1, size);
             VERIFY_NOT_NULL(TAG, resetPfCbor, ERROR);
             CborEncoder encoder;  // will be initialized in |cbor_parser_init|
index 70ce730..da650f0 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 #include "utlist.h"
 #include "cJSON.h"
 #include "base64.h"
@@ -39,6 +40,7 @@
 #include "amaclresource.h"
 #include "credresource.h"
 #include "security_internals.h"
+#include "ocresourcehandler.h"
 
 #define TAG  "OIC_JSON2CBOR"
 #define MAX_RANGE   SIZE_MAX
@@ -51,6 +53,7 @@ static OicSecDoxm_t* JSONToDoxmBin(const char * jsonStr);
 static OicSecAcl_t *JSONToAclBin(const char * jsonStr);
 static OicSecAmacl_t* JSONToAmaclBin(const char * jsonStr);
 static OicSecCred_t* JSONToCredBin(const char * jsonStr);
+static OCDeviceProperties* JSONToDPBin(const char *jsonStr);
 
 static size_t GetJSONFileSize(const char *jsonFileName)
 {
@@ -85,8 +88,11 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
     uint8_t *doxmCbor = NULL;
     uint8_t *amaclCbor = NULL;
     uint8_t *credCbor = NULL;
+    uint8_t *dpCbor = NULL;
     cJSON *jsonRoot = NULL;
     OCStackResult ret = OC_STACK_ERROR;
+    OCDeviceProperties *deviceProps = NULL;
+
     size_t size = GetJSONFileSize(jsonFileName);
     if (0 == size)
     {
@@ -103,7 +109,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
         size_t bytesRead = fread(jsonStr, 1, size, fp);
         jsonStr[bytesRead] = '\0';
 
-        OIC_LOG_V(DEBUG, TAG, "Read %zu bytes", bytesRead);
+        OIC_LOG_V(DEBUG, TAG, "Read %" PRIuPTR " bytes", bytesRead);
         fclose(fp);
         fp = NULL;
     }
@@ -129,7 +135,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
             DeleteACLList(acl);
             goto exit;
         }
-        printf("ACL Cbor Size: %zd\n", aclCborSize);
+        printf("ACL Cbor Size: %" PRIuPTR "\n", aclCborSize);
         DeleteACLList(acl);
     }
 
@@ -146,7 +152,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
             DeletePstatBinData(pstat);
             goto exit;
         }
-        printf("PSTAT Cbor Size: %zd\n", pstatCborSize);
+        printf("PSTAT Cbor Size: %" PRIuPTR "\n", pstatCborSize);
         DeletePstatBinData(pstat);
     }
     value = cJSON_GetObjectItem(jsonRoot, OIC_JSON_DOXM_NAME);
@@ -162,7 +168,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
             DeleteDoxmBinData(doxm);
             goto exit;
         }
-        printf("DOXM Cbor Size: %zd\n", doxmCborSize);
+        printf("DOXM Cbor Size: %" PRIuPTR "\n", doxmCborSize);
         DeleteDoxmBinData(doxm);
     }
     value = cJSON_GetObjectItem(jsonRoot, OIC_JSON_AMACL_NAME);
@@ -178,7 +184,7 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
             DeleteAmaclList(amacl);
             goto exit;
         }
-        printf("AMACL Cbor Size: %zd\n", amaclCborSize);
+        printf("AMACL Cbor Size: %" PRIuPTR "\n", amaclCborSize);
         DeleteAmaclList(amacl);
     }
     value = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME);
@@ -196,14 +202,28 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
             DeleteCredList(cred);
             goto exit;
         }
-        printf("CRED Cbor Size: %zd\n", credCborSize);
+        printf("CRED Cbor Size: %" PRIuPTR "\n", credCborSize);
         DeleteCredList(cred);
     }
+    value = cJSON_GetObjectItem(jsonRoot, OC_JSON_DEVICE_PROPS_NAME);
+    size_t dpCborSize = 0;
+    if (NULL != value)
+    {
+        deviceProps = JSONToDPBin(jsonStr);
+        VERIFY_NOT_NULL(TAG, deviceProps, FATAL);
+        ret = DevicePropertiesToCBORPayload(deviceProps, &dpCbor, &dpCborSize);
+        if (OC_STACK_OK != ret)
+        {
+            OIC_LOG(ERROR, TAG, "Failed converting OCDeviceProperties to Cbor Payload");
+            goto exit;
+        }
+        printf("Device Properties Cbor Size: %" PRIuPTR "\n", dpCborSize);
+    }
 
     CborEncoder encoder;
-    size_t cborSize = aclCborSize + pstatCborSize + doxmCborSize + credCborSize + amaclCborSize;
+    size_t cborSize = aclCborSize + pstatCborSize + doxmCborSize + credCborSize + amaclCborSize + dpCborSize;
 
-    printf("Total Cbor Size : %zd\n", cborSize);
+    printf("Total Cbor Size : %" PRIuPTR "\n", cborSize);
     cborSize += 255; // buffer margin for adding map and byte string
     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborSize);
     VERIFY_NOT_NULL(TAG, outPayload, ERROR);
@@ -247,12 +267,19 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
         cborEncoderResult = cbor_encode_byte_string(&map, credCbor, credCborSize);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CRED Value.");
     }
+    if (dpCborSize > 0)
+    {
+        cborEncoderResult = cbor_encode_text_string(&map, OC_JSON_DEVICE_PROPS_NAME, strlen(OC_JSON_DEVICE_PROPS_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Properties Name.");
+        cborEncoderResult = cbor_encode_byte_string(&map, dpCbor, dpCborSize);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Properties Value.");
+    }
 
     cborEncoderResult = cbor_encoder_close_container(&encoder, &map);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Container.");
 
     size_t s = cbor_encoder_get_buffer_size(&encoder, outPayload);
-    OIC_LOG_V(DEBUG, TAG, "Payload size %zu", s);
+    OIC_LOG_V(DEBUG, TAG, "Payload size %" PRIuPTR, s);
 
     fp1 = fopen(cborFileName, "w");
     if (fp1)
@@ -260,11 +287,11 @@ static void ConvertJsonToCBOR(const char *jsonFileName, const char *cborFileName
         size_t bytesWritten = fwrite(outPayload, 1, s, fp1);
         if (bytesWritten == s)
         {
-            OIC_LOG_V(DEBUG, TAG, "Written %zu bytes", bytesWritten);
+            OIC_LOG_V(DEBUG, TAG, "Written %" PRIuPTR " bytes", bytesWritten);
         }
         else
         {
-            OIC_LOG_V(ERROR, TAG, "Failed writing %zu bytes", s);
+            OIC_LOG_V(ERROR, TAG, "Failed writing %" PRIuPTR " bytes", s);
         }
         fclose(fp1);
         fp1 = NULL;
@@ -278,7 +305,9 @@ exit:
     OICFree(amaclCbor);
     OICFree(credCbor);
     OICFree(jsonStr);
-    return ;
+    OICFree(dpCbor);
+    CleanUpDeviceProperties(&deviceProps);
+    return;
 }
 
 OicSecAcl_t* JSONToAclBin(const char * jsonStr)
@@ -1036,6 +1065,48 @@ exit:
     return headAmacl;
 }
 
+OCDeviceProperties* JSONToDPBin(const char *jsonStr)
+{
+    OIC_LOG(DEBUG, TAG, "JSONToDPBin IN");
+    if (NULL == jsonStr)
+    {
+        return NULL;
+    }
+
+    OCStackResult ret = OC_STACK_ERROR;
+    OCDeviceProperties *deviceProps = NULL;
+    cJSON *jsonDeviceProps = NULL;
+    cJSON *jsonObj = NULL;
+
+    cJSON *jsonRoot = cJSON_Parse(jsonStr);
+    VERIFY_NOT_NULL(TAG, jsonRoot, ERROR);
+
+    jsonDeviceProps = cJSON_GetObjectItem(jsonRoot, OC_JSON_DEVICE_PROPS_NAME);
+    VERIFY_NOT_NULL(TAG, jsonDeviceProps, ERROR);
+
+    deviceProps = (OCDeviceProperties*)OICCalloc(1, sizeof(OCDeviceProperties));
+    VERIFY_NOT_NULL(TAG, deviceProps, ERROR);
+
+    // Protocol Independent ID -- Mandatory
+    jsonObj = cJSON_GetObjectItem(jsonDeviceProps, OC_RSRVD_PROTOCOL_INDEPENDENT_ID);
+    if (jsonObj && (cJSON_String == jsonObj->type))
+    {
+        OICStrcpy(deviceProps->protocolIndependentId, UUID_STRING_SIZE, jsonObj->valuestring);
+    }
+
+    ret = OC_STACK_OK;
+
+exit:
+    cJSON_Delete(jsonRoot);
+    if (OC_STACK_OK != ret)
+    {
+        CleanUpDeviceProperties(&deviceProps);
+    }
+    OIC_LOG_V(DEBUG, TAG, "OUT %s: %s\n", __func__, (deviceProps != NULL) ? "success" : "failure");
+
+    return deviceProps;
+}
+
 int main(int argc, char* argv[])
 {
     if (argc == 3)
index b6ebb49..09594fa 100644 (file)
@@ -48,6 +48,16 @@ extern "C" {
 #define OC_RESOURCE_SECURE       1
 
 /**
+ * Device properties persistent store name.
+ */
+#define OC_DEVICE_PROPS_FILE_NAME  "device_properties.dat"
+
+/**
+ * Device properties name
+ */
+#define OC_JSON_DEVICE_PROPS_NAME "DeviceProperties"
+
+/**
  *  OIC Virtual resources supported by every OIC device.
  */
 typedef enum
@@ -215,6 +225,47 @@ OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
  */
 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult);
 
+/**
+ * Data structure for holding enhanced device information
+ */
+typedef struct _OCDeviceProperties
+{
+    /** Protocol Independent Id.*/
+    char protocolIndependentId[UUID_STRING_SIZE];
+} OCDeviceProperties;
+
+/**
+ * Internal API used to initialize device properties.
+ * @return ::OC_STACK_OK for Success, otherwise some error value
+ */
+OCStackResult InitializeDeviceProperties();
+
+/**
+ * Internal API used to clean up device properties.
+ * @param deviceProperties Pointer to OCDeviceProperties to clean up.
+ */
+void CleanUpDeviceProperties(OCDeviceProperties **deviceProperties);
+
+/**
+ * This method converts OCDeviceProperties into CBOR format.
+ * @param deviceProperties   Pointer to OCDeviceProperties to convert to CBOR.
+ * @param payload            JSON payload converted to CBOR. Passed parameter should not be NULL.
+ * @note Caller needs to invoke OICFree when they are finished using the returned string.
+ * @param size               Size of the cbor payload. Passed parameter should not be NULL.
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ */
+OCStackResult DevicePropertiesToCBORPayload(const OCDeviceProperties *deviceProperties, uint8_t **payload, size_t *size);
+
+/**
+ * This method converts CBOR data into OCDeviceProperties format.
+ * @param payload            CBOR payload to convert to OCDeviceProperties.
+ * @param size               Size of the cborPayload.
+ * @param deviceProperties   CBOR payload converted to OCDeviceProperties. Passed parameter should not be NULL.
+ * @note Caller needs to invoke CleanUpDeviceProperties after they are finished using the returned pointer.
+ * @return ::OC_STACK_OK for Success, otherwise some error value.
+ */
+OCStackResult CBORPayloadToDeviceProperties(const uint8_t *payload, size_t size, OCDeviceProperties **deviceProperties);
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
index d8854bb..ac02a55 100644 (file)
@@ -80,6 +80,9 @@ sample_build_dir = samples_env.get(
 introspectionJson = samples_env.Install(sample_build_dir,
                                         sample_src_dir + 'introspection.json')
 
+deviceProperties = samples_env.Install(sample_build_dir,
+                                       sample_src_dir + 'device_properties.dat')
+
 
 ######################################################################
 # Source files and Targets
diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.dat b/resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.dat
new file mode 100644 (file)
index 0000000..623be7e
--- /dev/null
@@ -0,0 +1 @@
+¿pDevicePropertiesX-¿dpiidx$a127ec9c-b1af-430e-ad6f-8e069a7cae3bÿÿ
\ No newline at end of file
diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.json b/resource/csdk/stack/samples/linux/SimpleClientServer/device_properties.json
new file mode 100644 (file)
index 0000000..bc68caf
--- /dev/null
@@ -0,0 +1,5 @@
+{
+    "DeviceProperties": {
+        "piid": "a127ec9c-b1af-430e-ad6f-8e069a7cae3b"
+    }
+}
index c16d8a1..3b5db32 100755 (executable)
@@ -55,6 +55,8 @@
 #include "ocendpoint.h"
 #include "ocstackinternal.h"
 #include "oickeepalive.h"
+#include "ocpayloadcbor.h"
+#include "psinterface.h"
 
 #ifdef ROUTING_GATEWAY
 #include "routingmanager.h"
 /// Module Name
 #define TAG "OIC_RI_RESOURCE"
 
-// using 1k as block size since most persistent storage implementations use a power of 2.
-#define INTROSPECTION_FILE_SIZE_BLOCK 1024
+// Using 1k as block size since most persistent storage implementations use a power of 2.
+#define INTROSPECTION_FILE_SIZE_BLOCK  1024
 
 #define VERIFY_SUCCESS(op) { if (op != (OC_STACK_OK)) \
             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
 
+/**
+ * Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+ * The value of payload size is increased up to CBOR_MAX_SIZE.
+ */
+static const uint16_t CBOR_SIZE = 512;
+
+/**
+ * Max cbor size payload.
+ */
+static const uint16_t CBOR_MAX_SIZE = 4400;
+
 extern OCResource *headResource;
 
 /**
@@ -80,6 +93,14 @@ static OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
                                                   CAEndpoint_t *networkInfo,
                                                   size_t infoSize);
 
+/**
+ * Sets the value of an attribute on a resource.
+ */
+static OCStackResult SetAttributeInternal(OCResource *resource,
+                                          const char *attribute,
+                                          const void *value,
+                                          bool updateDatabase);
+
 //-----------------------------------------------------------------------------
 // Default resource entity handler function
 //-----------------------------------------------------------------------------
@@ -488,6 +509,390 @@ OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
     return OC_STACK_OK;
 }
 
+void CleanUpDeviceProperties(OCDeviceProperties **deviceProperties)
+{
+    if (!deviceProperties || !(*deviceProperties))
+    {
+        return;
+    }
+
+    OICFreeAndSetToNull((void**)(deviceProperties));
+}
+
+static OCStackResult CreateDeviceProperties(const char *piid, OCDeviceProperties **deviceProperties)
+{
+    OIC_LOG(DEBUG, TAG, "CreateDeviceProperties IN");
+
+    OCStackResult result = OC_STACK_OK;
+
+    if (!piid || !deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = (OCDeviceProperties*)OICCalloc(1, sizeof(OCDeviceProperties));
+    if (*deviceProperties)
+    {
+        OICStrcpy((*deviceProperties)->protocolIndependentId, UUID_STRING_SIZE, piid);
+    }
+    else
+    {
+        result = OC_STACK_NO_MEMORY;
+    }
+
+    OIC_LOG(DEBUG, TAG, "CreateDeviceProperties OUT");
+
+    return result;
+}
+
+static OCStackResult GenerateDeviceProperties(OCDeviceProperties **deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    OicUuid_t generatedProtocolIndependentId = {.id = {0}};
+    char* protocolIndependentId = NULL;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = NULL;
+
+    // Generate a UUID for the Protocol Independent ID
+    if (OCGenerateUuid(generatedProtocolIndependentId.id))
+    {
+        protocolIndependentId = (char*)OICCalloc(UUID_STRING_SIZE, sizeof(char));
+        if (protocolIndependentId)
+        {
+            if (!OCConvertUuidToString(generatedProtocolIndependentId.id, protocolIndependentId))
+            {
+                OIC_LOG(ERROR, TAG, "ConvertUuidToStr failed");
+                result = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            result = OC_STACK_NO_MEMORY;
+        }
+    }
+    else
+    {
+        OIC_LOG(FATAL, TAG, "Generate UUID for Device Properties Protocol Independent ID failed!");
+        result = OC_STACK_ERROR;
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        result = CreateDeviceProperties(protocolIndependentId, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&protocolIndependentId);
+
+    return result;
+}
+
+OCStackResult CBORPayloadToDeviceProperties(const uint8_t *payload, size_t size, OCDeviceProperties **deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    CborError cborResult = CborNoError;
+    char* protocolIndependentId = NULL;
+    CborParser parser;
+    CborValue dpCbor;
+    CborValue dpMap;
+
+    if (!payload || (size <= 0) || !deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = NULL;
+
+    cbor_parser_init(payload, size, 0, &parser, &dpCbor);
+
+    // Protocol Independent ID - Mandatory
+    cborResult = cbor_value_map_find_value(&dpCbor, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &dpMap);
+    if ((CborNoError == cborResult) && cbor_value_is_text_string(&dpMap))
+    {
+        size_t len = 0;
+
+        cborResult = cbor_value_dup_text_string(&dpMap, &protocolIndependentId, &len, NULL);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to get Protocol Independent Id!");
+            result = OC_STACK_ERROR;
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Protocol Independent Id is not present or invalid!");
+        result = OC_STACK_ERROR;
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        result = CreateDeviceProperties(protocolIndependentId, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&protocolIndependentId);
+
+    return result;
+}
+
+OCStackResult DevicePropertiesToCBORPayload(const OCDeviceProperties *deviceProperties, uint8_t **payload, size_t *size)
+{
+    OCStackResult result = OC_STACK_OK;
+    CborError cborResult = CborNoError;
+    uint8_t *cborPayload = NULL;
+    size_t cborLen = CBOR_SIZE;
+    CborEncoder encoder;
+    CborEncoder dpMap;
+
+    if (!deviceProperties || !payload || !size || (*size > CBOR_MAX_SIZE))
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    // Reset the CBOR length if we need to
+    if (*size > 0)
+    {
+        cborLen = *size;
+    }
+
+    *payload = NULL;
+    *size = 0;
+
+    cborPayload = (uint8_t*)OICCalloc(1, cborLen);
+    if (NULL != cborPayload)
+    {
+        cbor_encoder_init(&encoder, cborPayload, cborLen, 0);
+
+        // Create the Device Properties encoder map
+        cborResult = cbor_encoder_create_map(&encoder, &dpMap, CborIndefiniteLength);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to create encoder map!");
+            result = OC_STACK_ERROR;
+        }
+    }
+    else
+    {
+        result = OC_STACK_NO_MEMORY;
+    }
+
+    // Protocol Independent ID - Mandatory
+    if (OC_STACK_OK == result)
+    {
+        cborResult = cbor_encode_text_string(&dpMap, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, strlen(OC_RSRVD_PROTOCOL_INDEPENDENT_ID));
+        if (CborNoError == cborResult)
+        {
+            cborResult = cbor_encode_text_string(&dpMap,
+                                                 deviceProperties->protocolIndependentId,
+                                                 strlen(deviceProperties->protocolIndependentId));
+            if (CborNoError != cborResult)
+            {
+                OIC_LOG(ERROR, TAG, "Failed to encode protocolIndependentId!");
+                result = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Failed to encode OC_RSRVD_PROTOCOL_INDEPENDENT_ID!");
+            result = OC_STACK_ERROR;
+        }
+    }
+
+    // Encoding is finished
+    if (OC_STACK_OK == result)
+    {
+        cborResult = cbor_encoder_close_container(&encoder, &dpMap);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to close dpMap container!");
+            result = OC_STACK_ERROR;
+        }
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        *size = cbor_encoder_get_buffer_size(&encoder, cborPayload);
+        *payload = cborPayload;
+        cborPayload = NULL;
+    }
+    else if ((CborErrorOutOfMemory == cborResult) && (cborLen < CBOR_MAX_SIZE))
+    {
+        OICFreeAndSetToNull((void**)&cborPayload);
+
+        // Realloc and try again
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+        result = DevicePropertiesToCBORPayload(deviceProperties, payload, &cborLen);
+        if (OC_STACK_OK == result)
+        {
+            *size = cborLen;
+        }
+    }
+    else
+    {
+        OICFreeAndSetToNull((void**)&cborPayload);
+    }
+
+    return result;
+}
+
+static OCStackResult UpdateDeviceInfoResourceWithDeviceProperties(const OCDeviceProperties *deviceProperties, bool updateDatabase)
+{
+    OCStackResult result = OC_STACK_OK;
+    OCResource *resource = NULL;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
+    if (resource)
+    {
+        result = SetAttributeInternal(resource, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, deviceProperties->protocolIndependentId, updateDatabase);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "OCSetPropertyValue failed to set Protocol Independent ID");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Resource does not exist.");
+        result = OC_STACK_NO_RESOURCE;
+    }
+
+    return result;
+}
+
+static OCStackResult ReadDevicePropertiesFromDatabase(OCDeviceProperties **deviceProperties)
+{
+    uint8_t *data = NULL;
+    size_t size = 0;
+
+    OCStackResult result = ReadDatabaseFromPS(OC_DEVICE_PROPS_FILE_NAME, OC_JSON_DEVICE_PROPS_NAME, &data, &size);
+    if (OC_STACK_OK == result)
+    {
+        // Read device properties from PS
+        result = CBORPayloadToDeviceProperties(data, size, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(WARNING, TAG, "CBORPayloadToDeviceProperties failed");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "ReadDatabaseFromPS failed");
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&data);
+
+    return result;
+}
+
+static OCStackResult UpdateDevicePropertiesDatabase(const OCDeviceProperties *deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    uint8_t *payload = NULL;
+    size_t size = 0;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    // Check to see if persistent storage exists. If it doesn't then
+    // we just allow the device properties to exist in memory and
+    // it is the application's job to manage them.
+    if (!OCGetPersistentStorageHandler())
+    {
+        OIC_LOG(DEBUG, TAG, "Persistent Storage handler is NULL.");
+        return OC_STACK_OK;
+    }
+
+    // Convert OCDeviceProperties into CBOR to use for updating Persistent Storage
+    result = DevicePropertiesToCBORPayload(deviceProperties, &payload, &size);
+    if ((OC_STACK_OK == result) && payload)
+    {
+        result = UpdateResourceInPS(OC_DEVICE_PROPS_FILE_NAME, OC_JSON_DEVICE_PROPS_NAME, payload, size);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG_V(ERROR, TAG, "UpdateResourceInPS failed with %d!", result);
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "DevicePropertiesToCBORPayload failed with %d!", result);
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&payload);
+
+    return result;
+}
+
+OCStackResult InitializeDeviceProperties()
+{
+    OIC_LOG(DEBUG, TAG, "InitializeDeviceProperties IN");
+
+    OCStackResult result = OC_STACK_OK;
+    OCDeviceProperties *deviceProperties = NULL;
+    bool updateDatabase = false;
+
+    // Populate OCDeviceProperties from persistent storage
+    result = ReadDevicePropertiesFromDatabase(&deviceProperties);
+    if (OC_STACK_OK != result)
+    {
+        OIC_LOG(ERROR, TAG, "ReadDevicePropertiesFromDatabase failed");
+    }
+
+    // If the device properties in persistent storage are corrupted or
+    // not available for some reason, a default OCDeviceProperties is created.
+    if ((OC_STACK_OK != result) || !deviceProperties)
+    {
+        result = GenerateDeviceProperties(&deviceProperties);
+        if (OC_STACK_OK == result)
+        {
+            updateDatabase = true;
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "GenerateDeviceProperties failed");
+        }
+    }
+
+    // Set the device properties information on the device info resource. This will
+    // also persist OCDeviceProperties so they can be used in the future if they are
+    // not already in the database.
+    if (OC_STACK_OK == result)
+    {
+        result = UpdateDeviceInfoResourceWithDeviceProperties(deviceProperties, updateDatabase);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "UpdateDeviceInfoResourceWithDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    CleanUpDeviceProperties(&deviceProperties);
+
+    OIC_LOG(DEBUG, TAG, "InitializeDeviceProperties OUT");
+
+    return result;
+}
+
 static size_t GetIntrospectionDataSize(const OCPersistentStorage *ps)
 {
     size_t size = 0;
@@ -2043,10 +2448,14 @@ OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **va
     return res;
 }
 
-OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const void* value)
+static OCStackResult SetAttributeInternal(OCResource *resource,
+                                          const char *attribute,
+                                          const void *value,
+                                          bool updateDatabase)
 {
-    // See if the attribute already exists in the list.
     OCAttribute *resAttrib = NULL;
+
+    // See if the attribute already exists in the list.
     for (resAttrib = resource->rsrcAttributes; resAttrib; resAttrib = resAttrib->next)
     {
         if (0 == strcmp(attribute, resAttrib->attrName))
@@ -2086,12 +2495,96 @@ OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const
     }
     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrValue, "Failed allocating attribute value");
 
+    // The resource has changed from what is stored in the database. Update the database to
+    // reflect the new value.
+    if (updateDatabase)
+    {
+        OCDeviceProperties *deviceProperties = NULL;
+
+        OCStackResult result = CreateDeviceProperties((const char*)value, &deviceProperties);
+        if (OC_STACK_OK == result)
+        {
+            result = UpdateDevicePropertiesDatabase(deviceProperties);
+            if (OC_STACK_OK != result)
+            {
+                OIC_LOG(ERROR, TAG, "UpdateDevicePropertiesDatabase failed!");
+            }
+
+            CleanUpDeviceProperties(&deviceProperties);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed!");
+        }
+    }
+
     return OC_STACK_OK;
 
 exit:
     OCDeleteResourceAttributes(resAttrib);
     return OC_STACK_NO_MEMORY;
+}
+
+static OCStackResult IsDatabaseUpdateNeeded(const char *attribute, const void *value, bool *update)
+{
+    OCStackResult result = OC_STACK_OK;
+    void *currentPIID = NULL;
+
+    if (!attribute || !value || !update)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *update = false;
+
+    // Protocol Independent ID
+    if (0 == strcmp(OC_RSRVD_PROTOCOL_INDEPENDENT_ID, attribute))
+    {
+        result = OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &currentPIID);
+        if (OC_STACK_OK == result)
+        {
+            // PIID has already been set on the resource and stored in the database. Check to see
+            // if the value is changing so the database can be updated accordingly.
+            if (0 != strcmp((char *)currentPIID, (char*)value))
+            {
+                *update = true;
+            }
+        }
+        else if (OC_STACK_NO_RESOURCE == result)
+        {
+            // PIID has not been set yet so we should always update the database.
+            *update = true;
+            result = OC_STACK_OK;
+        }
+        else
+        {
+            OIC_LOG_V(ERROR, TAG, 
+                "Call to OCGetPropertyValue for the current PIID failed with error: %d", result);
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull(&currentPIID);
+
+    return result;
+}
+
+OCStackResult OCSetAttribute(OCResource *resource, const char *attribute, const void *value)
+{
+    bool updateDatabase = false;
+
+    // Check to see if we also need to update the database for this attribute. If the current
+    // value matches what is stored in the database we can skip the update and an unnecessary
+    // write.
+    if (OC_STACK_OK != IsDatabaseUpdateNeeded(attribute, value, &updateDatabase))
+    {
+        OIC_LOG_V(WARNING, TAG, 
+            "Could not determine if a database update was needed for %s. Proceeding without updating the database.",
+            attribute);
+        updateDatabase = false;
+    }
 
+    return SetAttributeInternal(resource, attribute, value, updateDatabase);
 }
 
 OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const void *value)
index 92c311f..fe0ca73 100644 (file)
@@ -4870,6 +4870,12 @@ OCStackResult initResources()
         }
     }
 
+    // Initialize Device Properties
+    if (OC_STACK_OK == result)
+    {
+        result = InitializeDeviceProperties();
+    }
+
     return result;
 }
 
index 031af22..97919ac 100644 (file)
@@ -28,6 +28,7 @@ extern "C"
     #include "oic_malloc.h"
     #include "oic_string.h"
     #include "oic_time.h"
+    #include "ocresourcehandler.h"
 }
 
 #include "gtest/gtest.h"
@@ -65,6 +66,7 @@ namespace itst = iotivity::test;
 static const char TAG[] = "TestHarness";
 
 char gDeviceUUID[] = "fe3f9a68-4931-4cb0-9ea4-81702b43116c";
+char gDevicePIID[] = "32684bf3-4c44-47b0-99fe-6a9a59b73a8d";
 char gManufacturerName[] = "myName";
 static OCPrm_t pmSel;
 static char pinNumber;
@@ -181,6 +183,17 @@ uint8_t InitResourceIndex()
 
 extern "C" uint32_t g_ocStackStartCount;
 
+OCDeviceProperties* getTestDeviceProps()
+{
+    OCDeviceProperties* deviceProps = (OCDeviceProperties*)OICCalloc(1, sizeof(OCDeviceProperties));
+    if (NULL != deviceProps)
+    {
+        OICStrcpy(deviceProps->protocolIndependentId, UUID_STRING_SIZE, gDevicePIID);
+    }
+
+    return deviceProps;
+}
+
 class OCDiscoverTests : public testing::Test
 {
     protected:
@@ -194,6 +207,15 @@ class OCDiscoverTests : public testing::Test
             OCStop();
         }
 };
+
+class OCDevicePropertiesTests : public testing::Test
+{
+protected:
+    virtual void SetUp()
+    {
+        itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
+    }
+};
 //-----------------------------------------------------------------------------
 //  Tests
 //-----------------------------------------------------------------------------
@@ -1368,6 +1390,147 @@ TEST(StackResource, StackTestResourceDiscoverManyResources)
     EXPECT_EQ(OC_STACK_OK, OCStop());
 }
 
+TEST_F(OCDevicePropertiesTests, DevicePropertiesToCBORPayloadllNULL)
+{
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, DevicePropertiesToCBORPayload(NULL, NULL, NULL));
+}
+
+TEST_F(OCDevicePropertiesTests, DevicePropertiesToCBORPayloadNULLPayload)
+{
+    OCDeviceProperties* deviceProps = getTestDeviceProps();
+    ASSERT_TRUE(NULL != deviceProps);
+    size_t size = 0;
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, DevicePropertiesToCBORPayload(deviceProps, NULL, &size));
+
+    CleanUpDeviceProperties(&deviceProps);
+}
+
+TEST_F(OCDevicePropertiesTests, DevicePropertiesToCBORPayloadNULLSize)
+{
+    OCDeviceProperties* deviceProps = getTestDeviceProps();
+    ASSERT_TRUE(NULL != deviceProps);
+    uint8_t* payload = NULL;
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, DevicePropertiesToCBORPayload(deviceProps, &payload, NULL));
+
+    CleanUpDeviceProperties(&deviceProps);
+}
+
+TEST_F(OCDevicePropertiesTests, DevicePropertiesToCBORPayloadNULLDeviceProperties)
+{
+    uint8_t* payload = NULL;
+    size_t size = 0;
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, DevicePropertiesToCBORPayload(NULL, &payload, &size));
+}
+
+TEST_F(OCDevicePropertiesTests, DevicePropertiesToCBORPayloadVALID)
+{
+    OCDeviceProperties* deviceProps = getTestDeviceProps();
+    ASSERT_TRUE(NULL != deviceProps);
+    uint8_t* payload = NULL;
+    size_t size = 0;
+
+    EXPECT_EQ(OC_STACK_OK, DevicePropertiesToCBORPayload(deviceProps, &payload, &size));
+    EXPECT_TRUE(payload != NULL);
+
+    CleanUpDeviceProperties(&deviceProps);
+    OICFree(payload);
+}
+
+TEST_F(OCDevicePropertiesTests, CBORPayloadToDevicePropertiesAllNULL)
+{
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, CBORPayloadToDeviceProperties(NULL, 0, NULL));
+}
+
+TEST_F(OCDevicePropertiesTests, CBORPayloadToDevicePropertiesNULLPayload)
+{
+    OCDeviceProperties* deviceProps = NULL;
+    size_t size = 10;
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, CBORPayloadToDeviceProperties(NULL, size, &deviceProps));
+}
+
+TEST_F(OCDevicePropertiesTests, CBORPayloadToDevicePropertiesInvalidSize)
+{
+    OCDeviceProperties* deviceProps = NULL;
+    uint8_t* payload = (uint8_t*)OICCalloc(1, sizeof(uint8_t));
+    ASSERT_TRUE(NULL != payload);
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, CBORPayloadToDeviceProperties(payload, 0, &deviceProps));
+
+    OICFree(payload);
+}
+
+TEST_F(OCDevicePropertiesTests, CBORPayloadToDevicePropertiesNULLDeviceProperties)
+{
+    uint8_t* payload = (uint8_t*)OICCalloc(1, sizeof(uint8_t));
+    ASSERT_TRUE(NULL != payload);
+    size_t size = 10;
+
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, CBORPayloadToDeviceProperties(payload, size, NULL));
+
+    OICFree(payload);
+}
+
+TEST_F(OCDevicePropertiesTests, CBORPayloadToDevicePropertiesVALID)
+{
+    OCDeviceProperties* controlDeviceProps = getTestDeviceProps();
+    ASSERT_TRUE(NULL != controlDeviceProps);
+    OCDeviceProperties* testDeviceProps = NULL;
+    uint8_t* payload = NULL;
+    size_t size = 0;
+
+    EXPECT_EQ(OC_STACK_OK, DevicePropertiesToCBORPayload(controlDeviceProps, &payload, &size));
+    EXPECT_TRUE(payload != NULL);
+
+    EXPECT_EQ(OC_STACK_OK, CBORPayloadToDeviceProperties(payload, size, &testDeviceProps));
+    ASSERT_TRUE(testDeviceProps != NULL);
+    EXPECT_STREQ(gDevicePIID, testDeviceProps->protocolIndependentId);
+
+    CleanUpDeviceProperties(&controlDeviceProps);
+    CleanUpDeviceProperties(&testDeviceProps);
+    OICFree(payload);
+}
+
+TEST_F(OCDevicePropertiesTests, PIIDAvailableAfterInit)
+{
+    void *piid = NULL;
+
+    InitStack(OC_SERVER);
+
+    EXPECT_EQ(OC_STACK_OK, OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &piid));
+    ASSERT_TRUE(piid != NULL);
+
+    OICFree(piid);
+
+    EXPECT_EQ(OC_STACK_OK, OCStop());
+}
+
+TEST_F(OCDevicePropertiesTests, UpdatePIID)
+{
+    void *originalPIID = NULL;
+    void *newPIID = NULL;
+
+    InitStack(OC_SERVER);
+
+    EXPECT_EQ(OC_STACK_OK, OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &originalPIID));
+    ASSERT_TRUE(originalPIID != NULL);
+
+    EXPECT_EQ(OC_STACK_OK, OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, gDevicePIID));
+
+    EXPECT_EQ(OC_STACK_OK, OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &newPIID));
+    ASSERT_TRUE(newPIID != NULL);
+    EXPECT_STREQ(gDevicePIID, (char *)newPIID);
+    EXPECT_STRNE((char *)originalPIID, (char *)newPIID);
+
+    OICFree(newPIID);
+    OICFree(originalPIID);
+
+    EXPECT_EQ(OC_STACK_OK, OCStop());
+}
+
 TEST(StackBind, BindResourceTypeNameBad)
 {
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);