Patch for enabling blockwise and bt submit/tizen/20150908.015501
authorSangkwan Lee <skgood.lee@samsung.com>
Thu, 3 Sep 2015 02:27:18 +0000 (11:27 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Mon, 7 Sep 2015 14:36:51 +0000 (07:36 -0700)
1) Enable blockwise
2) Enable BT EDR
3) Fix : Notify bt discovery done sequence
4) Filtering connectivity type when sends multicast message (Now : When
multicast message, send the message to all available connectivity)
5) patch Change-id I2ea9fdab45bef800f05ade65296d3c4014037dea from
iotivity master branch
6) remove useless header

Change-Id: If4aec07ac966ff71bb3699b876a52987b1f585e9
Signed-off-by: Sangkwan Lee <skgood.lee@samsung.com>
20 files changed:
packaging/iotivity.spec
resource/c_common/SConscript
resource/c_common/platform_features.h [new file with mode: 0644]
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/inc/cablockwisetransfer.h [new file with mode: 0644]
resource/csdk/connectivity/inc/camessagehandler.h
resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h
resource/csdk/connectivity/src/SConscript [changed mode: 0755->0644]
resource/csdk/connectivity/src/bt_edr_adapter/tizen/caedrclient.c
resource/csdk/connectivity/src/cablockwisetransfer.c [new file with mode: 0644]
resource/csdk/connectivity/src/cainterfacecontroller.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/src/ocpayload.c
resource/csdk/stack/src/ocpayloadconvert.c
resource/csdk/stack/src/ocpayloadparse.c
resource/csdk/stack/src/ocserverrequest.c
resource/csdk/stack/src/ocstack.c

index db615ef..38c6732 100644 (file)
@@ -86,7 +86,7 @@ cp %{SOURCE1001} ./%{name}-test.manifest
 %endif
 
 
-scons -j 4 TARGET_OS=tizen TARGET_ARCH=%{RPM_ARCH} TARGET_TRANSPORT=IP RELEASE=%{release_mode}
+scons -j 4 TARGET_OS=tizen TARGET_ARCH=%{RPM_ARCH} TARGET_TRANSPORT=IP,BT RELEASE=%{release_mode}
 
 %install
 rm -rf %{buildroot}
index f0e140c..d018d88 100644 (file)
@@ -23,6 +23,7 @@ Import('env')
 import os
 
 env.AppendUnique(CPPPATH = [
+            os.path.join(Dir('.').abspath),
             os.path.join(Dir('.').abspath, 'oic_malloc/include'),
             os.path.join(Dir('.').abspath, 'oic_string/include')
         ])
diff --git a/resource/c_common/platform_features.h b/resource/c_common/platform_features.h
new file mode 100644 (file)
index 0000000..8f39e19
--- /dev/null
@@ -0,0 +1,44 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//******************************************************************
+
+/**
+ * @file
+ *
+ * This file contains compiler and platform feature definitions.  These
+ * can be used to enable functionality on only platforms that support
+ * said functionality.
+ */
+
+#ifndef PLATFORM_FEATURES_H_
+#define PLATFORM_FEATURES_H_
+
+
+#if (__cplusplus >=201103L) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+    #define SUPPORTS_DEFAULT_CTOR
+#endif
+
+#if (__STDC_VERSION__ >= 201112L)
+    #include <stdassert.h>
+    #define OC_STATIC_ASSERT(condition, msg) static_assert(condition, msg)
+#else
+    #define OC_STATIC_ASSERT(condition, msg) ((void)sizeof(char[2*!!(condition) - 1]))
+#endif
+
+#endif
index 2f18e56..e42fde2 100644 (file)
@@ -79,6 +79,10 @@ extern "C"
 #define COAP_MAX_PDU_SIZE           1400 /* maximum size of a CoAP PDU for big platforms*/
 #endif
 
+#ifdef WITH_BWT
+#define CA_DEFAULT_BLOCK_SIZE       CA_BLOCK_SIZE_1024_BYTE
+#endif
+
 /**
  *@brief Maximum length of the remoteEndpoint identity
  */
@@ -208,6 +212,21 @@ typedef enum
 } CAMethod_t;
 
 /**
+ * block size
+ * it depends on defined size in libCoAP.
+ */
+typedef enum
+{
+    CA_BLOCK_SIZE_16_BYTE = 0,    /**< 16byte */
+    CA_BLOCK_SIZE_32_BYTE = 1,    /**< 32byte */
+    CA_BLOCK_SIZE_64_BYTE = 2,    /**< 64byte */
+    CA_BLOCK_SIZE_128_BYTE = 3,   /**< 128byte */
+    CA_BLOCK_SIZE_256_BYTE = 4,   /**< 256byte */
+    CA_BLOCK_SIZE_512_BYTE = 5,   /**< 512byte */
+    CA_BLOCK_SIZE_1024_BYTE = 6     /**< 1Kbyte */
+} CABlockSize_t;
+
+/**
  * @brief Endpoint information for connectivities
  * Must be identical to OCDevAddr.
  */
@@ -260,11 +279,14 @@ typedef enum
     CA_VALID = 203,                  /**< Valid */
     CA_CHANGED = 204,                /**< Changed */
     CA_CONTENT = 205,                /**< Content */
+    CA_CONTINUE = 231,               /**< Continue */
     CA_BAD_REQ = 400,                /**< Bad Request */
     CA_UNAUTHORIZED_REQ = 401,       /**< Unauthorized Request */
     CA_BAD_OPT = 402,                /**< Bad Option */
     CA_FORBIDDEN_REQ = 403,          /**< Forbidden Request */
     CA_NOT_FOUND = 404,              /**< Not found */
+    CA_REQUEST_ENTITY_INCOMPLETE = 408, /**< Request Entity Incomplete */
+    CA_REQUEST_ENTITY_TOO_LARGE = 413,  /**< Request Entity Too Large */
     CA_INTERNAL_SERVER_ERROR = 500,  /**< Internal Server Error */
     CA_RETRANSMIT_TIMEOUT = 504      /**< Retransmit timeout */
     /* Response status code - END HERE */
diff --git a/resource/csdk/connectivity/inc/cablockwisetransfer.h b/resource/csdk/connectivity/inc/cablockwisetransfer.h
new file mode 100644 (file)
index 0000000..d3f883c
--- /dev/null
@@ -0,0 +1,557 @@
+/* *****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file contains common function for block messages.
+ */
+
+#ifndef CA_BLOCKWISETRANSFER_H_
+#define CA_BLOCKWISETRANSFER_H_
+
+#include <stdint.h>
+
+#include "coap.h"
+#include "cathreadpool.h"
+#include "camutex.h"
+#include "uarraylist.h"
+#include "cacommon.h"
+#include "caprotocolmessage.h"
+
+/**
+ * Callback to send block data.
+ * @param[in]   data    send data.
+ */
+typedef void (*CASendThreadFunc)(CAData_t *data);
+
+/**
+ * Callback to notify received data from the remote endpoint.
+ * @param[in]   data    received data.
+ */
+typedef void (*CAReceiveThreadFunc)(CAData_t *data);
+
+/**
+ * context of blockwise transfer.
+ */
+typedef struct
+{
+    /** send method for block data. **/
+    CASendThreadFunc sendThreadFunc;
+
+    /** callback function for received message. **/
+    CAReceiveThreadFunc receivedThreadFunc;
+
+    /** array list on which the thread is operating. **/
+    u_arraylist_t *dataList;
+
+    /** data list mutex for synchronization. **/
+    ca_mutex blockDataListMutex;
+
+    /** sender mutex for synchronization. **/
+    ca_mutex blockDataSenderMutex;
+} CABlockWiseContext_t;
+
+/**
+ * ID set of Blockwise transfer data set(::CABlockData_t).
+ */
+typedef struct
+{
+    uint8_t* id;                       /**< blockData ID for CA. */
+    size_t idLength;                   /**< length of blockData ID. */
+} CABlockDataID_t;
+
+/**
+ * Block Data Set.
+ */
+typedef struct
+{
+    coap_block_t block1;                /**< block1 option. */
+    coap_block_t block2;                /**< block2 option. */
+    uint16_t type;                      /**< block option type. */
+    CABlockDataID_t* blockDataId;        /**< ID set of CABlockData. */
+    CAData_t *sentData;                 /**< sent request or response data information. */
+    CAPayload_t payload;                /**< payload buffer. */
+    size_t payloadLength;               /**< the total payload length to be received. */
+    size_t receivedPayloadLen;          /**< currently received payload length. */
+} CABlockData_t;
+
+/**
+ * state of received block message from remote endpoint.
+ */
+typedef enum
+{
+    CA_BLOCK_UNKNOWN = 0,
+    CA_OPTION1_ACK,
+    CA_OPTION1_NO_ACK_LAST_BLOCK,
+    CA_OPTION1_NO_ACK_BLOCK,
+    CA_OPTION2_FIRST_BLOCK,
+    CA_OPTION2_LAST_BLOCK,
+    CA_OPTION2_ACK,
+    CA_OPTION2_NON,
+    CA_OPTION2_CON,
+    CA_SENT_PREVIOUS_NON_MSG,
+    CA_BLOCK_INCOMPLETE,
+    CA_BLOCK_TOO_LARGE,
+    CA_BLOCK_RECEIVED_ALREADY
+} CABlockState_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Initializes the block-wise transfer context.
+ * @param[in]  CASendThreadFunc    function point to add data in send queue thread.
+ * @param[in]  CAReceiveThreadFunc function point to add data in receive queue thread.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc blockSendMethod,
+                                         CAReceiveThreadFunc receivedDataCallback);
+
+/**
+ * Terminate the block-wise transfer context.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CATerminateBlockWiseTransfer();
+
+/**
+ * initialize mutex.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAInitBlockWiseMutexVariables();
+
+/**
+ * terminate mutex.
+ */
+void CATerminateBlockWiseMutexVariables();
+
+/**
+ * Pass the bulk data. if block-wise transfer process need,
+ *          bulk data will be sent to block messages.
+ * @param[in]   data    data for sending.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendBlockWiseData(const CAData_t *data);
+
+/**
+ * Add the data to send thread queue.
+ * @param[in]   sendData    data for sending.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const CABlockDataID_t *blockID);
+
+/**
+ * Check the block option type. If it has to be sent to a block,
+ *          block option will be set.
+ * @param[in]   currData    block data.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CACheckBlockOptionType(CABlockData_t *currData);
+
+/**
+ * Pass the received pdu data. and check if block option is set.
+ * @param[in]   pdu    received pdu binary data.
+ * @param[in]   endpoint    information of remote device.
+ * @param[in]   receivedData    received CAData.
+ * @param[in]   dataLen    received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                  const CAData_t *receivedData, size_t dataLen);
+
+/**
+ * process next step by block-wise state.
+ * @param[in]   pdu    received pdu binary data.
+ * @param[in]   receivedData    received CAData.
+ * @param[in]   blockWiseStatus    block-wise state to move next step.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
+                             uint8_t blockWiseStatus, const CABlockDataID_t *blockID);
+
+/**
+ * send block message to remote device.
+ * @param[in]   pdu    received pdu binary data.
+ * @param[in]   msgType    the message type of the block.
+ * @param[in]   status    block-wise state to move next step.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
+                              uint8_t status, const CABlockDataID_t *blockID);
+
+/**
+ * send error message to remote device.
+ * @param[in]   pdu    received pdu binary data.
+ * @param[in]   status    block-wise state to move next step.
+ * @param[in]   responseResult   response result code.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
+                              CAResponseResult_t responseResult,
+                              const CABlockDataID_t *blockID);
+
+/**
+ * receive last block data.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @param[in]   receivedData    received CAData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAReceiveLastBlock(const CABlockDataID_t *blockID,
+                              const CAData_t *receivedData);
+
+/**
+ * set next block option 1.
+ * @param[in]   pdu received pdu binary data.
+ * @param[in]   endpoint  information of remote device.
+ * @param[in]   receivedData    received CAData.
+ * @param[in]   block   block option data.
+ * @param[in]   dataLen received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 const CAData_t *receivedData, coap_block_t block,
+                                 size_t dataLen);
+
+/**
+ * set next block option 2.
+ * @param[in]   pdu received pdu binary data.
+ * @param[in]   endpoint    information of remote device.
+ * @param[in]   receivedData    received CAData.
+ * @param[in]   block   block option data.
+ * @param[in]   dataLen received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 const CAData_t *receivedData, coap_block_t block,
+                                 size_t dataLen);
+
+/**
+ * Update the block option in block-wise transfer list.
+ * @param[in]   currData   stored block data information.
+ * @param[in]   block   block option to update.
+ * @param[in]   msgType message type of pdu.
+ * @param[in]   blockType   block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
+                                CAMessageType_t msgType, uint16_t blockType);
+
+/**
+ * Update the block option in block-wise transfer list.
+ * @param[in]   currData    stored block data information.
+ * @param[in]   block   block option of current message.
+ * @param[in]   blockType   block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block,
+                             uint16_t blockType);
+
+/**
+ * Update the messageId in block-wise transfer list.
+ * @param[in]   pdu   received pdu binary data.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID);
+
+/**
+ * Update the block option items.
+ * @param[in]   currData    stored block data information.
+ * @param[in]   pdu received pdu binary data.
+ * @param[in/out]   block   block option of current message.
+ * @param[in]   blockType  block option type.
+ * @param[in]   status  current flow status for block-wise transfer.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *pdu,
+                                    coap_block_t *block, uint16_t blockType,
+                                    uint32_t status);
+/**
+ * Set the M-bit of block option.
+ * @param[in]   payloadLen  payload length of current bulk data.
+ * @param[out]  block   block option.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetMoreBitFromBlock(size_t payloadLen, coap_block_t *block);
+
+/**
+ * check the block option what kind of option have to set.
+ * @param[out]  pdu pdu object.
+ * @param[in]   info    information of the request/response.
+ * @param[in]   endpoint    port of transport.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
+                            const CAEndpoint_t *endpoint);
+
+/**
+ * Write the block option2 in pdu binary data.
+ * @param[out]  pdu   pdu object.
+ * @param[in]   info    information of the request/response.
+ * @param[in]   dataLength  length of payload.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+                             const CABlockDataID_t *blockID);
+
+/**
+ * Write the block option1 in pdu binary data.
+ * @param[out]  pdu    pdu object.
+ * @param[in]   info    information of the request/response.
+ * @param[in]   dataLength length of payload.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+                             const CABlockDataID_t *blockID);
+
+/**
+ * Add the block option in pdu data.
+ * @param[in]   pdu    pdu object.
+ * @param[out]  block    block data.
+ * @param[in]   blockType   block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOptionImpl(coap_pdu_t *pdu, coap_block_t *block, uint8_t blockType);
+
+/**
+ * Add the size option in pdu data.
+ * @param[in/out]   pdu    pdu object.
+ * @param[in]   sizeType    size option type.
+ * @param[in]   dataLength the total payload length to be sent.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataLength);
+
+/**
+ * Get the size option from pdu data.
+ * @param[in]   pdu    pdu object.
+ * @param[in]   sizeType    size option type.
+ * @param[out]  totalPayloadLen the total payload length to be received.
+ * @return true or false.
+ */
+bool CAIsPayloadLengthInPduWithBlockSizeOption(coap_pdu_t *pdu,
+                                               uint16_t sizeType,
+                                               size_t *totalPayloadLen);
+
+/**
+ * update the total payload with the received payload.
+ * @param[in]   currData    stored block data information.
+ * @param[in]   receivedData    received CAData.
+ * @param[in]   status  block-wise state.
+ * @param[in]   isSizeOption    size option.
+ * @param[in]   blockType    block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdatePayloadData(CABlockData_t *currData, const CAData_t *receivedData,
+                               uint8_t status, bool isSizeOption, uint16_t blockType);
+
+/**
+ * Generate CAData structure  from the given information.
+ * @param[in]   pdu    pdu object.
+ * @param[in]   endpoint    information of remote device.
+ * @return generated CAData.
+ */
+CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint);
+
+/**
+ * Update the block option items.
+ * @param[in/out]   blockblock option of current message.
+ * @param[in]   blockType   block option type.
+ * @param[in]   responseResult  result code of pdu.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAHandleBlockErrorResponse(coap_block_t *block, uint16_t blockType,
+                                      uint32_t responseResult);
+
+/**
+ * Check the received payload and if an error happens, return error type.
+ * @param[in/out]   currData    stored block data information.
+ * @param[in]   receivedBlock   received block option.
+ * @param[in]   receivedData    message type of pdu.
+ * @param[in]   blockType   block option type.
+ * @param[in]   dataLen received data length.
+ * @return block state.
+ */
+uint8_t CACheckBlockErrorType(CABlockData_t *currData, coap_block_t *receivedBlock,
+                              const CAData_t *receivedData, uint16_t blockType,
+                              size_t dataLen);
+
+/**
+ * Destroys the given CAData.
+ * @param[in]   data    CAData to destroy.
+ * @return generated CAData.
+ */
+void CADestroyDataSet(CAData_t* data);
+
+/**
+ * Create the blockId for CABlockData.
+ * @param[in]   token   token of current message.
+ * @param[in]   tokenLength   token length of current message.
+ * @param[in]   portNumber   port.
+ * @return ID set of CABlockData.
+ */
+CABlockDataID_t* CACreateBlockDatablockId(const CAToken_t token, uint8_t tokenLength,
+                                          uint16_t portNumber);
+
+/**
+ * Destroy the blockId set.
+ * @param[in]   blockID     ID set of CABlockData.
+ */
+void CADestroyBlockID(CABlockDataID_t *blockID);
+
+/**
+ * check whether Block ID is matched or not.
+ * @param[in]   currData    block data.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return true or false.
+ */
+bool CABlockidMatches(const CABlockData_t *currData, const CABlockDataID_t *blockID);
+/**
+ * Print the given block option information.
+ * @param[in]   block   block option information.
+ */
+void CALogBlockInfo(coap_block_t *block);
+
+/**
+ * Create new CAData structure from the input information.
+ * @param[in]   data    CAData information that needs to be duplicated.
+ * @return created CAData structure.
+ */
+CAData_t *CACloneCAData(const CAData_t *data);
+
+/**
+ * Update payload from the input information.
+ * @param[in]   data    CAData information that needs to be updated.
+ * @param[in]   payload received new payload from the remote endpoint.
+ * @param[in]   payloadLen  received full payload length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdatePayloadToCAData(CAData_t *data, const CAPayload_t payload,
+                                   size_t payloadLen);
+
+/**
+ * Get payload and payload length from the input information.
+ * @param[in]   data    CAData information.
+ * @param[out]  payloadLen  The payload length is stored.
+ * @return payload.
+ */
+CAPayload_t CAGetPayloadInfo(const CAData_t *data, size_t *payloadLen);
+
+/**
+ * Set the block option type.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @param[in]   blockType   block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockOptionType(const CABlockDataID_t *blockID,
+                                   uint8_t blockType);
+
+/**
+ * Get the block option type from block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return block option type.
+ */
+uint8_t CAGetBlockOptionType(const CABlockDataID_t *blockID);
+
+/**
+ * Get the block data from block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return CAData structure.
+ */
+CAData_t *CAGetDataSetFromBlockDataList(const CABlockDataID_t *blockID);
+
+/**
+ * Get token from block-wise transfer list.
+ * @param[in]   pdu    received pdu binary data.
+ * @param[in]   endpoint    remote endpoint information.
+ * @param[in]   responseInfo    received response information.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                       CAResponseInfo_t *responseInfo);
+
+/**
+ * check whether the block data is valid or not.
+ * @param[in]   sendData    CAData information.
+ * @param[out]  blockData   block data when it is valid.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **blockData);
+
+/**
+ * Get the block data from block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return CABlockData_t structure.
+ */
+CABlockData_t *CAGetBlockDataFromBlockDataList(const CABlockDataID_t *blockID);
+
+/**
+ * Get the block option from block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @param[in]   blockType    block option type.
+ * @return coap_block_t structure.
+ */
+coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID,
+                               uint16_t blockType);
+
+/**
+ * Get the full payload from block-wise list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @param[out]  fullPayloadLen  received full payload length.
+ * @return payload.
+ */
+CAPayload_t CAGetPayloadFromBlockDataList(const CABlockDataID_t *blockID,
+                                          size_t *fullPayloadLen);
+
+/**
+ * Create the block data from given data and add the data in block-wise transfer list.
+ * @param[in]   sendData    data to be added to a list.
+ * @return created CABlockData_t structure.
+ *         and NULL point will be returned if there is error case..
+ */
+CABlockData_t *CACreateNewBlockData(const CAData_t *sendData);
+
+/**
+ * Remove the block data in block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID);
+
+/**
+ * Check if data exist in block-wise transfer list.
+ * @param[in]   blockID     ID set of CABlockData.
+ * @return true or false.
+ */
+bool CAIsBlockDataInList(const CABlockDataID_t *blockID);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif  // CA_BLOCKWISETRANSFER_H_
index 9e58735..986738f 100644 (file)
 #define CA_MEMORY_ALLOC_CHECK(arg) { if (NULL == arg) {OIC_LOG(ERROR, TAG, "Out of memory"); \
 goto memory_error_exit;} }
 
+typedef enum
+{
+    SEND_TYPE_MULTICAST = 0, SEND_TYPE_UNICAST
+} CASendDataType_t;
+
+typedef enum
+{
+    CA_REQUEST_DATA = 1,
+    CA_RESPONSE_DATA = 2,
+    CA_ERROR_DATA = 3,
+} CADataType_t;
+
+typedef struct
+{
+    CASendDataType_t type;
+    CAEndpoint_t *remoteEndpoint;
+    CARequestInfo_t *requestInfo;
+    CAResponseInfo_t *responseInfo;
+    CAErrorInfo_t *errorInfo;
+    CAHeaderOption_t *options;
+    CADataType_t dataType;
+    uint8_t numOptions;
+} CAData_t;
+
 #ifdef __cplusplus
 extern "C"
 {
index f45831a..792ee92 100644 (file)
@@ -74,6 +74,7 @@
 #define COAP_OPTION_PROXY_URI    35 /* C, String, 1-1034 B, (none) */
 #define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
 #define COAP_OPTION_SIZE1        60 /* E, uint, 0-4 B, (none) */
+#define COAP_OPTION_SIZE2        28 /* E, uint, 0-4 B, (none) */
 
 /* option types from draft-ietf-coap-observe-09 */
 
old mode 100755 (executable)
new mode 100644 (file)
index 7a91274..33da629
@@ -77,6 +77,9 @@ else:
                'caqueueingthread.c',
                'caretransmission.c',
                ]
+       if (('BT' in ca_transport) or ('IP' in ca_transport) or ('ALL' in ca_transport)):
+               env.AppendUnique(CA_SRC = [os.path.join(ca_path, 'cablockwisetransfer.c') ])
+               env.AppendUnique(CPPDEFINES = ['WITH_BWT'])
        if secured == '1':
                env.AppendUnique(CPPDEFINES = ['__WITH_DTLS__'])
                 if ca_os == 'tizen':
index 5c7ae30..1ad2980 100644 (file)
 #include "cacommon.h"
 #include "caedrdevicelist.h"
 
+#define MICROSECS_PER_SEC 1000000
+
+/**
+ * Condition to check if OIC supported device is found.
+ */
+static ca_cond g_deviceDescCond = NULL;
+
+/**
+ * Flag that will be set when EDR adapter is stopped.
+ */
+static bool g_isStopping = false;
+
 /**
  * @var g_edrDeviceListMutex
  * @brief Mutex to synchronize the access to Bluetooth device information list.
@@ -307,6 +319,8 @@ void CAEDRDeviceDiscoveryCallback(int result, bt_adapter_device_discovery_state_
                         return;
                     }
                     device->serviceSearched = true;
+                    // Signal the wait to send the data.
+                    ca_cond_signal(g_deviceDescCond);
                     ca_mutex_unlock(g_edrDeviceListMutex);
                 }
                 else
@@ -478,20 +492,13 @@ CAResult_t CAEDRClientSetCallbacks(void)
 {
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN");
 
+    g_isStopping = false;
     // Register for discovery and rfcomm socket connection callbacks
     bt_adapter_set_device_discovery_state_changed_cb(CAEDRDeviceDiscoveryCallback, NULL);
     bt_device_set_service_searched_cb(CAEDRServiceSearchedCallback, NULL);
     bt_socket_set_connection_state_changed_cb(CAEDRSocketConnectionStateCallback, NULL);
     bt_socket_set_data_received_cb(CAEDRDataRecvCallback, NULL);
 
-    // Start device discovery
-    CAResult_t result = CAEDRStartDeviceDiscovery();
-    if(CA_STATUS_OK != result)
-    {
-        OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "Failed to Start Device discovery");
-        return CA_STATUS_FAILED;
-    }
-
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "OUT");
     return CA_STATUS_OK;
 }
@@ -507,6 +514,10 @@ void CAEDRClientUnsetCallbacks(void)
     // Stop the device discovery process
     CAEDRStopDeviceDiscovery();
 
+    // Signal the conditional wait for discovery of devices.
+    g_isStopping = true;
+    ca_cond_signal(g_deviceDescCond);
+
     // reset bluetooth adapter callbacks
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "Resetting the callbacks");
     bt_adapter_unset_device_discovery_state_changed_cb();
@@ -526,6 +537,11 @@ void CAEDRManagerInitializeMutex(void)
         g_edrDeviceListMutex = ca_mutex_new();
     }
 
+    if (!g_deviceDescCond)
+    {
+        g_deviceDescCond = ca_cond_new();
+    }
+
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "OUT");
 }
 
@@ -539,6 +555,11 @@ void CAEDRManagerTerminateMutex(void)
         g_edrDeviceListMutex = NULL;
     }
 
+    if (g_deviceDescCond)
+    {
+        ca_cond_free(g_deviceDescCond);
+        g_deviceDescCond = NULL;
+    }
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "OUT");
 }
 
@@ -718,6 +739,38 @@ CAResult_t CAEDRClientSendMulticastData(const char *serviceUUID, const void *dat
 
     // Send the packet to all OIC devices
     ca_mutex_lock(g_edrDeviceListMutex);
+
+    // Check if any device is discovered.
+    if (NULL == g_edrDeviceList)
+    {
+        // Wait for BT devices to be discovered.
+        CAResult_t result = CAEDRStartDeviceDiscovery();
+        if(CA_STATUS_OK != result)
+        {
+            OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "Failed to Start Device discovery");
+            return CA_STATUS_FAILED;
+        }
+
+        // Number of times to wait for discovery to complete.
+        int const RETRIES = 5;
+
+        uint64_t const TIMEOUT = 4 * MICROSECS_PER_SEC;  // Microseconds
+
+        bool devicesDiscovered = false;
+        for (size_t i = 0; i < RETRIES && !g_isStopping; ++i)
+        {
+            if (ca_cond_wait_for(g_deviceDescCond, g_edrDeviceListMutex,
+                                 TIMEOUT) == 0)
+            {
+                devicesDiscovered = true;
+            }
+        }
+        if (!devicesDiscovered || g_isStopping)
+        {
+            goto exit;
+        }
+    }
+
     EDRDeviceList *curList = g_edrDeviceList;
     CAResult_t result = CA_STATUS_FAILED;
     while (curList != NULL)
@@ -733,7 +786,6 @@ CAResult_t CAEDRClientSendMulticastData(const char *serviceUUID, const void *dat
 
         if (-1 == device->socketFD)
         {
-            OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN1");
             // Check if the device service search is finished
             if (false == device->serviceSearched)
             {
@@ -760,20 +812,18 @@ CAResult_t CAEDRClientSendMulticastData(const char *serviceUUID, const void *dat
                 CARemoveEDRDataFromList(&device->pendingDataList);
                 continue;
             }
-            OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN2");
         }
         else
         {
-            OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN3");
             result = CAEDRSendData(device->socketFD, data, dataLength, sentLength);
             if (CA_STATUS_OK != result)
             {
                 OIC_LOG_V(ERROR, EDR_ADAPTER_TAG, "Failed to send data to [%s] !",
                           device->remoteAddress);
             }
-            OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN4");
         }
     }
+exit:
     ca_mutex_unlock(g_edrDeviceListMutex);
 
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "OUT");
diff --git a/resource/csdk/connectivity/src/cablockwisetransfer.c b/resource/csdk/connectivity/src/cablockwisetransfer.c
new file mode 100644 (file)
index 0000000..54dda9b
--- /dev/null
@@ -0,0 +1,2611 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+// Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
+// definitions that may otherwise be skipped. Skipping can cause implicit
+// declaration warnings and/or bugs and subtle problems in code execution.
+// For glibc information on feature test macros,
+// Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
+//
+// This file requires #define use due to random()
+// For details on compatibility and glibc support,
+// Refer http://www.gnu.org/software/libc/manual/html_node/BSD-Random.html
+#define _DEFAULT_SOURCE
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "caadapterutils.h"
+#include "cainterface.h"
+#include "camessagehandler.h"
+#include "caremotehandler.h"
+#include "cablockwisetransfer.h"
+#include "oic_malloc.h"
+#include "camutex.h"
+#include "logger.h"
+
+#define TAG "CA_BWT"
+
+#define BLOCKWISE_OPTION_BUFFER    (sizeof(unsigned int))
+#define BLOCK_NUMBER_IDX           4
+#define BLOCK_M_BIT_IDX            3
+#define PORT_LENGTH                2
+
+#define BLOCK_SIZE(arg) (1 << ((arg) + 4))
+
+// context for block-wise transfer
+static CABlockWiseContext_t g_context = { 0 };
+
+CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc sendThreadFunc,
+                                         CAReceiveThreadFunc receivedThreadFunc)
+{
+    OIC_LOG(DEBUG, TAG, "initialize");
+
+    // set block-wise transfer context
+    if (!g_context.sendThreadFunc)
+    {
+        g_context.sendThreadFunc = sendThreadFunc;
+    }
+
+    if (!g_context.receivedThreadFunc)
+    {
+        g_context.receivedThreadFunc = receivedThreadFunc;
+    }
+
+    if (!g_context.dataList)
+    {
+        g_context.dataList = u_arraylist_create();
+    }
+
+    CAResult_t res = CAInitBlockWiseMutexVariables();
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "init has failed");
+    }
+
+    return res;
+}
+
+CAResult_t CATerminateBlockWiseTransfer()
+{
+    OIC_LOG(DEBUG, TAG, "terminate");
+
+    if (g_context.dataList)
+    {
+        u_arraylist_free(&g_context.dataList);
+    }
+
+    CATerminateBlockWiseMutexVariables();
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAInitBlockWiseMutexVariables()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    if (NULL == g_context.blockDataListMutex)
+    {
+        g_context.blockDataListMutex = ca_mutex_new();
+        if (NULL == g_context.blockDataListMutex)
+        {
+            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_context.blockDataSenderMutex)
+    {
+        g_context.blockDataSenderMutex = ca_mutex_new();
+        if (NULL == g_context.blockDataSenderMutex)
+        {
+            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            CATerminateBlockWiseMutexVariables();
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+void CATerminateBlockWiseMutexVariables()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    if (g_context.blockDataListMutex)
+    {
+        ca_mutex_free(g_context.blockDataListMutex);
+        g_context.blockDataListMutex = NULL;
+    }
+
+    if (g_context.blockDataSenderMutex)
+    {
+        ca_mutex_free(g_context.blockDataSenderMutex);
+        g_context.blockDataSenderMutex = NULL;
+    }
+}
+
+CAResult_t CASendBlockWiseData(const CAData_t *sendData)
+{
+    VERIFY_NON_NULL(sendData, TAG, "sendData");
+
+    // check if message type is CA_MSG_RESET
+    if (NULL != sendData->responseInfo)
+    {
+        if (CA_MSG_RESET == sendData->responseInfo->info.type)
+        {
+            OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
+            return CA_NOT_SUPPORTED;
+        }
+    }
+
+    // #1. check if it is already included in block data list
+    CABlockData_t *currData = NULL;
+    CAResult_t res = CACheckBlockDataValidation(sendData, &currData);
+    if (CA_STATUS_OK != res)
+    {
+        // #2. if it is not included, add the data into list
+        if (NULL == currData)
+        {
+            OIC_LOG(DEBUG, TAG, "There is no block data");
+            currData = CACreateNewBlockData(sendData);
+            if (NULL == currData)
+            {
+                OIC_LOG(ERROR, TAG, "failed to create block data");
+                return CA_MEMORY_ALLOC_FAILED;
+            }
+        }
+    }
+
+    // #3. check request/response block option type and payload length
+    res = CACheckBlockOptionType(currData);
+    if (CA_STATUS_OK == res)
+    {
+        // #4. send block message
+        OIC_LOG(DEBUG, TAG, "send first block msg");
+        res = CAAddSendThreadQueue(currData->sentData, (const CABlockDataID_t *)&currData->blockDataId);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            return res;
+        }
+    }
+
+    return res;
+}
+
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL(sendData, TAG, "sendData");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    CAData_t *cloneData = CACloneCAData(sendData);
+    if (NULL == cloneData)
+    {
+        OIC_LOG(ERROR, TAG, "clone has failed");
+        CARemoveBlockDataFromList(blockID);
+        return CA_STATUS_FAILED;
+    }
+
+    if (g_context.sendThreadFunc)
+    {
+        ca_mutex_lock(g_context.blockDataSenderMutex);
+        g_context.sendThreadFunc(cloneData);
+        ca_mutex_unlock(g_context.blockDataSenderMutex);
+    }
+    else
+    {
+        CADestroyDataSet(cloneData);
+    }
+    return CA_STATUS_OK;
+}
+
+CAResult_t CACheckBlockOptionType(CABlockData_t *currData)
+{
+    VERIFY_NON_NULL(currData, TAG, "currData");
+    VERIFY_NON_NULL(currData->sentData, TAG, "currData->sentData");
+
+    size_t payloadLen = 0;
+    CAGetPayloadInfo(currData->sentData, &payloadLen);
+
+    // check if message has to be transfered to a block
+    size_t maxBlockSize = BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE);
+    if (payloadLen <= maxBlockSize)
+    {
+        OIC_LOG_V(DEBUG, TAG, "payloadLen=%d, maxBlockSize=%d", payloadLen, maxBlockSize);
+        return CA_NOT_SUPPORTED;
+    }
+
+    // set block option (COAP_OPTION_BLOCK2 or COAP_OPTION_BLOCK1)
+    if (NULL != currData->sentData->requestInfo) // request message
+    {
+        currData->type = COAP_OPTION_BLOCK1;
+    }
+    else // response message
+    {
+        currData->type = COAP_OPTION_BLOCK2;
+    }
+
+    return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                  const CAData_t *receivedData, size_t dataLen)
+{
+    OIC_LOG(DEBUG, TAG, "CAReceiveBlockWiseData");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+    // check if received message type is CA_MSG_RESET
+    if (CA_EMPTY == pdu->hdr->code)
+    {
+        OIC_LOG(DEBUG, TAG, "code is CA_EMPTY..");
+
+        // get token from block-wise transfer list when CA_EMPTY(RST/ACK) is received
+        CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint, receivedData->responseInfo);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "fail to get token");
+            return res;
+        }
+
+        CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+                receivedData->responseInfo->info.token,
+                receivedData->responseInfo->info.tokenLength,
+                endpoint->port);
+        if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+        {
+            OIC_LOG(ERROR, TAG, "blockId is null");
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+
+        CARemoveBlockDataFromList(blockDataID);
+        CADestroyBlockID(blockDataID);
+        return CA_NOT_SUPPORTED;
+    }
+
+    // check if block option is set and get block data
+    coap_block_t block = {0, 0, 0};
+
+    // get block1 option
+    int isBlock1 = coap_get_block(pdu, COAP_OPTION_BLOCK1, &block);
+    if (isBlock1)
+    {
+        CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, block, dataLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "setting has failed");
+            return res;
+        }
+    }
+
+    // get block2 option
+    int isBlock2 = coap_get_block(pdu, COAP_OPTION_BLOCK2, &block);
+    if (isBlock2)
+    {
+        CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, block, dataLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "setting has failed");
+            return res;
+        }
+    }
+
+    // check if there is error code
+    if (!isBlock1 && !isBlock2)
+    {
+        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+        if (CA_REQUEST_ENTITY_INCOMPLETE == code)
+        {
+            CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+                    (CAToken_t)pdu->hdr->token,
+                     pdu->hdr->token_length,
+                     endpoint->port);
+
+            if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+            {
+                OIC_LOG(ERROR, TAG, "blockId is null");
+                CADestroyBlockID(blockDataID);
+                return CA_STATUS_FAILED;
+            }
+
+            CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+            if (NULL == data)
+            {
+                OIC_LOG(ERROR, TAG, "getting has failed");
+                CADestroyBlockID(blockDataID);
+                return CA_STATUS_FAILED;
+            }
+
+            if (COAP_OPTION_BLOCK2 == data->type)
+            {
+                coap_block_t *block2 = CAGetBlockOption(blockDataID,
+                                                        COAP_OPTION_BLOCK2);
+                if (NULL == block2)
+                {
+                    OIC_LOG(ERROR, TAG, "block is null");
+                    CADestroyBlockID(blockDataID);
+                    return CA_STATUS_FAILED;
+                }
+
+                CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block2,
+                                                       dataLen);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "setting has failed");
+                    CADestroyBlockID(blockDataID);
+                    return res;
+                }
+            }
+            else if (COAP_OPTION_BLOCK1 == data->type)
+            {
+                coap_block_t *block1 = CAGetBlockOption(blockDataID,
+                                                        COAP_OPTION_BLOCK1);
+                if (NULL == block1)
+                {
+                    OIC_LOG(ERROR, TAG, "block is null");
+                    CADestroyBlockID(blockDataID);
+                    return CA_STATUS_FAILED;
+                }
+
+                CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block1,
+                                                       dataLen);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "setting has failed");
+                    CADestroyBlockID(blockDataID);
+                    return res;
+                }
+            }
+        }
+        else
+        {
+            // normal pdu data
+            OIC_LOG(DEBUG, TAG, "it's normal pdu");
+
+            // if received data is response message
+            // and sent data remain in block data list, remove block data
+            if (receivedData->responseInfo)
+            {
+                CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint,
+                                                             receivedData->responseInfo);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "fail to get token");
+                    return res;
+                }
+            }
+            return CA_NOT_SUPPORTED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
+                             uint8_t blockWiseStatus, const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    CAResult_t res = CA_STATUS_OK;
+    CAData_t *data = NULL;
+
+    // process blockWiseStatus
+    switch (blockWiseStatus)
+    {
+        case CA_OPTION2_FIRST_BLOCK:
+            res = CAAddSendThreadQueue(receivedData, blockID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                return res;
+            }
+            break;
+
+        case CA_OPTION2_CON:
+            // add data to send thread
+            data = CAGetDataSetFromBlockDataList(blockID);
+            if (NULL == data)
+            {
+                OIC_LOG(ERROR, TAG, "it's unavailable");
+                return CA_STATUS_FAILED;
+            }
+
+            if (data->requestInfo)
+            {
+                data->requestInfo->info.messageId = pdu->hdr->id;
+            }
+
+            if (data->responseInfo)
+            {
+                data->responseInfo->info.messageId = pdu->hdr->id;
+            }
+
+            res = CAAddSendThreadQueue(data, blockID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                return res;
+            }
+
+            break;
+
+        case CA_OPTION1_ACK:
+        case CA_OPTION2_ACK:
+        case CA_SENT_PREVIOUS_NON_MSG:
+            res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
+                                     blockID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "send has failed");
+                return res;
+            }
+            break;
+
+        case CA_OPTION2_LAST_BLOCK:
+            // process last block and send upper layer
+            res = CAReceiveLastBlock(blockID, receivedData);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "receive has failed");
+                return res;
+            }
+
+            // remove data from list
+            res = CARemoveBlockDataFromList(blockID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "remove has failed");
+                return res;
+            }
+            break;
+
+        case CA_OPTION1_NO_ACK_LAST_BLOCK:
+            // process last block and send upper layer
+            res = CAReceiveLastBlock(blockID, receivedData);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "receive has failed");
+                return res;
+            }
+
+            if (CA_MSG_NONCONFIRM == pdu->hdr->type)
+            {
+                // remove data from list
+                res = CARemoveBlockDataFromList(blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "remove has failed");
+                    return res;
+                }
+            }
+            break;
+
+        case CA_OPTION1_NO_ACK_BLOCK:
+            if (CA_MSG_CONFIRM == pdu->hdr->type)
+            {
+                // add data to send thread
+                res = CASendBlockMessage(pdu, CA_MSG_ACKNOWLEDGE, blockWiseStatus,
+                                         blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "send has failed");
+                    return res;
+                }
+            }
+            break;
+
+        case CA_BLOCK_INCOMPLETE:
+            if (CA_MSG_CONFIRM == pdu->hdr->type || CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            {
+                // add data to send thread
+                res = CASendErrorMessage(pdu, blockWiseStatus,
+                                         CA_REQUEST_ENTITY_INCOMPLETE,
+                                         blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "send has failed");
+                    return res;
+                }
+            }
+            break;
+
+        case CA_BLOCK_TOO_LARGE:
+            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            {
+                res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
+                                         blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "send has failed");
+                    return res;
+                }
+            }
+            else if (CA_MSG_CONFIRM == pdu->hdr->type)
+            {
+                res = CASendErrorMessage(pdu, blockWiseStatus,
+                                         CA_REQUEST_ENTITY_TOO_LARGE,
+                                         blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "send has failed");
+                    return res;
+                }
+            }
+            break;
+        default:
+            OIC_LOG_V(ERROR, TAG, "no logic [%d]", blockWiseStatus);
+    }
+    return CA_STATUS_OK;
+}
+
+CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
+                              uint8_t status, const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    CAData_t *data = CAGetDataSetFromBlockDataList(blockID);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "CAData is unavailable");
+        return CA_STATUS_FAILED;
+    }
+
+    if (CA_MSG_CONFIRM == msgType)
+    {
+        OIC_LOG(DEBUG, TAG, "need new msgID");
+        if (data->requestInfo)
+        {
+            data->requestInfo->info.messageId = 0;
+        }
+
+        if (data->responseInfo)
+        {
+            data->responseInfo->info.messageId = 0;
+        }
+    }
+    else if (CA_MSG_ACKNOWLEDGE == msgType)
+    {
+        if (data->responseInfo)
+        {
+            OIC_LOG(DEBUG, TAG, "set ACK message");
+            data->responseInfo->info.messageId = pdu->hdr->id;
+            data->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
+            if (CA_OPTION1_NO_ACK_LAST_BLOCK == status)
+            {
+                data->responseInfo->result = CA_CHANGED;
+            }
+            else if (CA_OPTION1_NO_ACK_BLOCK == status)
+            {
+                data->responseInfo->result = CA_CONTINUE;
+            }
+        }
+    }
+
+    // add data to send thread
+    CAResult_t res = CAAddSendThreadQueue(data, blockID);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "add has failed");
+    }
+
+    return res;
+}
+
+CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
+                              CAResponseResult_t responseResult,
+                              const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    // create error responseInfo
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockID);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "data is unavailable");
+        return CA_STATUS_FAILED;
+    }
+
+    CAData_t *cloneData = NULL;
+    if (data->sentData && data->sentData->responseInfo)
+    {
+        data->sentData->responseInfo->info.messageId = pdu->hdr->id;
+        data->sentData->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
+        data->sentData->responseInfo->result = responseResult;
+        cloneData = CACloneCAData(data->sentData);
+        if (NULL == cloneData)
+        {
+            OIC_LOG(ERROR, TAG, "clone has failed");
+            return CA_MEMORY_ALLOC_FAILED;
+        }
+        OIC_LOG(DEBUG, TAG, "set ACK message");
+    }
+    else if (data->sentData)
+    {
+        cloneData = CACreateNewDataSet(pdu, data->sentData->remoteEndpoint);
+
+        if(!cloneData)
+        {
+            OIC_LOG(ERROR, TAG, PCF("CACreateNewDataSet failed"));
+            return CA_MEMORY_ALLOC_FAILED;
+        }
+
+        cloneData->responseInfo->info.type = CA_MSG_CONFIRM;
+        cloneData->responseInfo->result = responseResult;
+        OIC_LOG(DEBUG, TAG, "set CON message");
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "data has no sent-data");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    // add data to send thread
+    if (g_context.sendThreadFunc)
+    {
+        ca_mutex_lock(g_context.blockDataSenderMutex);
+        g_context.sendThreadFunc(cloneData);
+        ca_mutex_unlock(g_context.blockDataSenderMutex);
+    }
+    else
+    {
+        CADestroyDataSet(cloneData);
+    }
+
+    // if error code is 4.08, remove the stored payload and initialize block number
+    if (CA_BLOCK_INCOMPLETE == status)
+    {
+        OICFree(data->payload);
+        data->payload = NULL;
+        data->payloadLength = 0;
+        data->receivedPayloadLen = 0;
+        data->block1.num = 0;
+        data->block2.num = 0;
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAReceiveLastBlock(const CABlockDataID_t *blockID,
+                              const CAData_t *receivedData)
+{
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+    // total block data have to notify to Application
+    CAData_t *cloneData = CACloneCAData(receivedData);
+    if (NULL == cloneData)
+    {
+        OIC_LOG(ERROR, TAG, "clone has failed");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    // update payload
+    size_t fullPayloadLen = 0;
+    CAPayload_t fullPayload = CAGetPayloadFromBlockDataList(blockID,
+                                                            &fullPayloadLen);
+    if (NULL != fullPayload)
+    {
+        CAResult_t res = CAUpdatePayloadToCAData(cloneData, fullPayload, fullPayloadLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CADestroyDataSet(cloneData);
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (g_context.receivedThreadFunc)
+    {
+        g_context.receivedThreadFunc(cloneData);
+    }
+    else
+    {
+        CADestroyDataSet(cloneData);
+    }
+
+    return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 const CAData_t *receivedData, coap_block_t block,
+                                 size_t dataLen)
+{
+    OIC_LOG(INFO, TAG, "CASetNextBlockOption1");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+    OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
+
+    CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+            (CAToken_t)pdu->hdr->token,
+            pdu->hdr->token_length,
+            endpoint->port);
+
+    if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+    {
+        OIC_LOG(ERROR, TAG, "blockId is null");
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    // BlockData data is created if it not existed
+    if (!CAIsBlockDataInList(blockDataID))
+    {
+        OIC_LOG(DEBUG, TAG, "no message in list");
+
+        CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+        if (NULL == data)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+
+        CABlockData_t *currData = CACreateNewBlockData(data);
+        if (NULL == currData)
+        {
+            OIC_LOG(ERROR, TAG, "currData is null");
+            CADestroyDataSet(data);
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    // update BLOCK OPTION1 type
+    CAResult_t res = CAUpdateBlockOptionType(blockDataID,
+                                             COAP_OPTION_BLOCK1);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "update has failed");
+        CARemoveBlockDataFromList(blockDataID);
+        CADestroyBlockID(blockDataID);
+        return res;
+    }
+
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
+    // received type from remote device
+    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+    {
+        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+        if (0 == block.m &&
+                (CA_REQUEST_ENTITY_INCOMPLETE != code && CA_REQUEST_ENTITY_TOO_LARGE != code))
+        {
+            OIC_LOG(INFO, TAG, "Data has sent");
+            // initialize block number for response message
+            data->block1.num = 0;
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_OK;
+        }
+
+        blockWiseStatus = CA_OPTION1_ACK;
+        res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+
+        res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CARemoveBlockDataFromList(blockDataID);
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+    }
+    else // CON or NON message
+    {
+        OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
+
+        // check the size option
+        bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
+                                                                      COAP_OPTION_SIZE1,
+                                                                      &(data->payloadLength));
+
+        // check if received payload is exact
+        if (CA_MSG_CONFIRM == pdu->hdr->type)
+        {
+            blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
+                                                    COAP_OPTION_BLOCK1, dataLen);
+        }
+
+        if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
+        {
+            // store the received payload and merge
+            res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
+                                      isSizeOption, COAP_OPTION_BLOCK1);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(blockDataID);
+                CADestroyBlockID(blockDataID);
+                return res;
+            }
+
+            res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(blockDataID);
+                CADestroyBlockID(blockDataID);
+                return res;
+            }
+
+            // update block data
+            res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(blockDataID);
+                CADestroyBlockID(blockDataID);
+                return res;
+            }
+        }
+
+        // check the blcok-wise transfer status for next step
+        if (CA_BLOCK_UNKNOWN == blockWiseStatus || CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
+        {
+            if (0 == block.m) // Last block is received
+            {
+                OIC_LOG(DEBUG, TAG, "M bit is 0");
+                blockWiseStatus = CA_OPTION1_NO_ACK_LAST_BLOCK;
+            }
+            else
+            {
+                OIC_LOG(DEBUG, TAG, "M bit is 1");
+                blockWiseStatus = CA_OPTION1_NO_ACK_BLOCK;
+            }
+        }
+    }
+
+    res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "setting has failed");
+        CARemoveBlockDataFromList(blockDataID);
+    }
+
+    CADestroyBlockID(blockDataID);
+    return res;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 const CAData_t *receivedData, coap_block_t block,
+                                 size_t dataLen)
+{
+    OIC_LOG(DEBUG, TAG, "CASetNextBlockOption2");
+    OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
+
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+    CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+            (CAToken_t)pdu->hdr->token,
+            pdu->hdr->token_length,
+            endpoint->port);
+
+    if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+    {
+        OIC_LOG(ERROR, TAG, "blockId is null");
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    // BlockData data is created if it not existed
+    if (!CAIsBlockDataInList(blockDataID))
+    {
+        OIC_LOG(DEBUG, TAG, "no msg in list.");
+
+        CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+        if (NULL == data)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+
+        CABlockData_t *currData = CACreateNewBlockData(data);
+        if (NULL == currData)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            CADestroyDataSet(data);
+            CADestroyBlockID(blockDataID);
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    // set Block Option Type
+    CAResult_t res = CAUpdateBlockOptionType(blockDataID,
+                                             COAP_OPTION_BLOCK2);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "update has failed");
+        CARemoveBlockDataFromList(blockDataID);
+        CADestroyBlockID(blockDataID);
+        return res;
+    }
+
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        CARemoveBlockDataFromList(blockDataID);
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
+    if (0 == block.num && CA_GET == pdu->hdr->code && 0 == block.m)
+    {
+        OIC_LOG(INFO, TAG, "first block number");
+
+        res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CARemoveBlockDataFromList(blockDataID);
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+
+        // first block data have to notify to Application
+        res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CARemoveBlockDataFromList(blockDataID);
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+        blockWiseStatus = CA_OPTION2_FIRST_BLOCK;
+    }
+    else
+    {
+        // received type from remote device
+        if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type ||
+                (CA_MSG_NONCONFIRM == pdu->hdr->type && NULL != receivedData->responseInfo))
+        {
+            OIC_LOG(DEBUG, TAG, "received ACK or NON");
+
+            // check the size option
+            bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
+                                                                          COAP_OPTION_SIZE2,
+                                                                          &(data->payloadLength));
+
+            // check if received payload is exact
+            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            {
+                blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
+                                                        COAP_OPTION_BLOCK2, dataLen);
+            }
+
+            if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
+            {
+                // store the received payload and merge
+                res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
+                                          isSizeOption, COAP_OPTION_BLOCK2);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "update has failed");
+                    CARemoveBlockDataFromList(blockDataID);
+                    CADestroyBlockID(blockDataID);
+                    return res;
+                }
+            }
+
+            if (0 == block.m && CA_BLOCK_UNKNOWN == blockWiseStatus) // Last block is received
+            {
+                OIC_LOG(DEBUG, TAG, "M bit is 0");
+                blockWiseStatus = CA_OPTION2_LAST_BLOCK;
+            }
+            else
+            {
+                if (CA_BLOCK_UNKNOWN == blockWiseStatus ||
+                        CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
+                {
+                    OIC_LOG(DEBUG, TAG, "M bit is 1");
+
+                    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+                    {
+                        blockWiseStatus = CA_OPTION2_ACK;
+                    }
+                    else
+                    {
+                        blockWiseStatus = CA_OPTION2_NON;
+                    }
+                }
+
+                res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2,
+                                               blockWiseStatus);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "update has failed");
+                    CARemoveBlockDataFromList(blockDataID);
+                    CADestroyBlockID(blockDataID);
+                    return res;
+                }
+
+                res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "update has failed");
+                    CARemoveBlockDataFromList(blockDataID);
+                    CADestroyBlockID(blockDataID);
+                    return res;
+                }
+            }
+        }
+        else // CON message and so on.
+        {
+            OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
+
+            blockWiseStatus = CA_OPTION2_CON;
+
+            res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(blockDataID);
+                CADestroyBlockID(blockDataID);
+                return res;
+            }
+
+            res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(blockDataID);
+                CADestroyBlockID(blockDataID);
+                return res;
+            }
+        }
+    }
+
+    res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "setting has failed");
+        CARemoveBlockDataFromList(blockDataID);
+        CADestroyBlockID(blockDataID);
+        return res;
+    }
+
+    CADestroyBlockID(blockDataID);
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *pdu,
+                                    coap_block_t *block, uint16_t blockType,
+                                    uint32_t status)
+{
+    VERIFY_NON_NULL(currData, TAG, "currData");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(block, TAG, "block");
+
+    // update block data
+    CAResult_t res = CA_STATUS_OK;
+    uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+
+    if (CA_REQUEST_ENTITY_INCOMPLETE == code || CA_REQUEST_ENTITY_TOO_LARGE == code)
+    {
+        // response error code of the received block message
+        res = CAHandleBlockErrorResponse(block, blockType, code);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "error handle has failed");
+            return res;
+        }
+    }
+    else
+    {
+        // update block option items
+        switch (status)
+        {
+            case CA_OPTION1_ACK:
+                if (currData->block1.num > block->num)
+                {
+                    OIC_LOG(ERROR, TAG, "received incorrect block num");
+                    return CA_STATUS_FAILED;
+                }
+                block->num++;
+                break;
+            case CA_OPTION2_NON:
+                block->num++;
+                block->m = 0;
+                break;
+            case CA_OPTION2_CON:
+                block->m = 0;
+                break;
+            case CA_OPTION2_ACK:
+                if (currData->block2.num > block->num)
+                {
+                    OIC_LOG(ERROR, TAG, "received incorrect block num");
+                    return CA_STATUS_FAILED;
+                }
+                block->num++;
+                block->m = 0;
+                break;
+            case CA_BLOCK_TOO_LARGE:
+                // if state of received block message is CA_BLOCK_TOO_LARGE or CA_BLOCK_INCOMPLETE
+                // we set the response error code appropriately and send
+                if (COAP_OPTION_BLOCK2 == blockType)
+                {
+                    block->num++;
+                    block->m = 0;
+                    block->szx = currData->block2.szx;
+                }
+                else
+                {
+                    block->szx = currData->block1.szx;
+                }
+                break;
+            default:
+                OIC_LOG_V(ERROR, TAG, "no logic [%d]", status);
+        }
+
+        if (CA_BLOCK_INCOMPLETE != status && CA_BLOCK_TOO_LARGE != status)
+        {
+            // negotiate block size
+            res = CANegotiateBlockSize(currData, block, pdu->hdr->type, blockType);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "negotiation has failed");
+                return res;
+            }
+        }
+    }
+    return res;
+}
+
+CAResult_t CAGetMoreBitFromBlock(size_t payloadLen, coap_block_t *block)
+{
+    VERIFY_NON_NULL(block, TAG, "block");
+
+    if ((size_t)((block->num + 1) << (block->szx + BLOCK_NUMBER_IDX))
+        < payloadLen)
+    {
+        OIC_LOG(DEBUG, TAG, "Set the M-bit(1)");
+        block->m = 1;
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "Set the M-bit(0)");
+        block->m = 0;
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
+                                CAMessageType_t msgType, uint16_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-NegotiateBlockSize");
+
+    VERIFY_NON_NULL(currData, TAG, "currData");
+    VERIFY_NON_NULL(block, TAG, "block");
+
+    // #1. check the block option type
+    if (COAP_OPTION_BLOCK2 == blockType)
+    {
+        // #2. check the message type
+        if (CA_MSG_ACKNOWLEDGE == msgType)
+        {
+            if (block->szx > currData->block2.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is big");
+
+                // #3. calculate new block number from block size
+                unsigned int blockNum = BLOCK_SIZE(block->szx) /
+                                        BLOCK_SIZE(currData->block2.szx) - 1;
+                OIC_LOG(DEBUG, TAG, "num is set as Negotiation");
+                block->num += blockNum;
+                block->szx = currData->block2.szx;
+                OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
+            }
+        }
+        else
+        {
+            if (block->szx > currData->block2.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is big");
+                block->szx = currData->block2.szx;
+            }
+        }
+    }
+    else if (COAP_OPTION_BLOCK1 == blockType)
+    {
+        if (CA_MSG_ACKNOWLEDGE == msgType)
+        {
+            if (block->szx < currData->block1.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is small");
+
+                unsigned int blockNum = BLOCK_SIZE(currData->block1.szx) /
+                                        BLOCK_SIZE(block->szx) - 1;
+                block->num += blockNum;
+                OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
+            }
+        }
+        else
+        {
+            if (block->szx > currData->block1.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is big");
+                block->szx = currData->block1.szx;
+            }
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "Invalid block option");
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-NegotiateBlockSize");
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block,
+                             uint16_t blockType)
+{
+    VERIFY_NON_NULL(currData, TAG, "currData");
+
+    // check if block size is bigger than CABlockSize_t
+    if (block.szx > CA_BLOCK_SIZE_1024_BYTE)
+    {
+        OIC_LOG(DEBUG, TAG, "invalid block szx");
+        return CA_STATUS_FAILED;
+    }
+
+    // update block option
+    if (COAP_OPTION_BLOCK2 == blockType)
+    {
+        currData->block2 = block;
+    }
+    else
+    {
+        currData->block1 = block;
+    }
+
+    OIC_LOG(DEBUG, TAG, "data has updated");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    // if CON message is sent, update messageId in block-wise transfer list
+    if (CA_MSG_CONFIRM == pdu->hdr->type)
+    {
+        CAData_t * cadata = CAGetDataSetFromBlockDataList(blockID);
+        if (NULL == cadata)
+        {
+            OIC_LOG(ERROR, TAG, "CAData is unavailable");
+            return CA_STATUS_FAILED;
+        }
+
+        if (NULL != cadata->requestInfo)
+        {
+            cadata->requestInfo->info.messageId = pdu->hdr->id;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
+                            const CAEndpoint_t *endpoint)
+{
+    OIC_LOG(DEBUG, TAG, "IN-AddBlockOption");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+    VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+
+    size_t dataLength = 0;
+    if (info.payload)
+    {
+        dataLength = info.payloadSize;
+        OIC_LOG_V(DEBUG, TAG, "dataLength - %d", dataLength);
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "previous payload - %s", (*pdu)->data);
+
+    uint32_t code = CA_RESPONSE_CODE((*pdu)->hdr->code);
+    if (CA_REQUEST_ENTITY_INCOMPLETE == code)
+    {
+        OIC_LOG(INFO, TAG, "don't use option");
+        return CA_STATUS_OK;
+    }
+
+    CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+            (CAToken_t)(*pdu)->hdr->token,
+            (*pdu)->hdr->token_length,
+            endpoint->port);
+
+    if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+    {
+        OIC_LOG(ERROR, TAG, "blockId is null");
+        CADestroyBlockID(blockDataID);
+        return CA_STATUS_FAILED;
+    }
+
+    uint8_t blockType = CAGetBlockOptionType(blockDataID);
+    if (COAP_OPTION_BLOCK2 == blockType)
+    {
+        CAResult_t res = CAAddBlockOption2(pdu, info, dataLength,
+                                           blockDataID);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+    }
+    else if (COAP_OPTION_BLOCK1 == blockType)
+    {
+        CAResult_t res = CAAddBlockOption1(pdu, info, dataLength,
+                                           blockDataID);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CADestroyBlockID(blockDataID);
+            return res;
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "no BLOCK option");
+        // if response data is so large. it have to send as block transfer
+        if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info.payload))
+        {
+            OIC_LOG(INFO, TAG, "it have to use block");
+        }
+        else
+        {
+            OIC_LOG(INFO, TAG, "not Blockwise Transfer");
+        }
+    }
+
+    CAResult_t res = CAUpdateMessageId(*pdu, blockDataID);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "fail to update CON message id ");
+        CADestroyBlockID(blockDataID);
+        return res;
+    }
+
+    CADestroyBlockID(blockDataID);
+    OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+                             const CABlockDataID_t *blockID)
+{
+    OIC_LOG(DEBUG, TAG, "IN-AddBlockOption2");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+    VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    // get set block data from CABlock list-set.
+    coap_block_t *block1 = CAGetBlockOption(blockID,
+                                            COAP_OPTION_BLOCK1);
+    coap_block_t *block2 = CAGetBlockOption(blockID,
+                                            COAP_OPTION_BLOCK2);
+    if (!block1 || !block2)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    CALogBlockInfo(block2);
+
+    uint8_t code = 0;
+    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type ||
+            (CA_MSG_NONCONFIRM == (*pdu)->hdr->type && CA_GET != (*pdu)->hdr->code))
+    {
+        int32_t res = coap_write_block_opt(block2, COAP_OPTION_BLOCK2, *pdu, dataLength);
+        switch (res)
+        {
+            case -2: /* illegal block */
+                code = COAP_RESPONSE_CODE(CA_BAD_REQ);
+                OIC_LOG(ERROR, TAG, "write block option : -2");
+                goto error;
+            case -1: /* should really not happen */
+                OIC_LOG(ERROR, TAG, "write block option : -1");
+                break;
+            case -3: /* cannot handle request */
+                code = COAP_RESPONSE_CODE(CA_INTERNAL_SERVER_ERROR);
+                OIC_LOG(ERROR, TAG, "write block option : -3");
+                goto error;
+            default:
+                OIC_LOG(INFO, TAG, "success write block option");
+        }
+        CALogBlockInfo(block2);
+
+        if (block1->num)
+        {
+            OIC_LOG(DEBUG, TAG, "combining block1 and block2");
+            CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                CARemoveBlockDataFromList(blockID);
+                return res;
+            }
+            // initialize block number
+            block1->num = 0;
+        }
+
+        // if block number is 0, add size2 option
+        if (0 == block2->num)
+        {
+            res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE2, dataLength);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                CARemoveBlockDataFromList(blockID);
+                return res;
+            }
+        }
+
+        if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+                            block2->num, block2->szx))
+        {
+            OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
+            return CA_STATUS_FAILED;
+        }
+
+        if (!block2->m)
+        {
+            // if sent message is last response block message, remove data
+            CARemoveBlockDataFromList(blockID);
+        }
+        else
+        {
+            if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+            {
+                OIC_LOG(DEBUG, TAG, "NON, send next block..");
+                // update block data
+                block2->num++;
+                CAResult_t res = CAProcessNextStep(*pdu, NULL,
+                                                   CA_SENT_PREVIOUS_NON_MSG,
+                                                   blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "failed to process next step");
+                    CARemoveBlockDataFromList(blockID);
+                    return res;
+                }
+            }
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "option2, not ACK msg");
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block2, COAP_OPTION_BLOCK2);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList(blockID);
+            return res;
+        }
+    }
+
+    return CA_STATUS_OK;
+
+error:
+    OIC_LOG_V(ERROR, TAG, "error : %d", code);
+
+    char* phrase = coap_response_phrase(code);
+    if(phrase)
+    {
+        coap_add_data(*pdu, strlen(phrase),
+                      (unsigned char *) phrase);
+    }
+    return CA_STATUS_FAILED;
+}
+
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+                             const CABlockDataID_t *blockID)
+{
+    OIC_LOG(DEBUG, TAG, "IN-AddBlockOption1");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+    VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    // get set block data from CABlock list-set.
+    coap_block_t *block1 = CAGetBlockOption(blockID,
+                                            COAP_OPTION_BLOCK1);
+    if (NULL == block1)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    CALogBlockInfo(block1);
+
+    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type)
+    {
+        OIC_LOG(DEBUG, TAG, "option1 and ACK msg..");
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList(blockID);
+            return res;
+        }
+
+        // reset block-list after write block
+        if (0 == block1->m)
+        {
+            // remove data from list
+            CAResult_t res = CARemoveBlockDataFromList(blockID);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "remove has failed");
+                return res;
+            }
+        }
+    }
+    else
+    {
+        CAGetMoreBitFromBlock(dataLength, block1);
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList(blockID);
+            return res;
+        }
+        CALogBlockInfo(block1);
+
+        // if block number is 0, add size1 option
+        if (0 == block1->num)
+        {
+            res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE1, dataLength);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                CARemoveBlockDataFromList(blockID);
+                return res;
+            }
+        }
+
+        if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+                            block1->num, block1->szx))
+        {
+            OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
+            return CA_STATUS_FAILED;
+        }
+
+        // check the message type and if message type is NON, next block message will be sent
+        if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+        {
+            if (block1->m)
+            {
+                OIC_LOG(DEBUG, TAG, "NON, send next block..");
+                // update block data
+                block1->num++;
+                CAResult_t res = CAProcessNextStep(*pdu, NULL,
+                                                   CA_SENT_PREVIOUS_NON_MSG,
+                                                   blockID);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "failed to process next step");
+                    CARemoveBlockDataFromList(blockID);
+                    return res;
+                }
+            }
+            else
+            {
+                CARemoveBlockDataFromList(blockID);
+            }
+        }
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption1");
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOptionImpl(coap_pdu_t *pdu, coap_block_t *block, uint8_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-AddBlockOptionImpl");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(block, TAG, "block");
+
+    coap_option *option = (coap_option *) OICMalloc(sizeof(coap_option));
+    if (NULL == option)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    unsigned char buf[BLOCKWISE_OPTION_BUFFER] = { 0 };
+    option->key = blockType;
+    option->length = coap_encode_var_bytes(buf,
+                                           ((block->num << BLOCK_NUMBER_IDX)
+                                            | (block->m << BLOCK_M_BIT_IDX) | block->szx));
+    if (!coap_add_option(pdu, option->key, option->length, buf))
+    {
+        OIC_LOG(ERROR, TAG, "coap_add_option has failed");
+        OICFree(option);
+        return CA_STATUS_FAILED;
+    }
+
+    OICFree(option);
+
+    OIC_LOG(DEBUG, TAG, "OUT-AddBlockOptionImpl");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataLength)
+{
+    OIC_LOG(DEBUG, TAG, "IN-CAAddBlockSizeOption");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+
+    if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
+    {
+        OIC_LOG(ERROR, TAG, "unknown option type");
+        return CA_STATUS_FAILED;
+    }
+
+    unsigned char value[BLOCKWISE_OPTION_BUFFER] = { 0 };
+    unsigned int optionLength = coap_encode_var_bytes(value, dataLength);
+
+    if (!coap_add_option(pdu, sizeType, optionLength, value))
+    {
+        OIC_LOG(ERROR, TAG, "failed to add size option");
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-CAAddBlockSizeOption");
+
+    return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+bool CAIsPayloadLengthInPduWithBlockSizeOption(coap_pdu_t *pdu,
+                                               uint16_t sizeType,
+                                               size_t *totalPayloadLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN-CAIsPayloadLengthInPduWithBlockSizeOption");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(totalPayloadLen, TAG, "totalPayloadLen");
+
+    if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
+    {
+        OIC_LOG(ERROR, TAG, "unknown option type");
+        return CA_STATUS_FAILED;
+    }
+
+    coap_opt_iterator_t opt_iter;
+    coap_opt_t *option = coap_check_option(pdu, sizeType, &opt_iter);
+    if (option)
+    {
+        OIC_LOG(DEBUG, TAG, "get size option from pdu");
+        *totalPayloadLen = coap_decode_var_bytes(COAP_OPT_VALUE(option),
+                                                 COAP_OPT_LENGTH(option));
+
+        OIC_LOG_V(DEBUG, TAG, "the total payload length to be received is [%d]bytes",
+                  *totalPayloadLen);
+
+        return true;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-CAIsPayloadLengthInPduWithBlockSizeOption");
+
+    return false;
+}
+
+uint8_t CACheckBlockErrorType(CABlockData_t *currData, coap_block_t *receivedBlock,
+                              const CAData_t *receivedData, uint16_t blockType,
+                              size_t dataLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN-CheckBlockError");
+
+    VERIFY_NON_NULL(currData, TAG, "currData is NULL");
+    VERIFY_NON_NULL(receivedBlock, TAG, "receivedBlock is NULL");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData is NULL");
+
+    // #1. check the received payload length
+    size_t blockPayloadLen = 0;
+    CAGetPayloadInfo(receivedData, &blockPayloadLen);
+
+    // #2. check if the block sequence is right
+    if (COAP_OPTION_BLOCK1 == blockType)
+    {
+        size_t prePayloadLen = currData->receivedPayloadLen;
+        if (prePayloadLen != (size_t)BLOCK_SIZE(receivedBlock->szx)
+            * receivedBlock->num)
+        {
+            if (receivedBlock->num > currData->block1.num + 1)
+            {
+                // 408 Error handling of block loss
+                OIC_LOG(ERROR, TAG, "option1: error 4.08");
+                OIC_LOG(ERROR, TAG, "it didn't order");
+                return CA_BLOCK_INCOMPLETE;
+            }
+            return CA_BLOCK_RECEIVED_ALREADY;
+        }
+    }
+    else if (COAP_OPTION_BLOCK2 == blockType)
+    {
+        if (receivedBlock->num != currData->block2.num)
+        {
+            if (receivedBlock->num > currData->block2.num)
+            {
+                // 408 Error handling of block loss
+                OIC_LOG(ERROR, TAG, "option2: error 4.08");
+                OIC_LOG(ERROR, TAG, "it didn't order");
+                return CA_BLOCK_INCOMPLETE;
+            }
+            return CA_BLOCK_RECEIVED_ALREADY;
+        }
+    }
+
+    // #3. check if error check logic is required
+    size_t optionLen = dataLen - blockPayloadLen;
+    if (receivedBlock->m && blockPayloadLen !=
+        (size_t)BLOCK_SIZE(receivedBlock->szx))
+    {
+        // 413 Error handling of too large entity
+        if (COAP_MAX_PDU_SIZE < BLOCK_SIZE(receivedBlock->szx) + optionLen)
+        {
+            // buffer size is smaller than received block size
+            OIC_LOG(ERROR, TAG, "error type 4.13");
+            OIC_LOG(ERROR, TAG, "too large size");
+
+            // set the block size to be smaller than COAP_MAX_PDU_SIZE
+            for (int32_t size = CA_DEFAULT_BLOCK_SIZE; size >= 0; size--)
+            {
+                if (COAP_MAX_PDU_SIZE >= BLOCK_SIZE(size) + optionLen)
+                {
+                    OIC_LOG_V(ERROR, TAG, "replace sze with %d", size);
+                    if (COAP_OPTION_BLOCK2 == blockType)
+                    {
+                        currData->block2.szx = size;
+                    }
+                    else
+                    {
+                        currData->block1.szx = size;
+                    }
+                    break;
+                }
+            }
+            return CA_BLOCK_TOO_LARGE;
+        }
+        else
+        {
+            // 408 Error handling of payload loss
+            OIC_LOG(ERROR, TAG, "error type 4.08");
+            OIC_LOG(ERROR, TAG, "payload len != block sze");
+            return CA_BLOCK_INCOMPLETE;
+        }
+    }
+    else if (0 == receivedBlock->m && 0 != currData->payloadLength)
+    {
+        // if the received block is last block, check the total payload length
+        size_t receivedPayloadLen = currData->receivedPayloadLen;
+        receivedPayloadLen += blockPayloadLen;
+
+        if (receivedPayloadLen != currData->payloadLength)
+        {
+            OIC_LOG(ERROR, TAG, "error type 4.08");
+            OIC_LOG(ERROR, TAG, "total payload length is wrong");
+            return CA_BLOCK_INCOMPLETE;
+        }
+    }
+
+    OIC_LOG(DEBUG, TAG, "received all data normally");
+
+    OIC_LOG(DEBUG, TAG, "OUT-CheckBlockError");
+
+    return CA_BLOCK_UNKNOWN;
+}
+
+CAResult_t CAUpdatePayloadData(CABlockData_t *currData, const CAData_t *receivedData,
+                               uint8_t status, bool isSizeOption, uint16_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-UpdatePayloadData");
+
+    VERIFY_NON_NULL(currData, TAG, "currData");
+    VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+    // if error code is 4.08, do not update payload
+    if (CA_BLOCK_INCOMPLETE == status)
+    {
+        OIC_LOG(ERROR, TAG, "no require to update");
+        return CA_STATUS_OK;
+    }
+
+    size_t blockPayloadLen = 0;
+    CAPayload_t blockPayload = CAGetPayloadInfo(receivedData, &blockPayloadLen);
+
+    if (CA_BLOCK_TOO_LARGE == status)
+    {
+        blockPayloadLen = (COAP_OPTION_BLOCK2 == blockType) ?
+                BLOCK_SIZE(currData->block2.szx) : BLOCK_SIZE(currData->block1.szx);
+    }
+
+    // memory allocation for the received block payload
+    size_t prePayloadLen = currData->receivedPayloadLen;
+    if (NULL != blockPayload)
+    {
+        if (0 != currData->payloadLength)
+        {
+            // in case the block message has the size option
+            // allocate the memory for the total payload
+            if (true == isSizeOption)
+            {
+                CAPayload_t prePayload = currData->payload;
+
+                OIC_LOG(DEBUG, TAG, "allocate memory for the total payload");
+                currData->payload = (CAPayload_t) OICCalloc(currData->payloadLength + 1,
+                                                            sizeof(char));
+                if (NULL == currData->payload)
+                {
+                    OIC_LOG(ERROR, TAG, "out of memory");
+                    return CA_MEMORY_ALLOC_FAILED;
+                }
+                memcpy(currData->payload, prePayload, prePayloadLen);
+                OICFree(prePayload);
+            }
+
+            // update the total payload
+            memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
+        }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "allocate memory for the received block payload");
+
+            size_t totalPayloadLen = prePayloadLen + blockPayloadLen + 1;
+            CAPayload_t newPayload = OICRealloc(currData->payload, totalPayloadLen);
+            if (NULL == newPayload)
+            {
+                OIC_LOG(ERROR, TAG, "out of memory");
+                return CA_MEMORY_ALLOC_FAILED;
+            }
+
+            // update the total payload
+            memset(newPayload + prePayloadLen, 0, blockPayloadLen + 1);
+            currData->payload = newPayload;
+            memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
+        }
+
+        // update received payload length
+        currData->receivedPayloadLen += blockPayloadLen;
+
+        OIC_LOG_V(DEBUG, TAG, "updated payload: %s, len: %d", currData->payload,
+                  currData->receivedPayloadLen);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-UpdatePayloadData");
+    return CA_STATUS_OK;
+}
+
+CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint)
+{
+    VERIFY_NON_NULL_RET(pdu, TAG, "pdu", NULL);
+    VERIFY_NON_NULL_RET(pdu->hdr, TAG, "pdu->hdr", NULL);
+    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
+
+    CAInfo_t responseData = { .tokenLength = pdu->hdr->token_length };
+    responseData.token = (CAToken_t) OICMalloc(responseData.tokenLength);
+    if (NULL == responseData.token)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return NULL;
+    }
+    memcpy(responseData.token, pdu->hdr->token, responseData.tokenLength);
+
+    CAResponseInfo_t* responseInfo = (CAResponseInfo_t*) OICCalloc(1, sizeof(CAResponseInfo_t));
+    if (NULL == responseInfo)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        OICFree(responseData.token);
+        return NULL;
+    }
+    responseInfo->info = responseData;
+
+    CAData_t *data = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        OICFree(responseInfo);
+        return NULL;
+    }
+
+    data->requestInfo = NULL;
+    data->responseInfo = responseInfo;
+    data->remoteEndpoint = CACloneEndpoint(endpoint);
+    data->type = SEND_TYPE_UNICAST;
+
+    return data;
+}
+
+CAData_t *CACloneCAData(const CAData_t *data)
+{
+    VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
+
+    CAData_t *clone = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
+    if (NULL == clone)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return NULL;
+    }
+    *clone = *data;
+
+    if (data->requestInfo)
+    {
+        clone->requestInfo = CACloneRequestInfo(data->requestInfo);
+    }
+
+    if (data->responseInfo)
+    {
+        clone->responseInfo = CACloneResponseInfo(data->responseInfo);
+    }
+
+    if (data->remoteEndpoint)
+    {
+        clone->remoteEndpoint = CACloneEndpoint(data->remoteEndpoint);
+    }
+
+    return clone;
+}
+
+CAResult_t CAUpdatePayloadToCAData(CAData_t *data, const CAPayload_t payload,
+                                   size_t payloadLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN-UpdatePayload");
+
+    VERIFY_NON_NULL(data, TAG, "data is NULL");
+    VERIFY_NON_NULL(payload, TAG, "payload is NULL");
+
+    if (NULL != data->requestInfo)
+    {
+        // allocate payload field
+        if (NULL != data->requestInfo->info.payload)
+        {
+            char *temp = (char *) OICCalloc(payloadLen, sizeof(char));
+            if (NULL == temp)
+            {
+                OIC_LOG(ERROR, TAG, "out of memory");
+                return CA_STATUS_FAILED;
+            }
+            memcpy(temp, payload, payloadLen);
+
+            // save the full payload
+            OICFree(data->requestInfo->info.payload);
+            data->requestInfo->info.payload = (CAPayload_t) temp;
+        }
+        data->requestInfo->info.payloadSize = payloadLen;
+    }
+
+    if (NULL != data->responseInfo)
+    {
+        // allocate payload field
+        if (NULL != data->responseInfo->info.payload)
+        {
+            char *temp = (char *) OICCalloc(payloadLen, sizeof(char));
+            if (NULL == temp)
+            {
+                OIC_LOG(ERROR, TAG, "out of memory");
+                return CA_STATUS_FAILED;
+            }
+            memcpy(temp, payload, payloadLen);
+
+            // save the full payload
+            OICFree(data->responseInfo->info.payload);
+            data->responseInfo->info.payload = (CAPayload_t) temp;
+        }
+        data->responseInfo->info.payloadSize = payloadLen;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-UpdatePayload");
+
+    return CA_STATUS_OK;
+}
+
+CAPayload_t CAGetPayloadInfo(const CAData_t *data, size_t *payloadLen)
+{
+    VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
+    VERIFY_NON_NULL_RET(payloadLen, TAG, "payloadLen", NULL);
+
+    if (NULL != data->requestInfo)
+    {
+        if (NULL != data->requestInfo->info.payload)
+        {
+            *payloadLen = data->requestInfo->info.payloadSize;
+            return data->requestInfo->info.payload;
+        }
+    }
+    else
+    {
+        if (NULL != data->responseInfo->info.payload)
+        {
+            *payloadLen = data->responseInfo->info.payloadSize;
+            return data->responseInfo->info.payload;
+        }
+    }
+
+    return NULL;
+}
+
+CAResult_t CAHandleBlockErrorResponse(coap_block_t *block, uint16_t blockType,
+                                      uint32_t responseResult)
+{
+    OIC_LOG(DEBUG, TAG, "IN-HandleBlockErrorRes");
+    VERIFY_NON_NULL(block, TAG, "block is NULL");
+
+    // update block data
+    switch (responseResult)
+    {
+        case CA_REQUEST_ENTITY_INCOMPLETE:
+            block->num = 0;
+            break;
+        case CA_REQUEST_ENTITY_TOO_LARGE:
+            if (COAP_OPTION_BLOCK1 == blockType)
+            {
+                block->num++;
+            }
+            block->m = 0;
+            break;
+        default:
+            OIC_LOG_V(ERROR, TAG, "there is no Error Code of BWT[%d]", responseResult);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-HandleBlockErrorRes");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockOptionType(const CABlockDataID_t *blockID,
+                                   uint8_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-UpdateBlockOptionType");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            currData->type = blockType;
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
+            return CA_STATUS_OK;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
+    return CA_STATUS_FAILED;
+}
+
+uint8_t CAGetBlockOptionType(const CABlockDataID_t *blockID)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetBlockOptionType");
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", 0);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
+            return currData->type;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
+    return 0;
+}
+
+CAData_t *CAGetDataSetFromBlockDataList(const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            return currData->sentData;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return NULL;
+}
+
+CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                       CAResponseInfo_t *responseInfo)
+{
+    OIC_LOG(DEBUG, TAG, "IN-CAGetTokenFromBlockDataList");
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+    VERIFY_NON_NULL(responseInfo, TAG, "responseInfo");
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (NULL == currData)
+        {
+            continue;
+        }
+
+        if (NULL != currData->sentData && NULL != currData->sentData->requestInfo)
+        {
+            if (pdu->hdr->id == currData->sentData->requestInfo->info.messageId &&
+                    endpoint->adapter == currData->sentData->remoteEndpoint->adapter)
+            {
+                if (NULL != currData->sentData->requestInfo->info.token)
+                {
+                    uint8_t length = currData->sentData->requestInfo->info.tokenLength;
+                    responseInfo->info.tokenLength = length;
+                    responseInfo->info.token = (char *) OICMalloc(length);
+                    if (NULL == responseInfo->info.token)
+                    {
+                        OIC_LOG(ERROR, TAG, "out of memory");
+                        ca_mutex_unlock(g_context.blockDataListMutex);
+                        return CA_MEMORY_ALLOC_FAILED;
+                    }
+                    memcpy(responseInfo->info.token, currData->sentData->requestInfo->info.token,
+                           responseInfo->info.tokenLength);
+
+                    ca_mutex_unlock(g_context.blockDataListMutex);
+                    OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
+                    return CA_STATUS_OK;
+                }
+            }
+        }
+    }
+
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **blockData)
+{
+    VERIFY_NON_NULL(sendData, TAG, "sendData");
+    VERIFY_NON_NULL(blockData, TAG, "blockData");
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+
+        if (NULL == currData)
+        {
+            continue;
+        }
+
+        if (NULL != sendData->requestInfo) // sendData is requestMessage
+        {
+            OIC_LOG(DEBUG, TAG, "Send request");
+            if (NULL != currData->blockDataId
+                    && NULL != currData->blockDataId->id
+                    && currData->blockDataId->idLength > 0
+                    && NULL != sendData->requestInfo->info.token)
+            {
+                CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+                        (CAToken_t)sendData->requestInfo->info.token,
+                        sendData->requestInfo->info.tokenLength,
+                        sendData->remoteEndpoint->port);
+
+                if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+                {
+                    OIC_LOG(ERROR, TAG, "blockId is null");
+                    CADestroyBlockID(blockDataID);
+                    return CA_STATUS_FAILED;
+                }
+
+                if (CABlockidMatches(currData, blockDataID))
+                {
+                    OIC_LOG(ERROR, TAG, "already sent");
+                    CADestroyBlockID(blockDataID);
+                    continue;
+                }
+                CADestroyBlockID(blockDataID);
+            }
+        }
+        else if (NULL != sendData->responseInfo) // sendData is responseMessage
+        {
+            OIC_LOG(DEBUG, TAG, "Send response");
+            if (NULL != currData->blockDataId
+                    && NULL != currData->blockDataId->id
+                    && currData->blockDataId->idLength > 0
+                    && NULL != sendData->responseInfo->info.token)
+            {
+                CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+                        (CAToken_t)sendData->responseInfo->info.token,
+                        sendData->responseInfo->info.tokenLength,
+                        sendData->remoteEndpoint->port);
+
+                if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+                {
+                    OIC_LOG(ERROR, TAG, "blockId is null");
+                    CADestroyBlockID(blockDataID);
+                    return CA_STATUS_FAILED;
+                }
+
+                if (CABlockidMatches(currData, blockDataID))
+                {
+                    // set sendData
+                    if (NULL != currData->sentData)
+                    {
+                        OIC_LOG(DEBUG, TAG, "init block number");
+                        CADestroyDataSet(currData->sentData);
+                    }
+                    currData->sentData = CACloneCAData(sendData);
+                    *blockData = currData;
+                    CADestroyBlockID(blockDataID);
+                    ca_mutex_unlock(g_context.blockDataListMutex);
+                    return CA_STATUS_OK;
+                }
+                CADestroyBlockID(blockDataID);
+            }
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "no CAInfo data");
+            continue;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return CA_STATUS_FAILED;
+}
+
+CABlockData_t *CAGetBlockDataFromBlockDataList(const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            return currData;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return NULL;
+}
+
+coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID,
+                               uint16_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetBlockOption");
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+            if (COAP_OPTION_BLOCK2 == blockType)
+            {
+                return &currData->block2;
+            }
+            else
+            {
+                return &currData->block1;
+            }
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+    return NULL;
+}
+
+CAPayload_t CAGetPayloadFromBlockDataList(const CABlockDataID_t *blockID,
+                                          size_t *fullPayloadLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetFullPayload");
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+    VERIFY_NON_NULL_RET(fullPayloadLen, TAG, "fullPayloadLen", NULL);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            *fullPayloadLen = currData->receivedPayloadLen;
+            OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
+            return currData->payload;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
+    return NULL;
+}
+
+CABlockData_t *CACreateNewBlockData(const CAData_t *sendData)
+{
+    OIC_LOG(DEBUG, TAG, "IN-CACreateNewBlockData");
+    VERIFY_NON_NULL_RET(sendData, TAG, "sendData", NULL);
+
+    // create block data
+    CABlockData_t *data = (CABlockData_t *) OICCalloc(1, sizeof(CABlockData_t));
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "memory alloc has failed");
+        return NULL;
+    }
+
+    data->block1.szx = CA_DEFAULT_BLOCK_SIZE;
+    data->block2.szx = CA_DEFAULT_BLOCK_SIZE;
+    data->sentData = CACloneCAData(sendData);
+    if(!data->sentData)
+    {
+        OIC_LOG(ERROR, TAG, PCF("memory alloc has failed"));
+        OICFree(data);
+        return NULL;
+    }
+
+    CAToken_t token = NULL;
+    uint8_t tokenLength = 0;
+    if (data->sentData->requestInfo)
+    {
+        // update token info
+        tokenLength = data->sentData->requestInfo->info.tokenLength;
+        token = data->sentData->requestInfo->info.token;
+    }
+    else if(data->sentData->responseInfo)
+    {
+        tokenLength = data->sentData->responseInfo->info.tokenLength;
+        token = data->sentData->responseInfo->info.token;
+    }
+
+    CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+            token, tokenLength,
+            data->sentData->remoteEndpoint->port);
+    if (NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+    {
+        OIC_LOG(ERROR, TAG, "blockId is null");
+        CADestroyBlockID(blockDataID);
+        return NULL;
+    }
+    data->blockDataId = blockDataID;
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    CAResult_t res = u_arraylist_add(g_context.dataList, (void *) data);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "add has failed(%d)", res);
+        CADestroyBlockID(data->blockDataId);
+        OICFree(data);
+        ca_mutex_unlock(g_context.blockDataListMutex);
+        return NULL;
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-CreateBlockData");
+    return data;
+}
+
+CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID)
+{
+    OIC_LOG(DEBUG, TAG, "CARemoveBlockData");
+    VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            CABlockData_t *removedData = u_arraylist_remove(g_context.dataList, i);
+            if (NULL == removedData)
+            {
+                OIC_LOG(ERROR, TAG, "data is NULL");
+                ca_mutex_unlock(g_context.blockDataListMutex);
+                return CA_STATUS_FAILED;
+            }
+
+            // destroy memory
+            if (currData->sentData)
+            {
+                CADestroyDataSet(currData->sentData);
+            }
+            OICFree(currData->payload);
+            CADestroyBlockID(currData->blockDataId);
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            return CA_STATUS_OK;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return CA_STATUS_OK;
+}
+
+bool CAIsBlockDataInList(const CABlockDataID_t *blockID)
+{
+    OIC_LOG(DEBUG, TAG, "IN-IsBlockDataInList");
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    size_t len = u_arraylist_length(g_context.dataList);
+    for (size_t i = 0; i < len; i++)
+    {
+        CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+        if (CABlockidMatches(currData, blockID))
+        {
+            OIC_LOG(DEBUG, TAG, "found block data");
+            ca_mutex_unlock(g_context.blockDataListMutex);
+            return true;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-IsBlockDataInList");
+    return false;
+}
+
+void CADestroyDataSet(CAData_t* data)
+{
+    VERIFY_NON_NULL_VOID(data, TAG, "data");
+
+    CAFreeEndpoint(data->remoteEndpoint);
+    CADestroyRequestInfoInternal(data->requestInfo);
+    CADestroyResponseInfoInternal(data->responseInfo);
+    OICFree(data);
+}
+
+CABlockDataID_t* CACreateBlockDatablockId(const CAToken_t token, uint8_t tokenLength,
+                                          uint16_t portNumber)
+{
+    VERIFY_NON_NULL_RET(token, TAG, "token", NULL);
+
+    char port[PORT_LENGTH] = {0,};
+    port[0] = (char)((portNumber>>8) & 0xFF);
+    port[1] = (char)(portNumber & 0xFF);
+
+    CABlockDataID_t* blockDataID = (CABlockDataID_t *) OICMalloc(sizeof(CABlockDataID_t));
+    blockDataID->idLength = tokenLength + sizeof(port);
+    blockDataID->id = (uint8_t *) OICMalloc(blockDataID->idLength);
+    if (!blockDataID->id)
+    {
+        OIC_LOG(ERROR, TAG, "memory alloc has failed");
+        OICFree(blockDataID);
+        return NULL;
+    }
+
+    memcpy(blockDataID->id, token, tokenLength);
+    memcpy(blockDataID->id + tokenLength, port, sizeof(port));
+
+    OIC_LOG(DEBUG, TAG, "BlockID is ");
+    OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)blockDataID->id, blockDataID->idLength);
+
+    return blockDataID;
+}
+
+void CADestroyBlockID(CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL_VOID(blockID, TAG, "blockID");
+    OICFree(blockID->id);
+    OICFree(blockID);
+    blockID = NULL;
+}
+
+bool CABlockidMatches(const CABlockData_t *currData, const CABlockDataID_t *blockID)
+{
+    VERIFY_NON_NULL_RET(currData, TAG, "currData", false);
+    VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
+    VERIFY_NON_NULL_RET(blockID->id, TAG, "blockID->id", false);
+
+    if ((currData->blockDataId)
+        && (currData->blockDataId->id)
+        && (currData->blockDataId->idLength == blockID->idLength)
+        && !memcmp(currData->blockDataId->id, blockID->id, currData->blockDataId->idLength))
+    {
+        return true;
+    }
+    return false;
+}
+
+void CALogBlockInfo(coap_block_t *block)
+{
+    VERIFY_NON_NULL_VOID(block, TAG, "block");
+
+    OIC_LOG(DEBUG, TAG, "block option info");
+
+    OIC_LOG_V(DEBUG, TAG, "block option-num : %d", block->num);
+
+    OIC_LOG_V(DEBUG, TAG, "block option-m   : %d", block->m);
+
+    OIC_LOG_V(DEBUG, TAG, "block option-szx : %d", block->szx);
+}
index 6c4a81f..cb41241 100644 (file)
@@ -412,6 +412,10 @@ CAResult_t CASendMulticastData(const CAEndpoint_t *endpoint, const void *data, u
         }
 
         CATransportAdapter_t connType = *(CATransportAdapter_t *)ptrType;
+        if (0 == (endpoint->adapter & connType))
+        {
+            continue;
+        }
 
         int index = CAGetAdapterIndex(connType);
 
index 9695e2f..38d722c 100644 (file)
 #include "caprotocolmessage.h"
 #include "caretransmission.h"
 #include "caadapterutils.h"
+
+#ifdef WITH_BWT
+#include "cablockwisetransfer.h"
+#endif
+
 #include "uqueue.h"
 #include "logger.h"
 #include "config.h" /* for coap protocol */
 
 #define MAX_THREAD_POOL_SIZE    20
 
-typedef enum
-{
-    SEND_TYPE_MULTICAST = 0, SEND_TYPE_UNICAST
-} CASendDataType_t;
-
-typedef enum
-{
-    CA_REQUEST_DATA = 1,
-    CA_RESPONSE_DATA = 2,
-    CA_ERROR_DATA = 3,
-} CADataType_t;
-
-typedef struct
-{
-    CASendDataType_t type;
-    CAEndpoint_t *remoteEndpoint;
-    CARequestInfo_t *requestInfo;
-    CAResponseInfo_t *responseInfo;
-    CAErrorInfo_t *errorInfo;
-    CAHeaderOption_t *options;
-    CADataType_t dataType;
-    uint8_t numOptions;
-} CAData_t;
-
 // thread pool handle
 static ca_thread_pool_t g_threadPoolHandle = NULL;
 
@@ -87,6 +68,30 @@ static void CAErrorHandler(const CAEndpoint_t *endpoint,
                            const void *data, uint32_t dataLen,
                            CAResult_t result);
 
+#ifdef WITH_BWT
+void CAAddDataToSendThread(CAData_t *data)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    VERIFY_NON_NULL_VOID(data, TAG, "data");
+
+    // add thread
+    CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+void CAAddDataToReceiveThread(CAData_t *data)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CAAddDataToReceiveThread");
+    VERIFY_NON_NULL_VOID(data, TAG, "data");
+
+    // add thread
+    CAQueueingThreadAddData(&g_receiveThread, data, sizeof(CAData_t));
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAAddDataToReceiveThread");
+}
+#endif
+
 static bool CAIsSelectedNetworkAvailable()
 {
     u_arraylist_t *list = CAGetSelectedNetworkList();
@@ -247,6 +252,7 @@ static void CASendThreadProcess(void *threadData)
     CASendDataType_t type = data->type;
 
     coap_pdu_t *pdu = NULL;
+    CAInfo_t *info = NULL;
 
     if (SEND_TYPE_UNICAST == type)
     {
@@ -256,12 +262,14 @@ static void CASendThreadProcess(void *threadData)
         {
             OIC_LOG(DEBUG, TAG, "requestInfo is available..");
 
+            info = &data->requestInfo->info;
             pdu = CAGeneratePDU(data->requestInfo->method, &data->requestInfo->info);
         }
         else if (NULL != data->responseInfo)
         {
             OIC_LOG(DEBUG, TAG, "responseInfo is available..");
 
+            info = &data->responseInfo->info;
             pdu = CAGeneratePDU(data->responseInfo->result, &data->responseInfo->info);
         }
         else
@@ -273,6 +281,24 @@ static void CASendThreadProcess(void *threadData)
         // interface controller function call.
         if (NULL != pdu)
         {
+#ifdef WITH_BWT
+            if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+            {
+                // Blockwise transfer
+                if (NULL != info)
+                {
+                    CAResult_t res = CAAddBlockOption(&pdu, *info,
+                                                      data->remoteEndpoint);
+                    if (CA_STATUS_OK != res)
+                    {
+                        OIC_LOG(INFO, TAG, "to write block option has failed");
+                        CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res);
+                        coap_delete_pdu(pdu);
+                        return;
+                    }
+                }
+            }
+#endif
             CALogPDUInfo(pdu);
 
             res = CASendUnicastData(data->remoteEndpoint, pdu->hdr, pdu->length);
@@ -314,6 +340,21 @@ static void CASendThreadProcess(void *threadData)
             pdu = CAGeneratePDU(CA_GET, info);
             if (NULL != pdu)
             {
+#ifdef WITH_BWT
+                if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+                {
+                    // Blockwise transfer
+                    CAResult_t res = CAAddBlockOption(&pdu, data->requestInfo->info,
+                                                      data->remoteEndpoint);
+                    if (CA_STATUS_OK != res)
+                    {
+                        OIC_LOG(DEBUG, TAG, "CAAddBlockOption has failed");
+                        CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res);
+                        coap_delete_pdu(pdu);
+                        return;
+                    }
+                }
+#endif
                 CALogPDUInfo(pdu);
 
                 res = CASendMulticastData(data->remoteEndpoint, pdu->hdr, pdu->length);
@@ -457,7 +498,23 @@ static void CAReceivedPacketCallback(const CAEndpoint_t *endpoint, void *data, u
         cadata->remoteEndpoint = CACloneEndpoint(endpoint);
         cadata->requestInfo = ReqInfo;
         cadata->responseInfo = NULL;
+#ifdef WITH_BWT
+    if (CA_ADAPTER_GATT_BTLE != endpoint->adapter)
+    {
+        CAResult_t res = CAReceiveBlockWiseData(pdu, endpoint, cadata, dataLen);
+        if (CA_NOT_SUPPORTED == res)
+        {
+            OIC_LOG(ERROR, TAG, "this message does not have block option");
+            CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+        }
+        else
+        {
+            CADataDestroyer(cadata, sizeof(CAData_t));
+        }
+    }
+#else
         CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+#endif
     }
     else
     {
@@ -536,7 +593,23 @@ static void CAReceivedPacketCallback(const CAEndpoint_t *endpoint, void *data, u
         OICFree(retransmissionPdu);
         cadata->responseInfo = ResInfo;
 
+#ifdef WITH_BWT
+        if (CA_ADAPTER_GATT_BTLE != endpoint->adapter)
+        {
+            CAResult_t res = CAReceiveBlockWiseData(pdu, endpoint, cadata, dataLen);
+            if (CA_NOT_SUPPORTED == res)
+            {
+                OIC_LOG(ERROR, TAG, "this message does not have block option");
+                CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+            }
+            else
+            {
+                CADataDestroyer(cadata, sizeof(CAData_t));
+            }
+        }
+#else
         CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+#endif
     }
 
     if (pdu)
@@ -653,7 +726,26 @@ CAResult_t CADetachRequestMessage(const CAEndpoint_t *object, const CARequestInf
     }
 
     // add thread
+#ifdef WITH_BWT
+    if (CA_ADAPTER_GATT_BTLE != object->adapter)
+    {
+        // send block data
+        CAResult_t res = CASendBlockWiseData(data);
+        if(CA_NOT_SUPPORTED == res)
+        {
+            OIC_LOG(DEBUG, TAG, "normal msg will be sent");
+            CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+            return CA_STATUS_OK;
+        }
+        else
+        {
+            CADataDestroyer(data, sizeof(CAData_t));
+        }
+        return res;
+    }
+#else
     CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+#endif
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 
@@ -716,7 +808,27 @@ CAResult_t CADetachResponseMessage(const CAEndpoint_t *object,
     }
 
     // add thread
+#ifdef WITH_BWT
+    if (CA_ADAPTER_GATT_BTLE != object->adapter)
+    {
+        // send block data
+        CAResult_t res = CASendBlockWiseData(data);
+        if(CA_NOT_SUPPORTED == res)
+        {
+            OIC_LOG(DEBUG, TAG, "normal msg will be sent");
+            CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+            return CA_STATUS_OK;
+        }
+        else
+        {
+            CADataDestroyer(data, sizeof(CAData_t));
+        }
+        return res;
+    }
+    else
+#else
     CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+#endif
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
@@ -807,6 +919,11 @@ CAResult_t CAInitializeMessageHandler()
     CARetransmissionInitialize(&g_retransmissionContext, g_threadPoolHandle, CASendUnicastData,
                                CATimeoutCallback, NULL);
 
+#ifdef WITH_BWT
+    // block-wise transfer initialize
+    CAInitializeBlockWiseTransfer(CAAddDataToSendThread, CAAddDataToReceiveThread);
+#endif
+
     // start retransmission
     res = CARetransmissionStart(&g_retransmissionContext);
 
@@ -872,6 +989,9 @@ void CATerminateMessageHandler()
         g_threadPoolHandle = NULL;
     }
 
+#ifdef WITH_BWT
+    CATerminateBlockWiseTransfer();
+#endif
     CARetransmissionDestroy(&g_retransmissionContext);
     CAQueueingThreadDestroy(&g_sendThread);
     CAQueueingThreadDestroy(&g_receiveThread);
index b6e3b05..16024c7 100644 (file)
@@ -538,7 +538,9 @@ uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
 
     while ((option = coap_option_next(&opt_iter)))
     {
-        if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type)
+        if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type
+            && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type
+            && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type)
         {
             count++;
         }
@@ -678,6 +680,11 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *
                     }
                 }
             }
+            else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type
+                    || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type)
+            {
+                OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type);
+            }
             else
             {
                 if (idx < count)
index 709a4b0..6a88b0d 100644 (file)
@@ -69,7 +69,7 @@ typedef struct
     // resource query send by client
     char query[MAX_QUERY_LENGTH];
     // reqJSON is retrieved from the payload of the received request PDU
-    uint8_t payload[MAX_REQUEST_LENGTH];
+    uint8_t *payload;
     // qos is indicating if the request is CON or NON
     OCQualityOfService qos;
     // An array of the received vendor specific header options
index 91776c4..fc6aaea 100644 (file)
@@ -299,7 +299,7 @@ bool OCRepPayloadGetPropDouble(const OCRepPayload* payload, const char* name, do
 
 bool OCRepPayloadSetPropString(OCRepPayload* payload, const char* name, const char* value);
 bool OCRepPayloadSetPropStringAsOwner(OCRepPayload* payload, const char* name, char* value);
-bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, const char** value);
+bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, char** value);
 
 bool OCRepPayloadSetPropBool(OCRepPayload* payload, const char* name, bool value);
 bool OCRepPayloadGetPropBool(const OCRepPayload* payload, const char* name, bool* value);
@@ -349,7 +349,7 @@ void OCRepPayloadDestroy(OCRepPayload* payload);
 // Discovery Payload
 OCDiscoveryPayload* OCDiscoveryPayloadCreate();
 
-OCSecurityPayload* OCSecurityPayloadCreate(char* securityData);
+OCSecurityPayload* OCSecurityPayloadCreate(const char* securityData);
 void OCSecurityPayloadDestroy(OCSecurityPayload* payload);
 
 void OCDiscoveryPayloadAddResource(OCDiscoveryPayload* payload, const OCResource* res,
index afb8700..3c7bcc5 100644 (file)
@@ -30,6 +30,7 @@
 
 #define TAG "OCPayload"
 static void OCFreeRepPayloadValueContents(OCRepPayloadValue* val);
+static void FreeOCDiscoveryResource(OCResourcePayload* payload);
 
 void OCPayloadDestroy(OCPayload* payload)
 {
@@ -292,7 +293,17 @@ static OCRepPayloadValue* OCRepPayloadFindAndSetValue(OCRepPayload* payload, con
     if(val == NULL)
     {
         payload->values = (OCRepPayloadValue*)OICCalloc(1, sizeof(OCRepPayloadValue));
+        if(!payload->values)
+        {
+            return NULL;
+        }
         payload->values->name = OICStrdup(name);
+        if(!payload->values->name)
+        {
+            OICFree(payload->values);
+            payload->values = NULL;
+            return NULL;
+        }
         payload->values->type =type;
         return payload->values;
     }
@@ -308,7 +319,17 @@ static OCRepPayloadValue* OCRepPayloadFindAndSetValue(OCRepPayload* payload, con
         else if(val->next == NULL)
         {
             val->next = (OCRepPayloadValue*)OICCalloc(1, sizeof(OCRepPayloadValue));
+            if(!val->next)
+            {
+                return NULL;
+            }
             val->next->name = OICStrdup(name);
+            if(!val->next->name)
+            {
+                OICFree(val->next);
+                val->next = NULL;
+                return NULL;
+            }
             val->next->type =type;
             return val->next;
         }
@@ -424,26 +445,52 @@ bool OCRepPayloadIsNull(const OCRepPayload* payload, const char* name)
     return val->type == OCREP_PROP_NULL;
 }
 
-bool OCRepPayloadSetNull(OCRepPayload* payload, const char* name)
+static bool OCRepPayloadSetProp(OCRepPayload* payload, const char* name,
+        void* value, OCRepPayloadPropType type)
 {
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_NULL);
-    return val != NULL;
-}
-
-bool OCRepPayloadSetPropInt(OCRepPayload* payload,
-        const char* name, int64_t value)
-{
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_INT);
-
+    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, type);
     if(!val)
     {
         return false;
     }
+    switch(type)
+    {
+        case OCREP_PROP_INT:
+               val->i = *(int64_t*)value;
+               break;
+        case OCREP_PROP_DOUBLE:
+               val->d = *(double*)value;
+               break;
+        case OCREP_PROP_BOOL:
+               val->b = *(bool*)value;
+               break;
+        case OCREP_PROP_OBJECT:
+               val->obj = (OCRepPayload*)value;
+               break;
+        case OCREP_PROP_STRING:
+               val->str = (char*)value;
+               return val->str != NULL;
+        case OCREP_PROP_NULL:
+               return val != NULL;
+        case OCREP_PROP_ARRAY:
+        default:
+               return false;
+    }
 
-    val->i = value;
     return true;
 }
 
+bool OCRepPayloadSetNull(OCRepPayload* payload, const char* name)
+{
+    return OCRepPayloadSetProp(payload, name, NULL, OCREP_PROP_NULL);
+}
+
+bool OCRepPayloadSetPropInt(OCRepPayload* payload,
+        const char* name, int64_t value)
+{
+    return OCRepPayloadSetProp(payload, name, &value, OCREP_PROP_INT);
+}
+
 bool OCRepPayloadGetPropInt(const OCRepPayload* payload, const char* name, int64_t* value)
 {
     OCRepPayloadValue* val = OCRepPayloadFindValue(payload, name);
@@ -460,15 +507,7 @@ bool OCRepPayloadGetPropInt(const OCRepPayload* payload, const char* name, int64
 bool OCRepPayloadSetPropDouble(OCRepPayload* payload,
         const char* name, double value)
 {
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_DOUBLE);
-
-    if(!val )
-    {
-        return false;
-    }
-
-    val->d = value;
-    return true;
+    return OCRepPayloadSetProp(payload, name, &value, OCREP_PROP_DOUBLE);
 }
 
 bool OCRepPayloadGetPropDouble(const OCRepPayload* payload, const char* name, double* value)
@@ -498,18 +537,10 @@ bool OCRepPayloadSetPropString(OCRepPayload* payload, const char* name, const ch
 
 bool OCRepPayloadSetPropStringAsOwner(OCRepPayload* payload, const char* name, char* value)
 {
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_STRING);
-
-    if(!val)
-    {
-        return false;
-    }
-
-    val->str = value;
-    return val->str != NULL;
+    return OCRepPayloadSetProp(payload, name, value, OCREP_PROP_STRING);
 }
 
-bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, const char** value)
+bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, char** value)
 {
     OCRepPayloadValue* val = OCRepPayloadFindValue(payload, name);
 
@@ -525,15 +556,7 @@ bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, co
 bool OCRepPayloadSetPropBool(OCRepPayload* payload,
         const char* name, bool value)
 {
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_BOOL);
-
-    if(!val)
-    {
-        return false;
-    }
-
-    val->b = value;
-    return true;
+    return OCRepPayloadSetProp(payload, name, &value, OCREP_PROP_BOOL);
 }
 
 bool OCRepPayloadGetPropBool(const OCRepPayload* payload, const char* name, bool* value)
@@ -563,15 +586,7 @@ bool OCRepPayloadSetPropObject(OCRepPayload* payload, const char* name, const OC
 
 bool OCRepPayloadSetPropObjectAsOwner(OCRepPayload* payload, const char* name, OCRepPayload* value)
 {
-    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_OBJECT);
-
-    if(!val)
-    {
-        return false;
-    }
-
-    val->obj = value;
-    return true;
+    return OCRepPayloadSetProp(payload, name, value, OCREP_PROP_OBJECT);
 }
 
 bool OCRepPayloadGetPropObject(const OCRepPayload* payload, const char* name, OCRepPayload** value)
@@ -1079,7 +1094,7 @@ OCDiscoveryPayload* OCDiscoveryPayloadCreate()
     return payload;
 }
 
-OCSecurityPayload* OCSecurityPayloadCreate(char* securityData)
+OCSecurityPayload* OCSecurityPayloadCreate(const char* securityData)
 {
     OCSecurityPayload* payload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
 
@@ -1143,6 +1158,11 @@ static OCResourcePayload* OCCopyResource(const OCResource* res, uint16_t port)
 
     pl->uri = OICStrdup(res->uri);
     pl->sid = (uint8_t*)OICCalloc(1, UUID_SIZE);
+    if(!pl->uri || ! pl->sid)
+    {
+        FreeOCDiscoveryResource(pl);
+        return NULL;
+    }
     memcpy(pl->sid, OCGetServerInstanceID(), UUID_SIZE);
 
     // types
@@ -1151,14 +1171,34 @@ static OCResourcePayload* OCCopyResource(const OCResource* res, uint16_t port)
     if(typePtr != NULL)
     {
         pl->types = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+        if(!pl->types)
+        {
+            FreeOCDiscoveryResource(pl);
+            return NULL;
+        }
         pl->types->value = OICStrdup(typePtr->resourcetypename);
+        if(!pl->types->value)
+        {
+            FreeOCDiscoveryResource(pl);
+            return NULL;
+        }
 
         OCStringLL* cur = pl->types;
         typePtr = typePtr->next;
         while(typePtr)
         {
             cur->next = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+            if(!cur->next)
+            {
+                FreeOCDiscoveryResource(pl);
+                return NULL;
+            }
             cur->next->value = OICStrdup(typePtr->resourcetypename);
+            if(!cur->next->value)
+            {
+                FreeOCDiscoveryResource(pl);
+                return NULL;
+            }
             cur = cur->next;
             typePtr = typePtr->next;
         }
@@ -1169,14 +1209,34 @@ static OCResourcePayload* OCCopyResource(const OCResource* res, uint16_t port)
     if(ifPtr != NULL)
     {
         pl->interfaces = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+        if(!pl->interfaces)
+        {
+            FreeOCDiscoveryResource(pl);
+            return NULL;
+        }
         pl->interfaces->value = OICStrdup(ifPtr->name);
+        if(!pl->interfaces->value)
+        {
+            FreeOCDiscoveryResource(pl);
+            return NULL;
+        }
 
         OCStringLL* cur = pl->interfaces;
         ifPtr = ifPtr->next;
         while(ifPtr)
         {
             cur->next = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+            if(!cur->next)
+            {
+                FreeOCDiscoveryResource(pl);
+                return NULL;
+            }
             cur->next->value = OICStrdup(ifPtr->name);
+            if(!cur->next->value)
+            {
+                FreeOCDiscoveryResource(pl);
+                return NULL;
+            }
             cur = cur->next;
             ifPtr = ifPtr->next;
         }
@@ -1212,7 +1272,7 @@ void OCDiscoveryPayloadAddNewResource(OCDiscoveryPayload* payload, OCResourcePay
     }
 }
 
-void FreeOCDiscoveryResource(OCResourcePayload* payload)
+static void FreeOCDiscoveryResource(OCResourcePayload* payload)
 {
     if(!payload)
     {
index 3b6bd02..02a5b0f 100644 (file)
@@ -19,6 +19,7 @@
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
 #include "ocpayloadcbor.h"
+#include "platform_features.h"
 #include <stdlib.h>
 #include "oic_malloc.h"
 #include "logger.h"
 #include "cbor.h"
 
 #define TAG PCF("OCPayloadConvert")
+// Arbitrarily chosen size that seems to contain the majority of packages
+#define INIT_SIZE (255)
 
-static OCStackResult OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t** outPayload,
+// Functions all return either a CborError, or a negative version of the OC_STACK return values
+static int64_t OCConvertPayloadHelper(OCPayload* payload, uint8_t* outPayload, size_t* size);
+static int64_t OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t* outPayload,
         size_t* size);
-static OCStackResult OCConvertDevicePayload(OCDevicePayload* payload, uint8_t** outPayload,
+static int64_t OCConvertDevicePayload(OCDevicePayload* payload, uint8_t* outPayload,
         size_t* size);
-static OCStackResult OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t** outPayload,
+static int64_t OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t* outPayload,
         size_t* size);
-static OCStackResult OCConvertRepPayload(OCRepPayload* payload, uint8_t** outPayload, size_t* size);
-static OCStackResult OCConvertPresencePayload(OCPresencePayload* payload, uint8_t** outPayload,
+static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, size_t* size);
+static int64_t OCConvertPresencePayload(OCPresencePayload* payload, uint8_t* outPayload,
         size_t* size);
-static OCStackResult OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t** outPayload,
+static int64_t OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t* outPayload,
         size_t* size);
+static int64_t OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload);
+static int64_t OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray);
 
-bool AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
+static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
         const char* value);
 
-bool ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
+static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
         const char* value);
 
+#define STRINGIFY(s) XSTRINGIFY(s)
+#define XSTRINGIFY(s) #s
 
 OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t* size)
 {
+    // TinyCbor Version 47a78569c0 or better on master is required for the re-allocation
+    // strategy to work.  If you receive the following assertion error, please do a git-pull
+    // from the extlibs/tinycbor/tinycbor directory
+    #define CborNeedsUpdating  (CborErrorOutOfMemory < CborErrorDataTooLarge)
+    OC_STATIC_ASSERT(!CborNeedsUpdating, "tinycbor needs to be updated to at least 47a78569c0");
+    #undef CborNeedsUpdating
+    if (!payload)
+    {
+        OC_LOG(ERROR, TAG, PCF("Payload parameter NULL"));
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    if (!outPayload || !size)
+    {
+        OC_LOG(ERROR, TAG, PCF("Out parameter/s parameter NULL"));
+        return OC_STACK_INVALID_PARAM;
+    }
+
     OC_LOG_V(INFO, TAG, "Converting payload of type %d", payload->type);
+
+    size_t curSize = INIT_SIZE;
+    uint8_t* out = (uint8_t*)OICCalloc(1, curSize);
+    int64_t err = OCConvertPayloadHelper(payload, out, &curSize);
+
+    if (err == CborErrorOutOfMemory)
+    {
+        // reallocate "out" and try again!
+        uint8_t* out2 = (uint8_t*)OICRealloc(out, curSize);
+
+        if (!out2)
+        {
+            OICFree(out);
+            return OC_STACK_NO_MEMORY;
+        }
+
+        out = out2;
+        err = OCConvertPayloadHelper(payload, out, &curSize);
+    }
+
+    if (err == 0)
+    {
+        if (curSize < INIT_SIZE)
+        {
+            uint8_t* out2 = (uint8_t*)OICRealloc(out, curSize);
+
+            if (!out2)
+            {
+                OICFree(out);
+                return OC_STACK_NO_MEMORY;
+            }
+
+            out = out2;
+        }
+
+        *size = curSize;
+        *outPayload = out;
+        return OC_STACK_OK;
+    }
+    else if (err < 0)
+    {
+        return (OCStackResult)-err;
+    }
+    else
+    {
+        return OC_STACK_ERROR;
+    }
+}
+
+static int64_t OCConvertPayloadHelper(OCPayload* payload, uint8_t* outPayload, size_t* size)
+{
     switch(payload->type)
     {
         case PAYLOAD_TYPE_DISCOVERY:
@@ -71,410 +149,330 @@ OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t*
     }
 }
 
-static OCStackResult OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t** outPayload,
-        size_t* size)
+static int64_t checkError(int64_t err, CborEncoder* encoder, uint8_t* outPayload, size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
+    if (err == CborErrorOutOfMemory)
     {
-        return OC_STACK_NO_MEMORY;
+        *size += encoder->ptr - encoder->end;
+        return err;
     }
-
+    else if (err != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "Convert Payload failed", err);
+        return err;
+    }
+    else
+    {
+        *size = encoder->ptr - outPayload;
+        return 0;
+    }
+}
+static int64_t OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t* outPayload,
+        size_t* size)
+{
     CborEncoder encoder;
-    bool err = false;
+    int64_t err = 0;
 
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
 
     CborEncoder rootArray;
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, 2);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_SECURITY);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, 2);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_SECURITY);
 
     CborEncoder map;
 
-    err = err || cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
+    err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
 
     if(payload->securityData)
     {
-        err = err || AddTextStringToMap(&map, OC_RSRVD_REPRESENTATION,
+        err = err | AddTextStringToMap(&map, OC_RSRVD_REPRESENTATION,
                 sizeof(OC_RSRVD_REPRESENTATION) - 1,
                 payload->securityData);
     }
 
-    err = err || cbor_encoder_close_container(&rootArray, &map);
-
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Security Payload failed", err);
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
+    err = err | cbor_encoder_close_container(&rootArray, &map);
 
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
+    return checkError(err, &encoder, outPayload, size);
 
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
-
-    *outPayload = tempPayload;
-    return OC_STACK_OK;
 }
 
-static OCStackResult OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t** outPayload,
+static int64_t OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t* outPayload,
         size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
-
-    CborEncoder encoder = {};
-    bool err = false;
+    CborEncoder encoder = {0};
+    int64_t err = 0;
     size_t resourceCount =  OCDiscoveryPayloadGetResourceCount(payload);
 
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
 
     CborEncoder rootArray;
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, 1 + resourceCount);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_DISCOVERY);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, 1 + resourceCount);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_DISCOVERY);
 
     for(size_t i = 0; i < resourceCount; ++i)
     {
         CborEncoder map;
         OCResourcePayload* resource = OCDiscoveryPayloadGetResource(payload, i);
-        err = err || cbor_encoder_create_map(&rootArray, &map, 3);
+
+        if(!resource)
+        {
+            return OC_STACK_INVALID_PARAM;
+        }
+
+        err = err | cbor_encoder_create_map(&rootArray, &map, 3);
         // Uri
-        err = err || AddTextStringToMap(&map, OC_RSRVD_HREF,
+        err = err | AddTextStringToMap(&map, OC_RSRVD_HREF,
                 sizeof(OC_RSRVD_HREF) - 1,
                 resource->uri);
 
         // Server ID
-        err = err || cbor_encode_text_string(&map, OC_RSRVD_SERVER_INSTANCE_ID,
+        err = err | cbor_encode_text_string(&map, OC_RSRVD_SERVER_INSTANCE_ID,
                 sizeof(OC_RSRVD_SERVER_INSTANCE_ID) - 1);
-        err = err || cbor_encode_byte_string(&map, resource->sid, UUID_SIZE);
+        err = err | cbor_encode_byte_string(&map, resource->sid, UUID_SIZE);
         // Prop Tag
         {
             CborEncoder propMap;
-            err = err || cbor_encode_text_string(&map, OC_RSRVD_PROPERTY,
+            err = err | cbor_encode_text_string(&map, OC_RSRVD_PROPERTY,
                     sizeof(OC_RSRVD_PROPERTY) -1 );
-            err = err || cbor_encoder_create_map(&map, &propMap, 3);
+            err = err | cbor_encoder_create_map(&map, &propMap, 3);
 
             // Resource Type
             {
                 CborEncoder rtArray;
-                err = err || cbor_encode_text_string(&propMap, OC_RSRVD_RESOURCE_TYPE,
+                err = err | cbor_encode_text_string(&propMap, OC_RSRVD_RESOURCE_TYPE,
                     sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
-                err = err || cbor_encoder_create_array(&propMap, &rtArray, CborIndefiniteLength);
+                err = err | cbor_encoder_create_array(&propMap, &rtArray, CborIndefiniteLength);
 
                 OCStringLL* rtPtr = resource->types;
                 while(rtPtr)
                 {
-                    err = err || cbor_encode_text_string(&rtArray, rtPtr->value,
+                    err = err | cbor_encode_text_string(&rtArray, rtPtr->value,
                             strlen(rtPtr->value));
                     rtPtr = rtPtr->next;
                 }
 
-                err = err || cbor_encoder_close_container(&propMap, &rtArray);
+                err = err | cbor_encoder_close_container(&propMap, &rtArray);
             }
 
             // Interface Types
             {
                 CborEncoder ifArray;
-                err = err || cbor_encode_text_string(&propMap, OC_RSRVD_INTERFACE,
+                err = err | cbor_encode_text_string(&propMap, OC_RSRVD_INTERFACE,
                         sizeof(OC_RSRVD_INTERFACE) - 1);
-                err = err || cbor_encoder_create_array(&propMap, &ifArray, CborIndefiniteLength);
+                err = err | cbor_encoder_create_array(&propMap, &ifArray, CborIndefiniteLength);
                 OCStringLL* ifPtr = resource->interfaces;
 
                 while(ifPtr)
                 {
-                    err = err || cbor_encode_text_string(&ifArray, ifPtr->value,
+                    err = err | cbor_encode_text_string(&ifArray, ifPtr->value,
                         strlen(ifPtr->value));
                     ifPtr= ifPtr->next;
                 }
 
-                err = err || cbor_encoder_close_container(&propMap, &ifArray);
+                err = err | cbor_encoder_close_container(&propMap, &ifArray);
             }
             // Policy
             {
                 CborEncoder policyMap;
-                err = err || cbor_encode_text_string(&propMap, OC_RSRVD_POLICY,
+                err = err | cbor_encode_text_string(&propMap, OC_RSRVD_POLICY,
                         sizeof(OC_RSRVD_POLICY) - 1);
-                err = err || cbor_encoder_create_map(&propMap, &policyMap, CborIndefiniteLength);
+                err = err | cbor_encoder_create_map(&propMap, &policyMap, CborIndefiniteLength);
 
                 // Bitmap
-                err = err || cbor_encode_text_string(&policyMap, OC_RSRVD_BITMAP,
+                err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_BITMAP,
                         sizeof(OC_RSRVD_BITMAP) - 1);
-                err = err || cbor_encode_uint(&policyMap, resource->bitmap);
+                err = err | cbor_encode_uint(&policyMap, resource->bitmap);
 
                 if(resource->secure)
                 {
-                    err = err || cbor_encode_text_string(&policyMap, OC_RSRVD_SECURE,
+                    err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_SECURE,
                             sizeof(OC_RSRVD_SECURE) - 1);
-                    err = err || cbor_encode_boolean(&policyMap, OC_RESOURCE_SECURE);
+                    err = err | cbor_encode_boolean(&policyMap, OC_RESOURCE_SECURE);
 
                     if(resource->port != 0)
                     {
-                        err = err || cbor_encode_text_string(&policyMap, OC_RSRVD_HOSTING_PORT,
+                        err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_HOSTING_PORT,
                                 sizeof(OC_RSRVD_HOSTING_PORT) - 1);
-                        err = err || cbor_encode_uint(&policyMap, resource->port);
+                        err = err | cbor_encode_uint(&policyMap, resource->port);
                     }
                 }
 
-                err = err || cbor_encoder_close_container(&propMap, &policyMap);
+                err = err | cbor_encoder_close_container(&propMap, &policyMap);
             }
             // Close
-            err = err || cbor_encoder_close_container(&map, &propMap);
+            err = err | cbor_encoder_close_container(&map, &propMap);
         }
         // Close Item
-        err = err || cbor_encoder_close_container(&rootArray, &map);
+        err = err | cbor_encoder_close_container(&rootArray, &map);
     }
     // Close main array
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Discovery Payload failed with : %d", err);
-        return OC_STACK_ERROR;
-    }
-
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
-
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
 
-    *outPayload = tempPayload;
-    return OC_STACK_OK;
+    return checkError(err, &encoder, outPayload, size);
 }
 
-static OCStackResult OCConvertDevicePayload(OCDevicePayload* payload, uint8_t** outPayload,
+static int64_t OCConvertDevicePayload(OCDevicePayload* payload, uint8_t* outPayload,
         size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
-
-    CborEncoder encoder = {};
-    bool err = false;
+    CborEncoder encoder = {0};
+    int64_t err = 0;
 
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
     CborEncoder rootArray;
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, 2);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_DEVICE);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, 2);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_DEVICE);
 
     {
         CborEncoder map;
-        err = err || cbor_encoder_create_map(&rootArray, &map, 2);
+        err = err | cbor_encoder_create_map(&rootArray, &map, 2);
 
         // uri
-        err = err || AddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
+        err = err | AddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
                 payload->uri);
 
         // Rep Map
         {
             CborEncoder repMap;
-            err = err || cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
+            err = err | cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
                     sizeof(OC_RSRVD_REPRESENTATION) - 1);
-            err = err || cbor_encoder_create_map(&map, &repMap, 4);
+            err = err | cbor_encoder_create_map(&map, &repMap, 4);
 
             // Device ID
-            err = err || cbor_encode_text_string(&repMap, OC_RSRVD_DEVICE_ID,
+            err = err | cbor_encode_text_string(&repMap, OC_RSRVD_DEVICE_ID,
                     sizeof(OC_RSRVD_DEVICE_ID) - 1);
-            err = err || cbor_encode_byte_string(&repMap, payload->sid, UUID_SIZE);
+            err = err | cbor_encode_byte_string(&repMap, payload->sid, UUID_SIZE);
 
             // Device Name
-            err = err || AddTextStringToMap(&repMap, OC_RSRVD_DEVICE_NAME,
+            err = err | AddTextStringToMap(&repMap, OC_RSRVD_DEVICE_NAME,
                     sizeof(OC_RSRVD_DEVICE_NAME) - 1,
                     payload->deviceName);
 
             // Device Spec Version
-            err = err || AddTextStringToMap(&repMap, OC_RSRVD_SPEC_VERSION,
+            err = err | AddTextStringToMap(&repMap, OC_RSRVD_SPEC_VERSION,
                     sizeof(OC_RSRVD_SPEC_VERSION) - 1,
                     payload->specVersion);
 
             // Device data Model Version
-            err = err || AddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
+            err = err | AddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
                     sizeof(OC_RSRVD_DATA_MODEL_VERSION) - 1,
                     payload->dataModelVersion);
 
-            err = err || cbor_encoder_close_container(&map, &repMap);
+            err = err | cbor_encoder_close_container(&map, &repMap);
         }
 
         // Close Map
-        err = err || cbor_encoder_close_container(&rootArray, &map);
+        err = err | cbor_encoder_close_container(&rootArray, &map);
     }
 
     // Close main array
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Device Payload failed with : %d", err);
-        return OC_STACK_ERROR;
-    }
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
 
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
-
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
-
-    *outPayload = tempPayload;
-    return OC_STACK_OK;
+    return checkError(err, &encoder, outPayload, size);
 }
 
-static OCStackResult OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t** outPayload,
+static int64_t OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t* outPayload,
         size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
+    CborEncoder encoder = {0};
+    int64_t err = 0;
 
-    CborEncoder encoder = {};
-    bool err = false;
-
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
     CborEncoder rootArray;
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, 2);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_PLATFORM);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, 2);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_PLATFORM);
     {
         CborEncoder map;
-        err = err || cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
+        err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
 
         // uri
-        err = err || AddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
+        err = err | AddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
                 payload->uri);
 
         // Rep Map
         {
             CborEncoder repMap;
-            err = err || cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
+            err = err | cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
                     sizeof(OC_RSRVD_REPRESENTATION) - 1);
-            err = err || cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
+            err = err | cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
 
             // Platform ID
-            err = err || AddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_ID,
+            err = err | AddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_ID,
                     sizeof(OC_RSRVD_PLATFORM_ID) - 1,
                     payload->info.platformID);
 
             // MFG Name
-            err = err || AddTextStringToMap(&repMap, OC_RSRVD_MFG_NAME,
+            err = err | AddTextStringToMap(&repMap, OC_RSRVD_MFG_NAME,
                     sizeof(OC_RSRVD_MFG_NAME) - 1,
                     payload->info.manufacturerName);
 
             // MFG Url
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_URL,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_URL,
                     sizeof(OC_RSRVD_MFG_URL) - 1,
                     payload->info.manufacturerUrl);
 
             // Model Num
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MODEL_NUM,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MODEL_NUM,
                     sizeof(OC_RSRVD_MODEL_NUM) - 1,
                     payload->info.modelNumber);
 
             // Date of Mfg
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_DATE,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_DATE,
                     sizeof(OC_RSRVD_MFG_DATE) - 1,
                     payload->info.dateOfManufacture);
 
             // Platform Version
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_VERSION,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_VERSION,
                     sizeof(OC_RSRVD_PLATFORM_VERSION) - 1,
                     payload->info.platformVersion);
 
             // OS Version
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_OS_VERSION,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_OS_VERSION,
                     sizeof(OC_RSRVD_OS_VERSION) - 1,
                     payload->info.operatingSystemVersion);
 
             // Hardware Version
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_HARDWARE_VERSION,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_HARDWARE_VERSION,
                     sizeof(OC_RSRVD_HARDWARE_VERSION) - 1,
                     payload->info.hardwareVersion);
 
             // Firmware Version
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_FIRMWARE_VERSION,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_FIRMWARE_VERSION,
                     sizeof(OC_RSRVD_FIRMWARE_VERSION) - 1,
                     payload->info.firmwareVersion);
 
             // Support URL
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SUPPORT_URL,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SUPPORT_URL,
                     sizeof(OC_RSRVD_SUPPORT_URL) - 1,
                     payload->info.supportUrl);
 
             // System Time
-            err = err || ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SYSTEM_TIME,
+            err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SYSTEM_TIME,
                     sizeof(OC_RSRVD_SYSTEM_TIME) - 1,
                     payload->info.systemTime);
-            err = err || cbor_encoder_close_container(&map, &repMap);
+            err = err | cbor_encoder_close_container(&map, &repMap);
         }
 
         // Close Map
-        err = err || cbor_encoder_close_container(&rootArray, &map);
+        err = err | cbor_encoder_close_container(&rootArray, &map);
     }
 
     // Close main array
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Platform Payload failed with : %d", err);
-        return OC_STACK_ERROR;
-    }
-
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
-
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
-
-    *outPayload = tempPayload;
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
 
-    return OC_STACK_OK;
+    return checkError(err, &encoder, outPayload, size);
 }
 
-static bool OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload);
-
-static bool OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray)
+static int64_t OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray)
 {
     CborEncoder array;
-    bool err = false;
+    int64_t err = 0;
 
-    err = err || cbor_encoder_create_array(parent, &array, CborIndefiniteLength);
-    err = err || cbor_encode_uint(&array, valArray->type);
+    err = err | cbor_encoder_create_array(parent, &array, CborIndefiniteLength);
+    err = err | cbor_encode_uint(&array, valArray->type);
     for(int i = 0; i < MAX_REP_ARRAY_DEPTH; ++i)
     {
-        err = err || cbor_encode_uint(&array, valArray->dimensions[i]);
+        err = err | cbor_encode_uint(&array, valArray->dimensions[i]);
     }
 
     size_t dimTotal = calcDimTotal(valArray->dimensions);
@@ -488,16 +486,16 @@ static bool OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* va
                 err = CborUnknownError;
                 break;
             case OCREP_PROP_INT:
-                err = err || cbor_encode_int(&array, valArray->iArray[i]);
+                err = err | cbor_encode_int(&array, valArray->iArray[i]);
                 break;
             case OCREP_PROP_DOUBLE:
-                err = err || cbor_encode_double(&array, valArray->dArray[i]);
+                err = err | cbor_encode_double(&array, valArray->dArray[i]);
                 break;
             case OCREP_PROP_BOOL:
-                err = err || cbor_encode_boolean(&array, valArray->bArray[i]);
+                err = err | cbor_encode_boolean(&array, valArray->bArray[i]);
                 break;
             case OCREP_PROP_STRING:
-                err = err || cbor_encode_text_string(&array, valArray->strArray[i],
+                err = err | cbor_encode_text_string(&array, valArray->strArray[i],
                         strlen(valArray->strArray[i]));
                 break;
             case OCREP_PROP_OBJECT:
@@ -510,18 +508,18 @@ static bool OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* va
         }
     }
 
-    err = err || cbor_encoder_close_container(parent, &array);
+    err = err | cbor_encoder_close_container(parent, &array);
     return err;
 }
 
-static bool OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload)
+static int64_t OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload)
 {
-    bool err = false;
+    int64_t err = 0;
     CborEncoder map;
-    err = err || cbor_encoder_create_map(parent, &map, CborIndefiniteLength);
+    err = err | cbor_encoder_create_map(parent, &map, CborIndefiniteLength);
 
     // Uri
-    err = err || ConditionalAddTextStringToMap(&map, OC_RSRVD_HREF,
+    err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_HREF,
             sizeof(OC_RSRVD_HREF) - 1,
             payload->uri);
 
@@ -530,83 +528,83 @@ static bool OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* p
     if(payload->types || payload->interfaces)
     {
         OC_LOG_V(INFO, TAG, "Payload has types or interfaces");
-        err = err || cbor_encode_text_string(&map,
+        err = err | cbor_encode_text_string(&map,
                 OC_RSRVD_PROPERTY,
                 sizeof(OC_RSRVD_PROPERTY) - 1);
         CborEncoder propMap;
-        err = err || cbor_encoder_create_map(&map, &propMap, 2);
+        err = err | cbor_encoder_create_map(&map, &propMap, 2);
 
         CborEncoder curArray;
         if(payload->types)
         {
-            err = err || cbor_encode_text_string(&propMap,
+            err = err | cbor_encode_text_string(&propMap,
                     OC_RSRVD_RESOURCE_TYPE,
                     sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
-            err = err || cbor_encoder_create_array(&propMap, &curArray, CborIndefiniteLength);
+            err = err | cbor_encoder_create_array(&propMap, &curArray, CborIndefiniteLength);
             OCStringLL* val = payload->types;
             while(val)
             {
-                err = err || cbor_encode_text_string(&curArray, val->value, strlen(val->value));
+                err = err | cbor_encode_text_string(&curArray, val->value, strlen(val->value));
                 val = val->next;
             }
-            err = err || cbor_encoder_close_container(&propMap, &curArray);
+            err = err | cbor_encoder_close_container(&propMap, &curArray);
         }
         if(payload->interfaces)
         {
-            err = err || cbor_encode_text_string(&propMap,
+            err = err | cbor_encode_text_string(&propMap,
                     OC_RSRVD_INTERFACE,
                     sizeof(OC_RSRVD_INTERFACE) - 1);
-            err = err || cbor_encoder_create_array(&propMap, &curArray, CborIndefiniteLength);
+            err = err | cbor_encoder_create_array(&propMap, &curArray, CborIndefiniteLength);
             OCStringLL* val = payload->interfaces;
             while(val)
             {
-                err = err || cbor_encode_text_string(&curArray, val->value, strlen(val->value));
+                err = err | cbor_encode_text_string(&curArray, val->value, strlen(val->value));
                 val = val->next;
             }
-            err = err || cbor_encoder_close_container(&propMap, &curArray);
+            err = err | cbor_encoder_close_container(&propMap, &curArray);
         }
-        err = err || cbor_encoder_close_container(&map, &propMap);
+        err = err | cbor_encoder_close_container(&map, &propMap);
     }
 
     // Rep Map
     {
         CborEncoder repMap;
-        err = err || cbor_encode_text_string(&map,
+        err = err | cbor_encode_text_string(&map,
                 OC_RSRVD_REPRESENTATION,
                 sizeof(OC_RSRVD_REPRESENTATION) - 1);
-        err = err || cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
+        err = err | cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
         OCRepPayloadValue* value = payload->values;
         while(value)
         {
-            err = err || cbor_encode_text_string(&repMap,
+            err = err | cbor_encode_text_string(&repMap,
                     value->name,
                     strlen(value->name));
             switch(value->type)
             {
                 case OCREP_PROP_NULL:
-                    err = err || cbor_encode_null(&repMap);
+                    err = err | cbor_encode_null(&repMap);
                     break;
                 case OCREP_PROP_INT:
-                    err = err || cbor_encode_int(&repMap,
+                    err = err | cbor_encode_int(&repMap,
                             value->i);
                     break;
                 case OCREP_PROP_DOUBLE:
-                    err = err || cbor_encode_double(&repMap,
+                    err = err | cbor_encode_double(&repMap,
                             value->d);
                     break;
                 case OCREP_PROP_BOOL:
-                    err = err || cbor_encode_boolean(&repMap,
+                    err = err | cbor_encode_boolean(&repMap,
                             value->b);
                     break;
                 case OCREP_PROP_STRING:
-                    err = err || cbor_encode_text_string(&repMap,
+                    err = err | cbor_encode_text_string(&repMap,
                             value->str, strlen(value->str));
                     break;
                 case OCREP_PROP_OBJECT:
-                    err = err || OCConvertSingleRepPayload(&repMap, value->obj);
+                    err = err | OCConvertSingleRepPayload(&repMap, value->obj);
                     break;
                 case OCREP_PROP_ARRAY:
-                    err = err || OCConvertArray(&repMap, &value->arr);
+                    err = err | OCConvertArray(&repMap, &value->arr);
                     break;
                 default:
                     OC_LOG_V(ERROR, TAG, "Invalid Prop type: %d",
@@ -616,145 +614,93 @@ static bool OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* p
             value = value->next;
         }
 
-        err = err || cbor_encoder_close_container(&map, &repMap);
+        err = err | cbor_encoder_close_container(&map, &repMap);
     }
 
     // Close Map
-    err = err || cbor_encoder_close_container(parent, &map);
+    err = err | cbor_encoder_close_container(parent, &map);
 
     return err;
 }
 
-static OCStackResult OCConvertRepPayload(OCRepPayload* payload, uint8_t** outPayload, size_t* size)
+static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
+    CborEncoder encoder = {0};
+    int64_t err = 0;
 
-    CborEncoder encoder = {};
-    bool err = false;
-
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
     CborEncoder rootArray;
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, CborIndefiniteLength);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_REPRESENTATION);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, CborIndefiniteLength);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_REPRESENTATION);
 
-    while(payload != NULL && !err)
+    while(payload != NULL && (err == 0 || err == CborErrorOutOfMemory))
     {
-        err = err || OCConvertSingleRepPayload(&rootArray, payload);
+        err = err | OCConvertSingleRepPayload(&rootArray, payload);
         payload = payload->next;
     }
 
     // Close main array
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Rep Payload failed with : %d", err);
-        return OC_STACK_ERROR;
-    }
-
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
-
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
 
-    *outPayload = tempPayload;
-
-    return OC_STACK_OK;
+    return checkError(err, &encoder, outPayload, size);
 }
 
-static OCStackResult OCConvertPresencePayload(OCPresencePayload* payload,
-        uint8_t** outPayload, size_t* size)
+static int64_t OCConvertPresencePayload(OCPresencePayload* payload,
+        uint8_t* outPayload, size_t* size)
 {
-    *outPayload = (uint8_t*)OICCalloc(1, MAX_REQUEST_LENGTH);
-    *size = MAX_REQUEST_LENGTH;
-
-    if(!*outPayload)
-    {
-        return OC_STACK_NO_MEMORY;
-    }
+    CborEncoder encoder = {0};
+    int64_t err = 0;
 
-    CborEncoder encoder = {};
-    bool err = false;
-
-    cbor_encoder_init(&encoder, *outPayload, *size, 0);
+    cbor_encoder_init(&encoder, outPayload, *size, 0);
     CborEncoder rootArray;
 
-    err = err || cbor_encoder_create_array(&encoder, &rootArray, 2);
-    err = err || cbor_encode_uint(&rootArray, PAYLOAD_TYPE_PRESENCE);
+    err = err | cbor_encoder_create_array(&encoder, &rootArray, 2);
+    err = err | cbor_encode_uint(&rootArray, PAYLOAD_TYPE_PRESENCE);
 
 
     CborEncoder map;
-    err = err || cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
+    err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
 
     // Sequence Number
-    err = err || cbor_encode_text_string(&map,
+    err = err | cbor_encode_text_string(&map,
             OC_RSRVD_NONCE,
             sizeof(OC_RSRVD_NONCE) - 1);
-    err = err || cbor_encode_uint(&map, payload->sequenceNumber);
+    err = err | cbor_encode_uint(&map, payload->sequenceNumber);
 
     // Max Age
-    err = err || cbor_encode_text_string(&map,
+    err = err | cbor_encode_text_string(&map,
             OC_RSRVD_TTL,
             sizeof(OC_RSRVD_TTL) - 1);
-    err = err || cbor_encode_uint(&map, payload->maxAge);
+    err = err | cbor_encode_uint(&map, payload->maxAge);
 
     // Trigger
     const char* triggerStr = convertTriggerEnumToString(payload->trigger);
-    err = err || AddTextStringToMap(&map, OC_RSRVD_TRIGGER, sizeof(OC_RSRVD_TRIGGER) - 1,
+    err = err | AddTextStringToMap(&map, OC_RSRVD_TRIGGER, sizeof(OC_RSRVD_TRIGGER) - 1,
             triggerStr);
 
     // Resource type name
     if(payload->trigger != OC_PRESENCE_TRIGGER_DELETE)
     {
-        err = err || ConditionalAddTextStringToMap(&map, OC_RSRVD_RESOURCE_TYPE,
+        err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_RESOURCE_TYPE,
                 sizeof(OC_RSRVD_RESOURCE_TYPE) - 1, payload->resourceType);
     }
 
     // Close Map
-    err = err || cbor_encoder_close_container(&rootArray, &map);
-    err = err || cbor_encoder_close_container(&encoder, &rootArray);
-
-    if(err)
-    {
-        OC_LOG_V(ERROR, TAG, "Convert Presence Payload failed with : %d", err);
-        return OC_STACK_ERROR;
-    }
-
-    *size = encoder.ptr - *outPayload;
-    uint8_t* tempPayload = (uint8_t*)OICRealloc(*outPayload, *size);
-
-    if(!tempPayload)
-    {
-        OC_LOG_V(ERROR, TAG, PCF("Payload realloc failed!"));
-        OICFree(*outPayload);
-        return OC_STACK_ERROR;
-    }
-
-    *outPayload = tempPayload;
+    err = err | cbor_encoder_close_container(&rootArray, &map);
+    err = err | cbor_encoder_close_container(&encoder, &rootArray);
 
-    return OC_STACK_OK;
+    return checkError(err, &encoder, outPayload, size);
 }
 
-bool AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
+static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
         const char* value)
 {
-    return cbor_encode_text_string(map, key, keylen) ||
+    return cbor_encode_text_string(map, key, keylen) |
            cbor_encode_text_string(map, value, strlen(value));
 }
 
-bool ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
+static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
         const char* value)
 {
-    return value ? AddTextStringToMap(map, key, keylen, value) : false;
+    return value ? AddTextStringToMap(map, key, keylen, value) : 0;
 }
index 203986f..aa63c53 100644 (file)
@@ -59,7 +59,7 @@ OCStackResult OCParsePayload(OCPayload** outPayload, const uint8_t* payload, siz
     // enter the array
     err = err || cbor_value_enter_container(&rootValue, &arrayValue);
 
-    int payloadType;
+    int payloadType = 0;
     err = err || cbor_value_get_int(&arrayValue, &payloadType);
     err = err || cbor_value_advance_fixed(&arrayValue);
 
@@ -171,6 +171,7 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
         if(!resource)
         {
             OC_LOG_V(ERROR, TAG, "Memory allocation failed");
+            OCDiscoveryPayloadDestroy(out);
             return OC_STACK_NO_MEMORY;
         }
         CborValue curVal;
@@ -203,27 +204,38 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
                     llPtr = resource->types;
                     if(!llPtr)
                     {
-                        OC_LOG_V(ERROR, TAG, "Memory allocation failed");
+                        OC_LOG(ERROR, TAG, PCF("Memory allocation failed"));
                         OICFree(resource->uri);
                         OICFree(resource->sid);
                         OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
                         return OC_STACK_NO_MEMORY;
                     }
                 }
-                else
+                else if(llPtr)
                 {
                     llPtr->next = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
                     llPtr = llPtr->next;
                     if(!llPtr)
                     {
-                        OC_LOG_V(ERROR, TAG, "Memory allocation failed");
+                        OC_LOG(ERROR, TAG, PCF("Memory allocation failed"));
                         OICFree(resource->uri);
                         OICFree(resource->sid);
                         OCFreeOCStringLL(resource->types);
                         OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
                         return OC_STACK_NO_MEMORY;
                     }
-
+                }
+                else
+                {
+                        OC_LOG(ERROR, TAG, PCF("Unknown state in resource type copying"));
+                        OICFree(resource->uri);
+                        OICFree(resource->sid);
+                        OCFreeOCStringLL(resource->types);
+                        OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
+                        return OC_STACK_NO_MEMORY;
                 }
 
                  err = err || cbor_value_dup_text_string(&rtVal, &(llPtr->value), &len, NULL);
@@ -252,10 +264,11 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
                         OICFree(resource->sid);
                         OCFreeOCStringLL(resource->types);
                         OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
                         return OC_STACK_NO_MEMORY;
                     }
                 }
-                else
+                else if (llPtr)
                 {
                     llPtr->next = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
                     llPtr = llPtr->next;
@@ -267,9 +280,20 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
                         OCFreeOCStringLL(resource->types);
                         OCFreeOCStringLL(resource->interfaces);
                         OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
                         return OC_STACK_NO_MEMORY;
                     }
                 }
+                else
+                {
+                        OC_LOG(ERROR, TAG, PCF("Unknown state in resource interfaces copying"));
+                        OICFree(resource->uri);
+                        OICFree(resource->sid);
+                        OCFreeOCStringLL(resource->types);
+                        OICFree(resource);
+                        OCDiscoveryPayloadDestroy(out);
+                        return OC_STACK_NO_MEMORY;
+                }
 
                  err = err || cbor_value_dup_text_string(&ifVal, &(llPtr->value), &len, NULL);
                  err = err || cbor_value_advance(&ifVal);
@@ -305,7 +329,7 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
             }
         }
 
-         err = err || cbor_value_advance(arrayVal);
+        err = err || cbor_value_advance(arrayVal);
         if(err)
         {
             OICFree(resource->uri);
@@ -321,9 +345,16 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue*
         OCDiscoveryPayloadAddNewResource(out, resource);
     }
 
-    *outPayload = (OCPayload*)out;
-
-    return OC_STACK_OK;
+    if(err)
+    {
+        OCDiscoveryPayloadDestroy(out);
+        return OC_STACK_MALFORMED_RESPONSE;
+    }
+    else
+    {
+        *outPayload = (OCPayload*)out;
+        return OC_STACK_OK;
+    }
 }
 
 static OCStackResult OCParseDevicePayload(OCPayload** outPayload, CborValue* arrayVal)
@@ -404,7 +435,7 @@ static OCStackResult OCParsePlatformPayload(OCPayload** outPayload, CborValue* a
     if(cbor_value_is_map(arrayVal))
     {
         char* uri = NULL;
-        OCPlatformInfo info = {};
+        OCPlatformInfo info = {0};
         CborValue curVal;
          err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_HREF, &curVal);
         size_t len;
@@ -557,85 +588,112 @@ static bool OCParseArray(OCRepPayload* out, const char* name, CborValue* contain
     {
         case OCREP_PROP_INT:
             arr = (int64_t*)OICMalloc(dimTotal * sizeof(int64_t));
-            for(size_t i = 0; i < dimTotal && !err; ++i)
+            if (arr)
             {
-                 err = err || cbor_value_get_int64(&insideArray, &(((int64_t*)arr)[i]));
-                 err = err || cbor_value_advance_fixed(&insideArray);
+                for(size_t i = 0; i < dimTotal && !err; ++i)
+                {
+                     err = err || cbor_value_get_int64(&insideArray, &(((int64_t*)arr)[i]));
+                     err = err || cbor_value_advance_fixed(&insideArray);
+                }
+                if(err || !OCRepPayloadSetIntArrayAsOwner(out, name, (int64_t*)arr, dimensions))
+                {
+                    OICFree(arr);
+                    err = true;
+                }
             }
-            if(!err &&
-                OCRepPayloadSetIntArrayAsOwner(out, name, (int64_t*)arr, dimensions))
-            {}
             else
             {
-                err = CborUnknownError;
+                err = true;
             }
             break;
         case OCREP_PROP_DOUBLE:
             arr = (double*)OICMalloc(dimTotal * sizeof(double));
-            for(size_t i = 0; i < dimTotal && !err; ++i)
+            if(arr)
             {
-                 err = err || cbor_value_get_double(&insideArray, &(((double*)arr)[i]));
-                 err = err || cbor_value_advance_fixed(&insideArray);
+                for(size_t i = 0; i < dimTotal && !err; ++i)
+                {
+                     err = err || cbor_value_get_double(&insideArray, &(((double*)arr)[i]));
+                     err = err || cbor_value_advance_fixed(&insideArray);
+                }
+                if(err || !OCRepPayloadSetDoubleArrayAsOwner(out, name, (double*)arr, dimensions))
+                {
+                    OICFree(arr);
+                    err = true;
+                }
             }
-            if(!err &&
-                OCRepPayloadSetDoubleArrayAsOwner(out, name, (double*)arr, dimensions))
-            {}
             else
             {
-                err = CborUnknownError;
+                err = true;
             }
             break;
         case OCREP_PROP_BOOL:
             arr = (bool*)OICMalloc(dimTotal * sizeof(bool));
-            for(size_t i = 0; i < dimTotal && !err; ++i)
+            if(arr)
             {
-                 err = err || cbor_value_get_boolean(&insideArray, &(((bool*)arr)[i]));
-                 err = err || cbor_value_advance_fixed(&insideArray);
+                for(size_t i = 0; i < dimTotal && !err; ++i)
+                {
+                     err = err || cbor_value_get_boolean(&insideArray, &(((bool*)arr)[i]));
+                     err = err || cbor_value_advance_fixed(&insideArray);
+                }
+                if(err || !OCRepPayloadSetBoolArrayAsOwner(out, name, (bool*)arr, dimensions))
+                {
+                    OICFree(arr);
+                    err = true;
+                }
             }
-            if(!err &&
-                OCRepPayloadSetBoolArrayAsOwner(out, name, (bool*)arr, dimensions))
-            {}
             else
             {
-                err = CborUnknownError;
+                err = true;
             }
             break;
         case OCREP_PROP_STRING:
             arr = (char**)OICMalloc(dimTotal * sizeof(char*));
-            for(size_t i = 0; i < dimTotal && !err; ++i)
+            if(arr)
             {
-                err = err || cbor_value_dup_text_string(&insideArray, &tempStr, &len, NULL);
-                ((char**) arr)[i] = tempStr;
-                err = err || cbor_value_advance(&insideArray);
+                for(size_t i = 0; i < dimTotal && !err; ++i)
+                {
+                    err = err || cbor_value_dup_text_string(&insideArray, &tempStr,
+                            &len, NULL);
+                    err = err || cbor_value_advance(&insideArray);
+                    ((char**)arr)[i] = tempStr;
+                }
+                if(err || !OCRepPayloadSetStringArrayAsOwner(out, name, (char**)arr, dimensions))
+                {
+                    OICFree(arr);
+                    err = true;
+                }
             }
-            if(!err &&
-                OCRepPayloadSetStringArrayAsOwner(out, name, (char**)arr, dimensions))
-            {}
             else
             {
-                err = CborUnknownError;
+                err = true;
             }
             break;
         case OCREP_PROP_OBJECT:
             arr = (OCRepPayload**)OICMalloc(dimTotal * sizeof(OCRepPayload*));
-            for(size_t i = 0; i < dimTotal && !err; ++i)
+            if(arr)
             {
-                pl = NULL;
-                 err = err || OCParseSingleRepPayload(&pl, &insideArray);
-                ((OCRepPayload**)arr)[i] = pl;
-                 err = err || cbor_value_advance(&insideArray);
+                for(size_t i = 0; i < dimTotal && !err; ++i)
+                {
+                    pl = NULL;
+                    err = err || OCParseSingleRepPayload(&pl, &insideArray);
+                    err = err || cbor_value_advance(&insideArray);
+                    ((OCRepPayload**)arr)[i] = pl;
+                }
+                if(err || !OCRepPayloadSetPropObjectArrayAsOwner(out, name,
+                        (OCRepPayload**)arr, dimensions))
+                {
+                    OICFree(arr);
+                    err = true;
+                }
             }
-            if(!err &&
-                OCRepPayloadSetPropObjectArrayAsOwner(out, name, (OCRepPayload**)arr, dimensions))
-            {}
             else
             {
-                err = CborUnknownError;
+                err = true;
             }
             break;
         default:
             OC_LOG(ERROR, TAG, "Invalid Array type in Parse Array");
-            err = CborUnknownError;
+            err = true;
             break;
     }
 
@@ -664,7 +722,7 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repPar
     err = err || cbor_value_map_find_value(repParent, OC_RSRVD_PROPERTY, &curVal);
     if(cbor_value_is_valid(&curVal))
     {
-        CborValue insidePropArray;
+        CborValue insidePropArray = {0};
         err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_RESOURCE_TYPE,
                 &insidePropArray);
 
@@ -724,27 +782,42 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repPar
             switch(cbor_value_get_type(&repMap))
             {
                 case CborNullType:
-                    OCRepPayloadSetNull(curPayload, name);
+                    err = !OCRepPayloadSetNull(curPayload, name);
                     break;
                 case CborIntegerType:
                     err = err || cbor_value_get_int64(&repMap, &intval);
-                    OCRepPayloadSetPropInt(curPayload, name, intval);
+                    if (!err)
+                    {
+                        err = !OCRepPayloadSetPropInt(curPayload, name, intval);
+                    }
                     break;
                 case CborDoubleType:
                     err = err || cbor_value_get_double(&repMap, &doubleval);
-                    OCRepPayloadSetPropDouble(curPayload, name, doubleval);
+                    if (!err)
+                    {
+                        err = !OCRepPayloadSetPropDouble(curPayload, name, doubleval);
+                    }
                     break;
                 case CborBooleanType:
                     err = err || cbor_value_get_boolean(&repMap, &boolval);
-                    OCRepPayloadSetPropBool(curPayload, name, boolval);
+                    if (!err)
+                    {
+                        err = !OCRepPayloadSetPropBool(curPayload, name, boolval);
+                    }
                     break;
                 case CborTextStringType:
                     err = err || cbor_value_dup_text_string(&repMap, &strval, &len, NULL);
-                    OCRepPayloadSetPropStringAsOwner(curPayload, name, strval);
+                    if (!err)
+                    {
+                        err = !OCRepPayloadSetPropStringAsOwner(curPayload, name, strval);
+                    }
                     break;
                 case CborMapType:
                     err = err || OCParseSingleRepPayload(&pl, &repMap);
-                    OCRepPayloadSetPropObjectAsOwner(curPayload, name, pl);
+                    if (!err)
+                    {
+                        err = !OCRepPayloadSetPropObjectAsOwner(curPayload, name, pl);
+                    }
                     break;
                 case CborArrayType:
                     err = err || OCParseArray(curPayload, name, &repMap);
@@ -818,16 +891,16 @@ static OCStackResult OCParsePresencePayload(OCPayload** outPayload, CborValue* a
 
         CborValue curVal;
         // Sequence Number
-         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_NONCE, &curVal);
-         err = err || cbor_value_get_uint64(&curVal, &seqNum);
+        err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_NONCE, &curVal);
+        err = err || cbor_value_get_uint64(&curVal, &seqNum);
 
         // Max Age
-         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TTL, &curVal);
-         err = err || cbor_value_get_uint64(&curVal, &maxAge);
+        err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TTL, &curVal);
+        err = err || cbor_value_get_uint64(&curVal, &maxAge);
 
         // Trigger
-         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TRIGGER, &curVal);
-         err = err || cbor_value_dup_text_string(&curVal, &tempStr, &len, NULL);
+        err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TRIGGER, &curVal);
+        err = err || cbor_value_dup_text_string(&curVal, &tempStr, &len, NULL);
         trigger = convertTriggerStringToEnum(tempStr);
         OICFree(tempStr);
         tempStr = NULL;
index 9f8b0dc..d2c6aee 100644 (file)
@@ -517,13 +517,6 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
             OC_LOG(ERROR, TAG, "Error converting payload");
             return result;
         }
-
-        if(responseInfo.info.payloadSize > MAX_RESPONSE_LENGTH)
-        {
-            OICFree(responseInfo.info.payload);
-            OC_LOG(ERROR, TAG, "Payload too long!");
-            return OC_STACK_INVALID_PARAM;
-        }
     }
     else
     {
index be6fa96..3eda85a 100644 (file)
@@ -1316,11 +1316,12 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
         }
     }
 
-    if (requestInfo->info.payload)
+    if ((requestInfo->info.payload) && (0 < requestInfo->info.payloadSize))
     {
         serverRequest.reqTotalSize = requestInfo->info.payloadSize;
-        memcpy (&(serverRequest.payload), requestInfo->info.payload,
-                requestInfo->info.payloadSize);
+        serverRequest.payload = (uint8_t *) OICMalloc(requestInfo->info.payloadSize);
+        memcpy (serverRequest.payload, requestInfo->info.payload,
+                 requestInfo->info.payloadSize);
     }
     else
     {
@@ -1347,6 +1348,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
                         requestInfo->info.type, requestInfo->info.numOptions,
                         requestInfo->info.options, requestInfo->info.token,
                         requestInfo->info.tokenLength);
+            OICFree(serverRequest.payload);
             return;
     }
 
@@ -1362,6 +1364,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
                 requestInfo->info.type, requestInfo->info.numOptions,
                 requestInfo->info.options, requestInfo->info.token,
                 requestInfo->info.tokenLength);
+        OICFree(serverRequest.payload);
         return;
     }
     memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength);
@@ -1393,6 +1396,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
                 requestInfo->info.type, requestInfo->info.numOptions,
                 requestInfo->info.options, requestInfo->info.token,
                 requestInfo->info.tokenLength);
+         OICFree(serverRequest.payload);
         OICFree(serverRequest.requestToken);
         return;
     }
@@ -1424,6 +1428,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
     }
     // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest.
     // The token is copied in there, and is thus still owned by this function.
+    OICFree(serverRequest.payload);
     OICFree(serverRequest.requestToken);
     OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
 }
@@ -2044,6 +2049,8 @@ OCStackResult OCDoResource(OCDoHandle *handle,
         }
         else
         {
+            tmpDevAddr.adapter = adapter;
+            tmpDevAddr.flags = flags;
             destination = &tmpDevAddr;
             requestInfo.isMulticast = true;
         }