Append accept format and accept version in options.
authorZiran Sun <ziran.sun@samsung.com>
Tue, 2 May 2017 09:52:10 +0000 (10:52 +0100)
committerAshok Babu Channa <ashok.channa@samsung.com>
Thu, 18 May 2017 11:25:14 +0000 (11:25 +0000)
If accept format and accept version are not set via option headers,
set them to default value via stack functions.
These values will be passed to rcvdVendorSpecificHeaderOptions through
requestInfo.info.options.

Bug: https://jira.iotivity.org/browse/IOT-1973

Change-Id: I10f589cf3e18fc105640e1a27df5d50aa1b73298
Signed-off-by: Ziran Sun <ziran.sun@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/19535
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Phil Coval <philippe.coval@osg.samsung.com>
Reviewed-by: Uze Choi <uzchoi@samsung.com>
Reviewed-by: Ashok Babu Channa <ashok.channa@samsung.com>
java/common/src/main/java/org/iotivity/base/OcHeaderOption.java
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp
resource/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp
resource/csdk/stack/src/ocstack.c
resource/include/OCHeaderOption.h
resource/unittests/OCHeaderOptionTest.cpp

index bcabc66..a8db8e6 100644 (file)
@@ -44,6 +44,7 @@ public class OcHeaderOption {
     public static final int IF_NONE_MATCH_OPTION_ID = 5;
     public static final int LOCATION_PATH_OPTION_ID = 8;
     public static final int LOCATION_QUERY_OPTION_ID = 20;
+    public static final int ACCEPT_OPTION_ID = 17;
 
     private int mOptionId;
     private String mOptionData;
@@ -53,7 +54,8 @@ public class OcHeaderOption {
                 && optionId != IF_MATCH_OPTION_ID
                 && optionId != IF_NONE_MATCH_OPTION_ID
                 && optionId != LOCATION_PATH_OPTION_ID
-                && optionId != LOCATION_QUERY_OPTION_ID) {
+                && optionId != LOCATION_QUERY_OPTION_ID
+                && optionId != ACCEPT_OPTION_ID) {
             throw new InvalidParameterException("Option ID range is invalid");
         }
 
index 2beed9c..1bb3c0c 100755 (executable)
@@ -725,9 +725,7 @@ CAResult_t CAGetOptionCount(coap_opt_iterator_t opt_iter, uint8_t *optionCount)
             && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
             && 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)
@@ -953,38 +951,6 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
 
                 }
             }
-            else if (COAP_OPTION_ACCEPT_VERSION == opt_iter.type)
-            {
-                if (2 == COAP_OPT_LENGTH(option))
-                {
-                    unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
-                    assert(decodedVersion <= UINT16_MAX);
-                    outInfo->acceptVersion = (uint16_t)decodedVersion;
-                }
-                else
-                {
-                    OIC_LOG(DEBUG, TAG, "unsupported accept version");
-                    outInfo->acceptVersion = DEFAULT_VERSION_VALUE;
-                }
-            }
-            else if (COAP_OPTION_ACCEPT == opt_iter.type)
-            {
-                if (1 == COAP_OPT_LENGTH(option))
-                {
-                    outInfo->acceptFormat = CAConvertFormat((uint8_t)buf[0]);
-                }
-                else if (2 == COAP_OPT_LENGTH(option))
-                {
-                    unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
-                    assert(decodedFormat <= UINT16_MAX);
-                    outInfo->acceptFormat = CAConvertFormat((uint16_t)decodedFormat);
-                }
-                else
-                {
-                    outInfo->acceptFormat = CA_FORMAT_UNSUPPORTED;
-                    OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
-                }
-            }
             else if (COAP_OPTION_URI_PORT == opt_iter.type ||
                     COAP_OPTION_URI_HOST == opt_iter.type ||
                     COAP_OPTION_ETAG == opt_iter.type ||
@@ -1000,6 +966,40 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                 {
                     isProxyRequest = true;
                 }
+                else if (COAP_OPTION_ACCEPT_VERSION == opt_iter.type)
+                {
+                    if (2 == COAP_OPT_LENGTH(option))
+                    {
+                        unsigned int decodedVersion = coap_decode_var_bytes(COAP_OPT_VALUE(option),
+                                COAP_OPT_LENGTH(option));
+                        assert(decodedVersion <= UINT16_MAX);
+                        outInfo->acceptVersion = (uint16_t) decodedVersion;
+                    }
+                    else
+                    {
+                        OIC_LOG(DEBUG, TAG, "unsupported accept version");
+                        outInfo->acceptVersion = DEFAULT_VERSION_VALUE;
+                    }
+                }
+                else if (COAP_OPTION_ACCEPT == opt_iter.type)
+                {
+                    if (1 == COAP_OPT_LENGTH(option))
+                    {
+                        outInfo->acceptFormat = CAConvertFormat((uint8_t) buf[0]);
+                    }
+                    else if (2 == COAP_OPT_LENGTH(option))
+                    {
+                        unsigned int decodedFormat = coap_decode_var_bytes(COAP_OPT_VALUE(option),
+                                COAP_OPT_LENGTH(option));
+                        assert(decodedFormat <= UINT16_MAX);
+                        outInfo->acceptFormat = CAConvertFormat((uint16_t) decodedFormat);
+                    }
+                    else
+                    {
+                        outInfo->acceptFormat = CA_FORMAT_UNSUPPORTED;
+                        OIC_LOG(DEBUG, TAG, "option has an unsupported accept format");
+                    }
+                }
                 if (idx < count)
                 {
                     if (bufLength <= sizeof(outInfo->options[0].optionData))
index 3489ef7..fe49c79 100755 (executable)
@@ -45,6 +45,7 @@
 #include "ocpayload.h"
 #include "payload_logging.h"
 #include "common.h"
+#include "cacommon.h"
 
 #ifdef ROUTING_GATEWAY
 /**
@@ -835,8 +836,8 @@ int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptio
     {
         memset(options, 0, sizeof(OCHeaderOption)* MAX_HEADER_OPTIONS);
         size_t numOptions = 0;
-        uint8_t option0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-        uint16_t optionID = 2048;
+        uint8_t option0[] = { 16, 39 };
+        uint16_t optionID = COAP_OPTION_ACCEPT;
         size_t optionDataSize = sizeof(option0);
         OCSetHeaderOption(options,
                           &numOptions,
@@ -844,8 +845,8 @@ int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptio
                           option0,
                           optionDataSize);
 
-        uint8_t option1[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
-        optionID = 3000;
+        uint8_t option1[] = { 0, 8 };
+        optionID = COAP_OPTION_ACCEPT_VERSION;
         optionDataSize = sizeof(option1);
         OCSetHeaderOption(options,
                           &numOptions,
index 78bf24b..dee4405 100644 (file)
@@ -43,6 +43,7 @@
 #include "ocserver.h"
 #include "common.h"
 #include "oic_string.h"
+#include "cacommon.h"
 
 #define VERIFY_SUCCESS(op)                          \
 {                                                   \
@@ -641,13 +642,29 @@ OCEntityHandlerCb (OCEntityHandlerFlag flag,
                             MAX_HEADER_OPTION_DATA_LENGTH);
                     }
                 }
+                // Check on Accept Version option.
+                uint8_t vOptionData[MAX_HEADER_OPTION_DATA_LENGTH];
+                size_t vOptionDataSize = sizeof(vOptionData);
+                uint16_t actualDataSize = 0;
+                OCGetHeaderOption(entityHandlerRequest->rcvdVendorSpecificHeaderOptions,
+                        entityHandlerRequest->numRcvdVendorSpecificHeaderOptions,
+                        COAP_OPTION_ACCEPT_VERSION, vOptionData, vOptionDataSize, &actualDataSize);
+                if (actualDataSize)
+                {
+                    OIC_LOG_V(INFO, TAG, "accept version option exists");
+                    OIC_LOG_BUFFER(INFO, TAG, vOptionData, MAX_HEADER_OPTION_DATA_LENGTH);
+                }
+                uint16_t acceptVersion = vOptionData[0]*256 + vOptionData[1];
+                if (OC_SPEC_VERSION_VALUE == acceptVersion)
+                {
+                    OIC_LOG_V(INFO, TAG, "accept version equals to default OC_SPEC_VERSION_VALUE.");
+                }
 
                 OCHeaderOption* sendOptions = response.sendVendorSpecificHeaderOptions;
                 size_t numOptions = response.numSendVendorSpecificHeaderOptions;
                 // Check if the option header has already existed before adding it in.
                 uint8_t optionData[MAX_HEADER_OPTION_DATA_LENGTH];
                 size_t optionDataSize = sizeof(optionData);
-                uint16_t actualDataSize = 0;
                 OCGetHeaderOption(response.sendVendorSpecificHeaderOptions,
                                   response.numSendVendorSpecificHeaderOptions,
                                   2248,
index c999cce..faed96c 100644 (file)
@@ -372,7 +372,7 @@ static OCStackResult HandlePresenceResponse(const CAEndpoint_t *endPoint,
  * @param responseInfo CA response info.
  */
 static void HandleCAResponses(const CAEndpoint_t* endPoint,
-    const CAResponseInfo_t* responseInfo);
+        const CAResponseInfo_t* responseInfo);
 
 /**
  * This function will be called back by CA layer when a request is received.
@@ -381,7 +381,7 @@ static void HandleCAResponses(const CAEndpoint_t* endPoint,
  * @param requestInfo CA request info.
  */
 static void HandleCARequests(const CAEndpoint_t* endPoint,
-    const CARequestInfo_t* requestInfo);
+        const CARequestInfo_t* requestInfo);
 
 /**
  * Extract query from a URI.
@@ -417,6 +417,19 @@ static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);
 
 /**
+ * Set Header Option.
+ * @param caHdrOpt            Pointer to existing options
+ * @param numOptions          Number of existing options.
+ * @param optionID            COAP option ID.
+ * @param optionData          Option data value.
+ * @param optionDataLength    Size of Option data value.
+
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+static OCStackResult SetHeaderOption(CAHeaderOption_t *caHdrOpt, size_t numOptions,
+        uint16_t optionID, void* optionData, size_t optionDataLength);
+
+/**
  * Ensure the accept header option is set appropriatly before sending the requests and routing
  * header option is updated with destination.
  *
@@ -618,6 +631,8 @@ static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *
     }
 #endif
 
+    // TODO: We might need to remove acceptFormat and acceptVersion fields in requestinfo->info
+    // at a later stage to avoid duplication.
     uint16_t acceptVersion = OC_SPEC_VERSION_VALUE;
     CAPayloadFormat_t acceptFormat = CA_FORMAT_APPLICATION_VND_OCF_CBOR;
     // Check settings of version option and content format.
@@ -1527,6 +1542,7 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp
         {
             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
@@ -3382,19 +3398,89 @@ OCStackResult OCDoRequest(OCDoHandle *handle,
     }
     else
     {
-        requestInfo.info.numOptions = numOptions;
-        if(requestInfo.info.numOptions)
+        // Check if accept format and accept version have been set.
+        uint16_t acceptVersion = OC_SPEC_VERSION_VALUE;
+        uint16_t acceptFormat = COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR;
+        bool IsAcceptVersionSet = false;
+        bool IsAcceptFormatSet = false;
+        // Check settings of version option and content format.
+        if (numOptions > 0 && options)
         {
-            requestInfo.info.options =
-                (CAHeaderOption_t*) OICCalloc(numOptions, sizeof(CAHeaderOption_t));
-            if (NULL == requestInfo.info.options)
+            for (uint8_t i = 0; i < numOptions; i++)
             {
-                OIC_LOG(ERROR, TAG, "Calloc failed");
-                result = OC_STACK_NO_MEMORY;
-                goto exit;
+                if (COAP_OPTION_ACCEPT_VERSION == options[i].optionID)
+                {
+                    acceptVersion = *(uint16_t*) options[i].optionData;
+                    IsAcceptVersionSet = true;
+                }
+                else if (COAP_OPTION_ACCEPT == options[i].optionID)
+                {
+                    if (1 == options[i].optionLength)
+                    {
+                        acceptFormat = CAConvertFormat(*(uint8_t*)options[i].optionData);
+                        IsAcceptFormatSet = true;
+                    }
+                    else if (2 == options[i].optionLength)
+                    {
+                        acceptFormat = CAConvertFormat(*(uint16_t*)options[i].optionData);
+                        IsAcceptFormatSet = true;
+                    }
+                    else
+                    {
+                        acceptFormat = CA_FORMAT_UNSUPPORTED;
+                        IsAcceptFormatSet = true;
+                        OIC_LOG_V(DEBUG, TAG, "option has an unsupported format");
+                    }
+                }
             }
-            memcpy(requestInfo.info.options, (CAHeaderOption_t*)options,
-                   numOptions * sizeof(CAHeaderOption_t));
+        }
+
+        if (!IsAcceptVersionSet && !IsAcceptFormatSet)
+        {
+            requestInfo.info.numOptions = numOptions + 2;
+        }
+        else if ((IsAcceptFormatSet &&
+                CA_FORMAT_APPLICATION_VND_OCF_CBOR == acceptFormat &&
+                !IsAcceptVersionSet) || (IsAcceptVersionSet && !IsAcceptFormatSet))
+        {
+            requestInfo.info.numOptions = numOptions + 1;
+        }
+        else
+        {
+            requestInfo.info.numOptions = numOptions;
+        }
+
+        requestInfo.info.options = (CAHeaderOption_t*) OICCalloc(requestInfo.info.numOptions,
+                sizeof(CAHeaderOption_t));
+        if (NULL == requestInfo.info.options)
+        {
+            OIC_LOG(ERROR, TAG, "Calloc failed");
+            result = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+        memcpy(requestInfo.info.options, (CAHeaderOption_t*) options,
+               numOptions * sizeof(CAHeaderOption_t));
+
+        if (!IsAcceptVersionSet && !IsAcceptFormatSet)
+        {
+            // Append accept format and accept version to the options.
+            SetHeaderOption(requestInfo.info.options, numOptions, CA_OPTION_ACCEPT, &acceptFormat,
+                    sizeof(uint16_t));
+            SetHeaderOption(requestInfo.info.options, numOptions + 1, CA_OPTION_ACCEPT_VERSION,
+                    &acceptVersion, sizeof(uint16_t));
+        }
+        else if (IsAcceptFormatSet && CA_FORMAT_APPLICATION_VND_OCF_CBOR == acceptFormat
+                && !IsAcceptVersionSet)
+        {
+            // Append accept version to the options.
+            SetHeaderOption(requestInfo.info.options, numOptions, CA_OPTION_ACCEPT_VERSION,
+                    &acceptVersion, sizeof(uint16_t));
+        }
+        else if (IsAcceptVersionSet && OC_SPEC_VERSION_VALUE <= acceptVersion && !IsAcceptFormatSet)
+        {
+            // Append accept format to the options.
+            SetHeaderOption(requestInfo.info.options, numOptions, CA_OPTION_ACCEPT, &acceptFormat,
+                    sizeof(uint16_t));
         }
     }
 
@@ -5937,6 +6023,31 @@ OCResourceHandle OCGetResourceHandleAtUri(const char *uri)
     return NULL;
 }
 
+static OCStackResult SetHeaderOption(CAHeaderOption_t *caHdrOpt, size_t numOptions,
+        uint16_t optionID, void* optionData, size_t optionDataLength)
+{
+    if (!caHdrOpt)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (!optionData)
+    {
+        OIC_LOG (INFO, TAG, "optionData are NULL");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    caHdrOpt[numOptions].protocolID = CA_COAP_ID;
+    caHdrOpt[numOptions].optionID = optionID;
+    caHdrOpt[numOptions].optionLength =
+            (optionDataLength < MAX_HEADER_OPTION_DATA_LENGTH) ?
+                    (uint16_t) optionDataLength : MAX_HEADER_OPTION_DATA_LENGTH;
+    memcpy(caHdrOpt[numOptions].optionData, (const void*) optionData,
+            caHdrOpt[numOptions].optionLength);
+
+    return OC_STACK_OK;
+}
+
 OCStackResult OCSetHeaderOption(OCHeaderOption* ocHdrOpt, size_t* numOptions, uint16_t optionID,
                                 void* optionData, size_t optionDataLength)
 {
@@ -6004,8 +6115,8 @@ OCStackResult OCGetHeaderOption(OCHeaderOption* ocHdrOpt, size_t numOptions,
         {
             if (optionDataLength >= ocHdrOpt->optionLength)
             {
-                memcpy(optionData, ocHdrOpt->optionData, ocHdrOpt->optionLength);
-                *receivedDataLength = ocHdrOpt->optionLength;
+                memcpy(optionData, ocHdrOpt[i].optionData, ocHdrOpt[i].optionLength);
+                *receivedDataLength = ocHdrOpt[i].optionLength;
                 return OC_STACK_OK;
             }
             else
index 78f9029..e9533ec 100644 (file)
@@ -42,7 +42,7 @@ namespace OC
         *            NOTE: HeaderOptionID  is an unsigned integer value which MUST be within
         *            range of 2048 to 3000 inclusive of lower and upper bound
         *            except for If-Match with empty(num : 1), If-None-Match(num : 5),
-        *            Location-Path(num : 8), Location-Query(num : 20) option.
+        *            Location-Path(num : 8), Location-Query(num : 20), Accept(num : 17) option.
         *            HeaderOptions instance creation fails if above condition is not satisfied.
         */
         const uint16_t MIN_HEADER_OPTIONID = 2048;
@@ -51,6 +51,7 @@ namespace OC
         const uint16_t IF_NONE_MATCH_OPTION_ID = 5;
         const uint16_t LOCATION_PATH_OPTION_ID = 8;
         const uint16_t LOCATION_QUERY_OPTION_ID = 20;
+        const uint16_t ACCEPT_OPTION_ID = 17;
 
         class OCHeaderOption
         {
@@ -70,7 +71,8 @@ namespace OC
                         && optionID != IF_MATCH_OPTION_ID
                         && optionID != IF_NONE_MATCH_OPTION_ID
                         && optionID != LOCATION_PATH_OPTION_ID
-                        && optionID != LOCATION_QUERY_OPTION_ID)
+                        && optionID != LOCATION_QUERY_OPTION_ID
+                        && optionID != ACCEPT_OPTION_ID)
                 {
                     throw OCException(OC::Exception::OPTION_ID_RANGE_INVALID);
                 }
index fbe63b1..fe10e19 100644 (file)
@@ -51,7 +51,8 @@ namespace OC
                     if (HeaderOption::IF_MATCH_OPTION_ID != i
                             && HeaderOption::IF_NONE_MATCH_OPTION_ID != i
                             && HeaderOption::LOCATION_PATH_OPTION_ID != i
-                            && HeaderOption::LOCATION_QUERY_OPTION_ID != i)
+                            && HeaderOption::LOCATION_QUERY_OPTION_ID != i
+                            && HeaderOption::ACCEPT_OPTION_ID != i)
                     {
                         ASSERT_THROW(
                                 HeaderOption::OCHeaderOption(i,""),