Versioning feature implementation.
authorZiran Sun <ziran.sun@samsung.com>
Tue, 22 Nov 2016 16:26:22 +0000 (16:26 +0000)
committerZiran Sun <ziran.sun@samsung.com>
Fri, 3 Feb 2017 08:47:18 +0000 (08:47 +0000)
1. Introduce in new Content Type application/vnd.ocf+cbor
2. Introduce in option headers Accept Version and Content-Format Version
3. Handle versioning at CA and RI layers
4. Expose the result of version handling to application layer
5. Add test codes at CA, RI and application layers

Bug: https://jira.iotivity.org/browse/IOT-1735
Change-Id: I9924881f6233b4c4f5af9d50098cd48ef258a753
Signed-off-by: Ziran Sun <ziran.sun@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/16505
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Abhishek Sharma <ce.abhishek@samsung.com>
Reviewed-by: jihwan seo <jihwan.seo@samsung.com>
17 files changed:
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/common/src/caremotehandler.c
resource/csdk/connectivity/inc/caprotocolmessage.h
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/connectivity/test/caprotocolmessagetest.cpp
resource/csdk/include/octypes.h
resource/csdk/routing/src/routingmanagerinterface.c
resource/csdk/stack/include/internal/ocobserve.h
resource/csdk/stack/include/internal/ocserverrequest.h
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/samples/linux/SimpleClientServer/common.cpp
resource/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp
resource/csdk/stack/samples/linux/SimpleClientServer/occlient.h
resource/csdk/stack/src/ocobserve.c
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocserverrequest.c
resource/csdk/stack/src/ocstack.c

index bf99f27..8b6ab8b 100755 (executable)
@@ -129,6 +129,19 @@ extern "C"
 #define CA_OPTION_LOCATION_QUERY 20
 
 /**
+* TODO: Move these COAP defines to CoAP lib once approved.
+*/
+#define COAP_OPTION_ACCEPT_VERSION 2049
+#define COAP_OPTION_CONTENT_VERSION 2053
+#define COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR 10000 // application/vnd.ocf+cbor
+
+#define CA_OPTION_ACCEPT_VERSION 2049
+#define CA_OPTION_CONTENT_VERSION 2053
+
+#define DEFAULT_ACCEPT_VERSION_VALUE 2048   // OCF version 1.0.0
+#define DEFAULT_CONTENT_VERSION_VALUE 2048  // OCF version 1.0.0
+
+/**
  * Payload information from resource model.
  */
 typedef uint8_t *CAPayload_t;
@@ -411,6 +424,7 @@ typedef enum
     CA_FORMAT_APPLICATION_EXI,
     CA_FORMAT_APPLICATION_JSON,
     CA_FORMAT_APPLICATION_CBOR,
+    CA_FORMAT_APPLICATION_VND_OCF_CBOR,
     CA_FORMAT_UNSUPPORTED
 } CAPayloadFormat_t;
 
@@ -451,6 +465,8 @@ typedef struct
     size_t payloadSize;         /**< size in bytes of the payload */
     CAPayloadFormat_t payloadFormat;    /**< encoding format of the request payload */
     CAPayloadFormat_t acceptFormat;     /**< accept format for the response payload */
+    uint16_t payloadVersion;    /**< version of the payload */
+    uint16_t acceptVersion;     /**< expected version for the response payload */
     CAURI_t resourceUri;        /**< Resource URI information **/
     CARemoteId_t identity;      /**< endpoint identity */
     CADataType_t dataType;      /**< data type */
index 3df579d..8ef9d52 100644 (file)
@@ -297,6 +297,8 @@ CAResult_t CACloneInfo(const CAInfo_t *info, CAInfo_t *clone)
     }
     clone->payloadFormat = info->payloadFormat;
     clone->acceptFormat = info->acceptFormat;
+    clone->payloadVersion = info->payloadVersion;
+    clone->acceptVersion = info->acceptVersion;
 
     if (info->resourceUri)
     {
index cc31ccc..e24a204 100644 (file)
@@ -136,6 +136,21 @@ CAResult_t CAParseUriPartial(const unsigned char *str, size_t length, int target
 CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **optlist);
 
 /**
+ * Helper to parse content format and accept format header options
+ * and populate the supplied options list.
+ *
+ * @param[in]   format               content or accept format.
+ * @param[in]   formatOption         CoAP format header option.
+ * @param[in]   versionOption        CoAP version header option.
+ * @param[in]   version              value of version.
+ * @param[out]  optlist              options information.
+ * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
+ */
+
+CAResult_t CAParsePayloadFormatHeadOption(CAPayloadFormat_t format, uint16_t formatOption,
+        uint16_t versionOption, uint16_t version, coap_list_t **optlist);
+
+/**
  * creates option node from key length and data.
  * @param[in]   key                  key for the that needs to be sent.
  * @param[in]   length               length of the data that needs to be sent.
@@ -248,7 +263,7 @@ CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size);
  * @param[in]   format              coap format code.
  * @return format.
  */
-CAPayloadFormat_t CAConvertFormat(uint8_t format);
+CAPayloadFormat_t CAConvertFormat(uint16_t format);
 
 #ifdef WITH_TCP
 /**
index a0451a4..64f0acb 100644 (file)
@@ -551,61 +551,81 @@ CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **
     // insert one extra header with the payload format if applicable.
     if (CA_FORMAT_UNDEFINED != info->payloadFormat)
     {
-        coap_list_t* node = NULL;
-        uint8_t buf[CA_ENCODE_BUFFER_SIZE] = {0};
-        switch (info->payloadFormat)
-        {
-            case CA_FORMAT_APPLICATION_CBOR:
-                node = CACreateNewOptionNode(
-                        COAP_OPTION_CONTENT_FORMAT,
-                        coap_encode_var_bytes(buf, (unsigned short)COAP_MEDIATYPE_APPLICATION_CBOR),
-                        (char *)buf);
-                break;
-            default:
-                OIC_LOG_V(ERROR, TAG, "Content format option:[%d] not supported", info->payloadFormat);
-        }
-        if (!node)
-        {
-            OIC_LOG(ERROR, TAG, "Content format option not created");
-            return CA_STATUS_INVALID_PARAM;
-        }
-        int ret = coap_insert(optlist, node, CAOrderOpts);
-        if (ret <= 0)
-        {
-            coap_delete(node);
-            OIC_LOG(ERROR, TAG, "Content format option not inserted in header");
-            return CA_STATUS_INVALID_PARAM;
-        }
+        CAParsePayloadFormatHeadOption(info->payloadFormat, COAP_OPTION_CONTENT_FORMAT, COAP_OPTION_CONTENT_VERSION, info->payloadVersion, optlist);
     }
+
     if (CA_FORMAT_UNDEFINED != info->acceptFormat)
     {
-        coap_list_t* node = NULL;
-        uint8_t buf[CA_ENCODE_BUFFER_SIZE] = {0};
-        switch (info->acceptFormat)
+        CAParsePayloadFormatHeadOption(info->acceptFormat, COAP_OPTION_ACCEPT, info->acceptVersion, COAP_OPTION_ACCEPT_VERSION, optlist);
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAParsePayloadFormatHeadOption(CAPayloadFormat_t format, uint16_t formatOption,
+        uint16_t versionOption, uint16_t version, coap_list_t **optlist)
+{
+    coap_list_t* encodeNode = NULL;
+    coap_list_t* versionNode = NULL;
+    uint8_t encodeBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
+    uint8_t versionBuf[CA_ENCODE_BUFFER_SIZE] = { 0 };
+
+    switch (format)
+    {
+        case CA_FORMAT_APPLICATION_CBOR:
+            encodeNode = CACreateNewOptionNode(formatOption,
+                    coap_encode_var_bytes(encodeBuf,
+                            (unsigned short) COAP_MEDIATYPE_APPLICATION_CBOR), (char *) encodeBuf);
+            break;
+        case CA_FORMAT_APPLICATION_VND_OCF_CBOR:
+            encodeNode = CACreateNewOptionNode(formatOption,
+                    coap_encode_var_bytes(encodeBuf,
+                            (unsigned short) COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR),
+                    (char *) encodeBuf);
+            // Include payload version information for this format.
+            versionNode = CACreateNewOptionNode(versionOption,
+                    coap_encode_var_bytes(versionBuf, version), (char *) versionBuf);
+            break;
+        default:
+            OIC_LOG_V(ERROR, TAG, "Format option:[%d] not supported", format);
+    }
+    if (!encodeNode)
+    {
+        OIC_LOG(ERROR, TAG, "Format option not created");
+        return CA_STATUS_INVALID_PARAM;
+    }
+    int ret = coap_insert(optlist, encodeNode, CAOrderOpts);
+    if (0 >= ret)
+    {
+        coap_delete(encodeNode);
+        OIC_LOG(ERROR, TAG, "Format option not inserted in header");
+        if (CA_FORMAT_APPLICATION_VND_OCF_CBOR == format && versionNode)
         {
-            case CA_FORMAT_APPLICATION_CBOR:
-                node = CACreateNewOptionNode(
-                        COAP_OPTION_ACCEPT,
-                        coap_encode_var_bytes(buf, (unsigned short)COAP_MEDIATYPE_APPLICATION_CBOR),
-                        (char *)buf);
-                break;
-            default:
-                OIC_LOG_V(ERROR, TAG, "Accept format option:[%d] not supported", info->acceptFormat);
+            coap_delete(versionNode);
         }
-        if (!node)
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    if (CA_FORMAT_APPLICATION_VND_OCF_CBOR == format)
+    {
+        if (!versionNode)
         {
-            OIC_LOG(ERROR, TAG, "Accept format option not created");
+            OIC_LOG(ERROR, TAG, "Version option not created");
+            coap_delete(encodeNode);
             return CA_STATUS_INVALID_PARAM;
         }
-        int ret = coap_insert(optlist, node, CAOrderOpts);
-        if (ret <= 0)
+        else
         {
-            coap_delete(node);
-            OIC_LOG(ERROR, TAG, "Accept format option not inserted in header");
-            return CA_STATUS_INVALID_PARAM;
+            ret = coap_insert(optlist, versionNode, CAOrderOpts);
+            if (0 >= ret)
+            {
+                coap_delete(versionNode);
+                coap_delete(encodeNode);
+                OIC_LOG(ERROR, TAG, "Content version option not inserted in header");
+                return CA_STATUS_INVALID_PARAM;
+            }
         }
     }
-
     return CA_STATUS_OK;
 }
 
@@ -687,6 +707,8 @@ uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
             && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type
             && COAP_OPTION_CONTENT_FORMAT != opt_iter.type
             && COAP_OPTION_ACCEPT != opt_iter.type
+            && COAP_OPTION_CONTENT_VERSION != opt_iter.type
+            && COAP_OPTION_ACCEPT_VERSION != opt_iter.type
             && COAP_OPTION_URI_HOST != opt_iter.type && COAP_OPTION_URI_PORT != opt_iter.type
             && COAP_OPTION_ETAG != opt_iter.type && COAP_OPTION_MAXAGE != opt_iter.type
             && COAP_OPTION_PROXY_SCHEME != opt_iter.type)
@@ -866,11 +888,40 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                 {
                     outInfo->payloadFormat = CAConvertFormat((uint8_t)buf[0]);
                 }
+                else if (2 == COAP_OPT_LENGTH(option))
+                {
+                    outInfo->payloadFormat = CAConvertFormat(
+                            coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)));
+                }
                 else
                 {
                     outInfo->payloadFormat = CA_FORMAT_UNSUPPORTED;
-                    OIC_LOG_V(DEBUG, TAG, "option[%d] has an unsupported format [%d]",
-                              opt_iter.type, (uint8_t)buf[0]);
+                    OIC_LOG_V(DEBUG, TAG, "option has an unsupported format");
+                }
+            }
+            else if (COAP_OPTION_CONTENT_VERSION == opt_iter.type)
+            {
+                if (2 == COAP_OPT_LENGTH(option))
+                {
+                    outInfo->payloadVersion =  coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
+                }
+                else
+                {
+                    OIC_LOG_V(DEBUG, TAG, "unsupported content version");
+                    outInfo->payloadVersion = DEFAULT_CONTENT_VERSION_VALUE;
+
+                }
+            }
+            else if (COAP_OPTION_ACCEPT_VERSION == opt_iter.type)
+            {
+                if (2 == COAP_OPT_LENGTH(option))
+                {
+                    outInfo->acceptVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
+                }
+                else
+                {
+                    OIC_LOG_V(DEBUG, TAG, "unsupported accept version");
+                    outInfo->acceptVersion = DEFAULT_ACCEPT_VERSION_VALUE;
                 }
             }
             else if (COAP_OPTION_ACCEPT == opt_iter.type)
@@ -879,12 +930,16 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                 {
                     outInfo->acceptFormat = CAConvertFormat((uint8_t)buf[0]);
                 }
+                else if (2 == COAP_OPT_LENGTH(option))
+                {
+                    outInfo->acceptFormat = CAConvertFormat(
+                            coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)));
+                }
                 else
                 {
                     outInfo->acceptFormat = CA_FORMAT_UNSUPPORTED;
+                    OIC_LOG_V(DEBUG, TAG, "option has an unsupported accept format");
                 }
-                OIC_LOG_V(DEBUG, TAG, "option[%d] has an unsupported format [%d]",
-                          opt_iter.type, (uint8_t)buf[0]);
             }
             else if (COAP_OPTION_URI_PORT == opt_iter.type ||
                     COAP_OPTION_URI_HOST == opt_iter.type ||
@@ -1147,7 +1202,7 @@ CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
     return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->code);
 }
 
-CAPayloadFormat_t CAConvertFormat(uint8_t format)
+CAPayloadFormat_t CAConvertFormat(uint16_t format)
 {
     switch (format)
     {
@@ -1167,6 +1222,8 @@ CAPayloadFormat_t CAConvertFormat(uint8_t format)
             return CA_FORMAT_APPLICATION_JSON;
         case COAP_MEDIATYPE_APPLICATION_CBOR:
             return CA_FORMAT_APPLICATION_CBOR;
+        case COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR:
+            return CA_FORMAT_APPLICATION_VND_OCF_CBOR;
         default:
             return CA_FORMAT_UNSUPPORTED;
     }
index 4e95ff5..eb4e079 100644 (file)
@@ -34,8 +34,6 @@ public:
     std::string dataStr; // data could be binary... for testing we'll use str
 };
 
-
-
 /**
  * Helper to validate the state of CoAP URI parsing.
  *
@@ -215,3 +213,38 @@ TEST(CAProtocolMessage, CAGetTokenFromPDU)
     coap_delete_list(options);
     coap_delete_pdu(pdu);
 }
+
+TEST(CAProtocolMessage, CAGetInfoFromPDU)
+{
+    CAEndpoint_t tempRep;
+    memset(&tempRep, 0, sizeof(CAEndpoint_t));
+    tempRep.flags = CA_DEFAULT_FLAGS;
+    tempRep.adapter = CA_ADAPTER_IP;
+    tempRep.port = 5683;
+
+    coap_pdu_t *pdu = NULL;
+    coap_list_t *options = NULL;
+    coap_transport_t transport = COAP_UDP;
+
+    CAInfo_t inData;
+    memset(&inData, 0, sizeof(CAInfo_t));
+    inData.token = (CAToken_t)"token";
+    inData.tokenLength = strlen(inData.token);
+    inData.type = CA_MSG_NONCONFIRM;
+    inData.payload = (CAPayload_t) "requestPayload";
+    inData.payloadSize = sizeof(inData.payload);;
+    inData.payloadFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
+    inData.acceptFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
+    inData.payloadVersion = 2048;
+    inData.acceptVersion = 2048;
+
+    pdu = CAGeneratePDU(CA_GET, &inData, &tempRep, &options, &transport);
+
+    uint32_t code = CA_NOT_FOUND;
+    CAInfo_t outData;
+    memset(&outData, 0, sizeof(CAInfo_t));
+
+    EXPECT_EQ(CA_STATUS_OK, CAGetInfoFromPDU(pdu, &tempRep, &code, &outData));
+    coap_delete_list(options);
+    coap_delete_pdu(pdu);
+}
index f4e5ec1..13f6711 100755 (executable)
@@ -320,6 +320,9 @@ extern "C" {
 /** Device specification version.*/
 #define OC_SPEC_VERSION                 "core.1.1.0"
 
+/** Integer value of spec version.*/
+#define OC_SPEC_VERSION_VALUE           0
+
 /** Device Data Model version.*/
 #define OC_DATA_MODEL_VERSION           "res.1.1.0,sh.1.1.0"
 
@@ -911,6 +914,7 @@ typedef enum
 typedef enum
 {
     OC_FORMAT_CBOR,
+    OC_FORMAT_VND_OCF_CBOR,
     OC_FORMAT_JSON,
     OC_FORMAT_UNDEFINED,
     OC_FORMAT_UNSUPPORTED,
index e0172fb..922f73f 100644 (file)
@@ -269,7 +269,7 @@ OCStackResult RMAddObserverToStack(const OCServerRequest *request, OCObservation
                 (const char *)(request->query),
                 *obsID, request->requestToken, request->tokenLength,
                 (OCResource *)g_gateWayHandle, request->qos, OC_FORMAT_CBOR,
-                &request->devAddr);
+                OC_SPEC_VERSION_VALUE, &request->devAddr);
     OIC_LOG(DEBUG, TAG, "RMAddObserverToStack OUT");
     return result;
 }
index 284cfba..f06ee04 100644 (file)
@@ -94,6 +94,9 @@ typedef struct ResourceObserver
     /** requested payload encoding format. */
     OCPayloadFormat acceptFormat;
 
+    /** requested payload content version. */
+    uint16_t acceptVersion;
+
 } ResourceObserver;
 
 #ifdef WITH_PRESENCE
@@ -166,6 +169,8 @@ OCStackResult GenerateObserverId (OCObservationId *observationId);
  * @param tokenLength     Length of token.
  * @param resHandle       Resource handle.
  * @param qos             Quality of service of observation.
+ * @param acceptFormat    Accept payload format.
+ * @param acceptVersion   Accept payload version.
  * @param devAddr         Device address.
  *
  * @return ::OC_STACK_OK on success, some other value upon failure.
@@ -178,6 +183,7 @@ OCStackResult AddObserver (const char         *resUri,
                            OCResource         *resHandle,
                            OCQualityOfService qos,
                            OCPayloadFormat    acceptFormat,
+                           uint16_t           acceptVersion,
                            const OCDevAddr    *devAddr);
 
 /**
index ad07c96..52fdbf1 100644 (file)
@@ -50,6 +50,9 @@ typedef struct OCServerRequest
     /** Accept format retrieved from the received request PDU. */
     OCPayloadFormat acceptFormat;
 
+    /** Accept version retrieved from the received request PDU. */
+    uint16_t acceptVersion;
+
     /** resourceUrl will be filled in occoap using the path options in received request PDU.*/
     char resourceUrl[MAX_URI_LENGTH];
 
@@ -208,6 +211,7 @@ OCServerResponse * GetServerResponseUsingHandle (const OCServerRequest * handle)
  * @param resourceUrl                           URL of resource.
  * @param reqTotalSize                          Total size of the request.
  * @param acceptFormat                          The format requested for the payload encoding.
+ * @param acceptVersion                         The content version requested for the payload encoding.
  * @param devAddr                               Device Address.
  *
  * @return
@@ -222,6 +226,7 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
         uint8_t tokenLength,
         char * resourceUrl, size_t reqTotalSize,
         OCPayloadFormat acceptFormat,
+        uint16_t acceptVersion,
         const OCDevAddr *devAddr);
 
 /**
@@ -230,13 +235,17 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
  * @param entityHandlerRequest      pointer to the OCEntityHandlerRequest struct that is created.
  * @param request                   Request handle.
  * @param method                    RESTful method.
+ * @param endpoint                  Device address of the requester.
  * @param resource                  Resource handle.
  * @param queryBuf                  Resource query of request.
- * @param bufReqPayload             JSON payload of request.
+ * @param payloadType               Type of payload.
+ * @param payload                   cbor value of the payload.
+ * @param payloadSize               Size of payload.
  * @param numVendorOptions          Number of vendor options.
  * @param vendorOptions             Vendor options.
  * @param observeAction             Observe action flag.
  * @param observeID                 Observe ID.
+ * @param messageID                 Message ID.
  *
  * @return
  *     OCStackResult
index 304c35d..31769b1 100644 (file)
@@ -83,6 +83,9 @@ typedef struct
     /** the requested payload format. */
     OCPayloadFormat acceptFormat;
 
+    /** the requested payload format. */
+    uint16_t acceptVersion;
+
     /** resourceUrl will be filled in occoap using the path options in received request PDU.*/
     char resourceUrl[MAX_URI_LENGTH];
 
index 9505365..f06755c 100644 (file)
@@ -65,6 +65,8 @@ const char *getResult(OCStackResult result)
             return "OC_STACK_NO_OBSERVERS";
         case OC_STACK_UNAUTHORIZED_REQ:
             return "OC_STACK_UNAUTHORIZED_REQ";
+        case OC_STACK_NOT_ACCEPTABLE:
+            return "OC_STACK_NOT_ACCEPTABLE";
 #ifdef WITH_PRESENCE
         case OC_STACK_PRESENCE_STOPPED:
             return "OC_STACK_PRESENCE_STOPPED";
index 39d8d59..4ea4de1 100644 (file)
@@ -401,6 +401,14 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
     {
         OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
 
+        if (OC_STACK_NOT_ACCEPTABLE == clientResponse->result)
+        {
+            // Re-initiate discovery with OIC format. This is applicable for the case that
+            // a OCF 1.x client speaks to a OIC 1.1 server.
+            InitDiscovery(OC_LOW_QOS, 1);
+            return OC_STACK_KEEP_TRANSACTION;
+        }
+
         std::string connectionType = getConnectivityType (clientResponse->connType);
         OIC_LOG_V(INFO, TAG, "Discovered on %s", connectionType.c_str());
         OIC_LOG_V(INFO, TAG,
@@ -852,7 +860,7 @@ int InitIntrospectionDiscovery(OCQualityOfService qos)
     return ret;
 }
 
-int InitDiscovery(OCQualityOfService qos)
+int InitDiscovery(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptions)
 {
     OCStackResult ret;
     OCCallbackData cbData;
@@ -864,9 +872,32 @@ int InitDiscovery(OCQualityOfService qos)
     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
     cbData.cd = NULL;
 
-    ret = OCDoRequest(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
-                      (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
-                      &cbData, NULL, 0);
+    if (withVendorSpecificHeaderOptions)
+    {
+        OCHeaderOption options[MAX_HEADER_OPTIONS];
+        memset(options, 0, sizeof(OCHeaderOption) * MAX_HEADER_OPTIONS);
+        size_t numOptions = 0;
+
+        uint8_t option0[] = {0};
+        uint16_t optionID = 2049;
+        size_t optionDataSize = sizeof(option0);
+        OCSetHeaderOption(options, &numOptions, optionID, option0, optionDataSize);
+
+        uint8_t option1[] = {0};
+        optionID = 2053;
+        optionDataSize = sizeof(option1);
+        OCSetHeaderOption(options, &numOptions, optionID, option1, optionDataSize);
+
+        ret = OCDoRequest(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
+                              (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
+                              &cbData, options, 2);
+    }
+    else
+    {
+        ret = OCDoRequest(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
+                           (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
+                           &cbData, NULL, 0);
+    }
     if (ret != OC_STACK_OK)
     {
         OIC_LOG(ERROR, TAG, "OCStack resource error");
@@ -1075,7 +1106,7 @@ int main(int argc, char* argv[])
     }
     else
     {
-        InitDiscovery(OC_LOW_QOS);
+        InitDiscovery(OC_LOW_QOS, 0);
     }
 
     // Break from loop with Ctrl+C
index c96fa0c..11f197d 100644 (file)
@@ -115,7 +115,7 @@ int InitDeleteRequest(OCQualityOfService qos);
 int InitGetRequest(OCQualityOfService qos);
 int InitDeviceDiscovery(OCQualityOfService qos);
 int InitPlatformDiscovery(OCQualityOfService qos);
-int InitDiscovery(OCQualityOfService qos);
+int InitDiscovery(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptions);
 int InitGetRequestWithCoap(OCDiscoveryPayload* dis, bool isUdp);
 int InitIntrospection(OCDiscoveryPayload* dis);
 
index 1b756c6..f5ca966 100644 (file)
@@ -117,7 +117,7 @@ static OCStackResult SendObserveNotification(ResourceObserver *observer,
                               observer->query, NULL, NULL,
                               observer->token, observer->tokenLength,
                               observer->resUri, 0, observer->acceptFormat,
-                              &observer->devAddr);
+                              observer->acceptVersion, &observer->devAddr);
 
     if (request)
     {
@@ -202,7 +202,7 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
                         NULL, NULL,
                         resourceObserver->token, resourceObserver->tokenLength,
                         resourceObserver->resUri, 0, resourceObserver->acceptFormat,
-                        &resourceObserver->devAddr);
+                        resourceObserver->acceptVersion, &resourceObserver->devAddr);
 
                 if (result == OC_STACK_OK)
                 {
@@ -289,7 +289,7 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                         0, resource->sequenceNum, qos, observer->query,
                         NULL, NULL, observer->token, observer->tokenLength,
                         observer->resUri, 0, observer->acceptFormat,
-                        &observer->devAddr);
+                        observer->acceptVersion, &observer->devAddr);
 
                 if (request)
                 {
@@ -392,6 +392,7 @@ OCStackResult AddObserver (const char         *resUri,
                            OCResource         *resHandle,
                            OCQualityOfService qos,
                            OCPayloadFormat    acceptFormat,
+                           uint16_t           acceptVersion,
                            const OCDevAddr    *devAddr)
 {
     // Check if resource exists and is observable.
@@ -419,6 +420,7 @@ OCStackResult AddObserver (const char         *resUri,
 
         obsNode->qos = qos;
         obsNode->acceptFormat = acceptFormat;
+        obsNode->acceptVersion = acceptVersion;
         if (query)
         {
             obsNode->query = OICStrdup(query);
index 02c4142..703c61a 100755 (executable)
@@ -1697,7 +1697,7 @@ HandleResourceWithEntityHandler(OCServerRequest *request,
                 (const char *)(request->query),
                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
                 resource, request->qos, request->acceptFormat,
-                &request->devAddr);
+                request->acceptVersion, &request->devAddr);
 
         if(result == OC_STACK_OK)
         {
index cfab244..ee87703 100644 (file)
@@ -263,7 +263,7 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
         OCHeaderOption * rcvdVendorSpecificHeaderOptions,
         uint8_t * payload, CAToken_t requestToken, uint8_t tokenLength,
         char * resourceUrl, size_t reqTotalSize, OCPayloadFormat acceptFormat,
-        const OCDevAddr *devAddr)
+        uint16_t acceptVersion, const OCDevAddr *devAddr)
 {
     if (!request)
     {
@@ -289,6 +289,7 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
     serverRequest->observeResult = OC_STACK_ERROR;
     serverRequest->qos = qos;
     serverRequest->acceptFormat = acceptFormat;
+    serverRequest->acceptVersion = acceptVersion;
     serverRequest->ehResponseHandler = HandleSingleResponse;
     serverRequest->numResponses = 1;
 
@@ -631,6 +632,7 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
             case OC_FORMAT_UNDEFINED:
                 // No preference set by the client, so default to CBOR then
             case OC_FORMAT_CBOR:
+            case OC_FORMAT_VND_OCF_CBOR:
                 if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload,
                                 &responseInfo.info.payloadSize))
                         != OC_STACK_OK)
@@ -642,7 +644,20 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
                 // Add CONTENT_FORMAT OPT if payload exist
                 if (responseInfo.info.payloadSize > 0)
                 {
-                    responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
+                    if (OC_FORMAT_VND_OCF_CBOR == serverRequest->acceptFormat)
+                    {
+                        responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
+                        if (!serverRequest->acceptVersion)
+                        {
+                            serverRequest->acceptVersion = DEFAULT_ACCEPT_VERSION_VALUE;
+                        }
+                        // Add CONTENT_VERSION OPT for this format.
+                        responseInfo.info.payloadVersion = serverRequest->acceptVersion;
+                    }
+                    else
+                    {
+                        responseInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
+                    }
                 }
                 break;
             default:
index 88bb0c7..42cdb99 100644 (file)
@@ -525,8 +525,38 @@ static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *
     }
 #endif
 
-    // OC stack prefer CBOR encoded payloads.
-    requestInfo->info.acceptFormat = CA_FORMAT_APPLICATION_CBOR;
+    uint16_t acceptVersion = OC_SPEC_VERSION_VALUE;
+    // From OCF onwards, check settings of version option.
+    if (DEFAULT_ACCEPT_VERSION_VALUE <= acceptVersion)
+    {
+        if (requestInfo->info.numOptions > 0 && requestInfo->info.options)
+        {
+            for (uint8_t i = 0; i < requestInfo->info.numOptions; i++)
+            {
+                if (COAP_OPTION_ACCEPT_VERSION == requestInfo->info.options[i].protocolID)
+                {
+                    acceptVersion = requestInfo->info.options[i].optionData[0];
+                    break;
+                }
+                else if (COAP_OPTION_CONTENT_VERSION == requestInfo->info.options[i].protocolID)
+                {
+                    acceptVersion = requestInfo->info.options[i].optionData[0];
+                    break;
+                }
+            }
+        }
+    }
+
+    if (DEFAULT_CONTENT_VERSION_VALUE <= acceptVersion)
+    {
+        requestInfo->info.acceptFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
+        requestInfo->info.acceptVersion = acceptVersion;
+    }
+    else
+    {
+      requestInfo->info.acceptFormat = CA_FORMAT_APPLICATION_CBOR;
+    }
+
     CAResult_t result = CASendRequest(object, requestInfo);
     if(CA_STATUS_OK != result)
     {
@@ -1282,10 +1312,19 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp
                 //      app that at least the request was received at the server?
             }
         }
-        else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
+        else if (CA_RETRANSMIT_TIMEOUT == responseInfo->result
+                || CA_NOT_ACCEPTABLE == responseInfo->result)
         {
-            OIC_LOG(INFO, TAG, "Receiving A Timeout for this token");
-            OIC_LOG(INFO, TAG, "Calling into application address space");
+            if (CA_RETRANSMIT_TIMEOUT == responseInfo->result)
+            {
+                OIC_LOG(INFO, TAG, "Receiving A Timeout for this token");
+                OIC_LOG(INFO, TAG, "Calling into application address space");
+            }
+            else
+            {
+                OIC_LOG(INFO, TAG, "Server doesn't support the requested payload format");
+                OIC_LOG(INFO, TAG, "Calling into application address space");
+            }
 
             OCClientResponse *response = NULL;
 
@@ -1875,7 +1914,7 @@ OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
                 protocolRequest->payload, protocolRequest->requestToken,
                 protocolRequest->tokenLength, protocolRequest->resourceUrl,
                 protocolRequest->reqTotalSize, protocolRequest->acceptFormat,
-                &protocolRequest->devAddr);
+                protocolRequest->acceptVersion, &protocolRequest->devAddr);
         if (OC_STACK_OK != result)
         {
             OIC_LOG(ERROR, TAG, "Error adding server request");
@@ -2047,6 +2086,9 @@ void OCHandleRequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
         case CA_FORMAT_APPLICATION_CBOR:
             serverRequest.acceptFormat = OC_FORMAT_CBOR;
             break;
+        case CA_FORMAT_APPLICATION_VND_OCF_CBOR:
+            serverRequest.acceptFormat = OC_FORMAT_VND_OCF_CBOR;
+            break;
         case CA_FORMAT_UNDEFINED:
             serverRequest.acceptFormat = OC_FORMAT_UNDEFINED;
             break;
@@ -2936,7 +2978,7 @@ OCStackResult OCDoRequest(OCDoHandle *handle,
 
     CopyDevAddrToEndpoint(devAddr, &endpoint);
 
-    if(payload)
+    if (payload)
     {
         if((result =
             OCConvertPayload(payload, &requestInfo.info.payload, &requestInfo.info.payloadSize))
@@ -2945,7 +2987,38 @@ OCStackResult OCDoRequest(OCDoHandle *handle,
             OIC_LOG(ERROR, TAG, "Failed to create CBOR Payload");
             goto exit;
         }
-        requestInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
+
+        uint16_t payloadVersion = OC_SPEC_VERSION_VALUE;
+        // From OCF onwards, check version option settings
+        if (DEFAULT_CONTENT_VERSION_VALUE <= payloadVersion)
+        {
+            if (numOptions > 0 && options)
+            {
+                for (uint8_t i = 0; i < numOptions; i++)
+                {
+                    if (COAP_OPTION_CONTENT_VERSION == options[i].optionID)
+                    {
+                        payloadVersion = options[i].optionData[0];
+                        break;
+                    }
+                    else if (COAP_OPTION_ACCEPT_VERSION == options[i].optionID)
+                    {
+                        payloadVersion = options[i].optionData[0];
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (DEFAULT_CONTENT_VERSION_VALUE <= payloadVersion)
+        {
+            requestInfo.info.payloadFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
+            requestInfo.info.payloadVersion = payloadVersion;
+        }
+        else
+        {
+            requestInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR;
+        }
     }
     else
     {
@@ -3334,7 +3407,8 @@ OCStackResult OCStartPresence(const uint32_t ttl)
         }
 
         AddObserver(OC_RSRVD_PRESENCE_URI, NULL, 0, caToken, tokenLength,
-                (OCResource *)presenceResource.handle, OC_LOW_QOS, OC_FORMAT_UNDEFINED, &devAddr);
+                (OCResource *) presenceResource.handle, OC_LOW_QOS, OC_FORMAT_UNDEFINED,
+                OC_SPEC_VERSION_VALUE, &devAddr);
         CADestroyToken(caToken);
     }