blockwise-transfer rebase into master for merge/review
authorhyuna0213.jo <hyuna0213.jo@samsung.com>
Wed, 22 Jul 2015 02:49:01 +0000 (11:49 +0900)
committerErich Keane <erich.keane@intel.com>
Wed, 22 Jul 2015 18:10:22 +0000 (18:10 +0000)
- block option1, option2 can be supported
- size option can be supported
- late negotiation is supported
- IP tansport can be supported
- not supported in single threaded devices such as the Arduino Mega
- design document can be found on the link below
  https://wiki.iotivity.org/proposal_for_block-wise_transfer

Change-Id: Iebaa23ff8a6c1e23ee9fa6e10c09d76385affb66
Signed-off-by: hyuna0213.jo <hyuna0213.jo@samsung.com>
Signed-off-by: jihwan.seo <jihwan.seo@samsung.com>
Signed-off-by: Sandipan Patra <sandipan.p@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1667
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Erich Keane <erich.keane@intel.com>
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/build/android/jni/Android.mk
resource/csdk/connectivity/common/src/caremotehandler.c
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/samples/tizen/casample.c
resource/csdk/connectivity/src/SConscript
resource/csdk/connectivity/src/cablockwisetransfer.c [new file with mode: 0644]
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/caprotocolmessage.c

index 00dac16..666bec0 100644 (file)
@@ -20,7 +20,7 @@
 
 /**
  * @file cacommon.h
- * @brief This file contains the common data structures between Resource , CA and adapters
+ * This file contains the common data structures between Resource , CA and adapters
  */
 
 #ifndef CA_COMMON_H_
@@ -37,32 +37,32 @@ extern "C"
 #endif
 
 /**
- * @brief IP address Length
+ * IP address Length
  */
 #define CA_IPADDR_SIZE 16
 
 /**
- * @brief Remote Access jabber ID length.
+ * Remote Access jabber ID length.
  */
 #define CA_RAJABBERID_SIZE 256
 
 /**
- * @brief Mac address length for BT port
+ * Mac address length for BT port
  */
 #define CA_MACADDR_SIZE 18
 
 /**
- * @brief Max header options data length
+ * Max header options data length
  */
 #define CA_MAX_HEADER_OPTION_DATA_LENGTH 16
 
 /**
-* @brief Max token length
+* Max token length
 */
 #define CA_MAX_TOKEN_LEN (8)
 
 /**
- * @brief Max URI length
+ * Max URI length
  */
 #ifdef ARDUINO
 #define CA_MAX_URI_LENGTH 128  /* maximum size of URI for embedded platforms*/
@@ -71,7 +71,7 @@ extern "C"
 #endif
 
 /**
- * @brief Max PDU length supported
+ * Max PDU length supported
  */
 #ifdef ARDUINO
 #define COAP_MAX_PDU_SIZE           320  /* maximum size of a CoAP PDU for embedded platforms*/
@@ -79,13 +79,17 @@ 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
+ *Maximum length of the remoteEndpoint identity
  */
 #define CA_MAX_ENDPOINT_IDENTITY_LEN   (32)
 
 /**
- * @brief option types - the highest option number 63
+ * option types - the highest option number 63
  */
 #define CA_OPTION_IF_MATCH 1
 #define CA_OPTION_ETAG 4
@@ -101,17 +105,17 @@ extern "C"
 #define CA_OPTION_LOCATION_QUERY 20
 
 /**
- * @brief Payload information from resource model
+ * Payload information from resource model
  */
 typedef uint8_t *CAPayload_t;
 
 /**
- * @brief URI for the OIC base.CA considers relative URI as the URI.
+ * URI for the OIC base.CA considers relative URI as the URI.
  */
 typedef char *CAURI_t;
 
 /**
- * @brief Token information for mapping the request and responses by resource model
+ * Token information for mapping the request and responses by resource model
  */
 typedef char *CAToken_t;
 
@@ -165,7 +169,7 @@ typedef enum
 
 /**
  * @enum CANetworkStatus_t
- * @brief Information about the network status.
+ * Information about the network status.
  */
 typedef enum
 {
@@ -174,7 +178,7 @@ typedef enum
 } CANetworkStatus_t;
 
 /*
- * @brief remoteEndpoint identity
+ * remoteEndpoint identity
  */
 typedef struct
 {
@@ -184,7 +188,7 @@ typedef struct
 
 /**
  * @enum CAMessageType_t
- * @brief Message Type for Base source code
+ * Message Type for Base source code
  */
 typedef enum
 {
@@ -197,7 +201,7 @@ typedef enum
 
 /**
  * @enum CAMethod_t
- * @brief Allowed method to be used by resource model
+ * Allowed method to be used by resource model
  */
 typedef enum
 {
@@ -208,7 +212,22 @@ typedef enum
 } CAMethod_t;
 
 /**
- * @brief Endpoint information for connectivities
+ * 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;
+
+/**
+ * Endpoint information for connectivities
  * Must be identical to OCDevAddr.
  */
 typedef struct
@@ -223,11 +242,11 @@ typedef struct
 
 /**
  * @enum CAResult_t
- * @brief Enums for CA return values
+ * Enums for CA return values
  */
 typedef enum
 {
-    // Result code - START HERE
+    /* Result code - START HERE */
     CA_STATUS_OK = 0,               /**< Success */
     CA_STATUS_INVALID_PARAM,        /**< Invalid Parameter */
     CA_ADAPTER_NOT_ENABLED,         /**< Adapter is not enabled */
@@ -241,14 +260,14 @@ typedef enum
     CA_REQUEST_TIMEOUT,             /**< Request is Timeout */
     CA_DESTINATION_DISCONNECTED,    /**< Destination is disconnected */
     CA_NOT_SUPPORTED,               /**< Not supported */
-    CA_STATUS_NOT_INITIALIZED,      /**< CA layer is not initialized */
+    CA_STATUS_NOT_INITIALIZED,      /**< Not Initialized*/
     CA_STATUS_FAILED =255           /**< Failure */
     /* Result code - END HERE */
 } CAResult_t;
 
 /**
  * @enum CAResponseResult_t
- * @brief Enums for CA Response values
+ * Enums for CA Response values
  */
 typedef enum
 {
@@ -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 */
@@ -272,7 +294,7 @@ typedef enum
 
 /**
  * @enum CATransportProtocolID_t
- * @brief Transport Protocol IDs for additional options
+ * Transport Protocol IDs for additional options
  */
 typedef enum
 {
@@ -282,7 +304,7 @@ typedef enum
 
 /**
  * @enum CAAdapterState_t
- * @brief Adapter State to indicate the network changed notifications.
+ * Adapter State to indicate the network changed notifications.
  */
 typedef enum
 {
@@ -291,7 +313,7 @@ typedef enum
 } CAAdapterState_t;
 
 /**
- * @brief Header options structure to be filled
+ * Header options structure to be filled
  *
  * This structure is used to hold header information.
  */
@@ -305,7 +327,7 @@ typedef struct
 } CAHeaderOption_t;
 
 /**
- * @brief Base Information received
+ * Base Information received
  *
  * This structure is used to hold request & response base information
  */
@@ -326,7 +348,7 @@ typedef struct
 } CAInfo_t;
 
 /**
- * @brief Request Information to be sent
+ * Request Information to be sent
  *
  * This structure is used to hold request information
  */
@@ -338,7 +360,7 @@ typedef struct
 } CARequestInfo_t;
 
 /**
- * @brief Response information received
+ * Response information received
  *
  * This structure is used to hold response information
  */
@@ -349,7 +371,7 @@ typedef struct
 } CAResponseInfo_t;
 
 /**
- * @brief Error information from CA
+ * Error information from CA
  *        contains error code and message information
  *
  * This structure holds error information
@@ -362,7 +384,7 @@ typedef struct
 } CAErrorInfo_t;
 
 /**
- * @brief CA Remote Access information for XMPP Client
+ * CA Remote Access information for XMPP Client
  *
  */
 typedef struct
@@ -378,7 +400,7 @@ typedef struct
 
 
 /**
- * @brief Hold global variables for CA layer (also used by RI layer)
+ * Hold global variables for CA layer (also used by RI layer)
  */
 typedef struct
 {
@@ -395,30 +417,30 @@ typedef struct
 
     struct sockets
     {
-        void *threadpool;   // threadpool between Initialize and Start
-        CASocket_t u6;      // unicast   IPv6
-        CASocket_t u6s;     // unicast   IPv6 secure
-        CASocket_t u4;      // unicast   IPv4
-        CASocket_t u4s;     // unicast   IPv4 secure
-        CASocket_t m6;      // multicast IPv6
-        CASocket_t m6s;     // multicast IPv6 secure
-        CASocket_t m4;      // multicast IPv4
-        CASocket_t m4s;     // multicast IPv4 secure
-        int netlinkFd;      // netlink
-        int shutdownFds[2]; // shutdown pipe
-        int selectTimeout;  // in seconds
-        int maxfd;          // highest fd (for select)
-        int numInterfaces;  // number of active interfaces
-        bool started;       // the IP adapter has started
-        bool terminate;     // the IP adapter needs to stop
-        bool ipv6enabled;   // IPv6 enabled by OCInit flags
-        bool ipv4enabled;   // IPv4 enabled by OCInit flags
+        void *threadpool;   /**< threadpool between Initialize and Start */
+        CASocket_t u6;      /**< unicast   IPv6 */
+        CASocket_t u6s;     /**< unicast   IPv6 secure */
+        CASocket_t u4;      /**< unicast   IPv4 */
+        CASocket_t u4s;     /**< unicast   IPv4 secure */
+        CASocket_t m6;      /**< multicast IPv6 */
+        CASocket_t m6s;     /**< multicast IPv6 secure */
+        CASocket_t m4;      /**< multicast IPv4 */
+        CASocket_t m4s;     /**< multicast IPv4 secure */
+        int netlinkFd;      /**< netlink */
+        int shutdownFds[2]; /**< shutdown pipe */
+        int selectTimeout;  /**< in seconds */
+        int maxfd;          /**< highest fd (for select) */
+        int numInterfaces;  /**< number of active interfaces */
+        bool started;       /**< the IP adapter has started */
+        bool terminate;     /**< the IP adapter needs to stop */
+        bool ipv6enabled;   /**< IPv6 enabled by OCInit flags */
+        bool ipv4enabled;   /**< IPv4 enabled by OCInit flags */
     } ip;
 
     struct calayer
     {
-        CATransportFlags_t previousRequestFlags; // address family filtering
-        uint16_t previousRequestMessageId;       // address family filtering
+        CATransportFlags_t previousRequestFlags; /**< address family filtering */
+        uint16_t previousRequestMessageId;       /**< address family filtering */
     } ca;
 } CAGlobals_t;
 
@@ -428,5 +450,4 @@ extern CAGlobals_t caglobals;
 } /* extern "C" */
 #endif
 
-#endif //#ifndef CA_COMMON_H_
-
+#endif // CA_COMMON_H_
index c0e68fd..ed86105 100644 (file)
@@ -167,12 +167,12 @@ LOCAL_C_INCLUDES += $(OIC_C_COMMON_PATH)/oic_string/include
 LOCAL_C_INCLUDES += $(DTLS_LIB)
 
 LOCAL_CFLAGS += $(BUILD_FLAG)
-LOCAL_CFLAGS += -std=c99 -DWITH_POSIX
+LOCAL_CFLAGS += -std=c99 -DWITH_POSIX -DWITH_BWT
 
 LOCAL_SRC_FILES = \
                 caconnectivitymanager.c cainterfacecontroller.c \
                 camessagehandler.c canetworkconfigurator.c caprotocolmessage.c \
-                caretransmission.c caqueueingthread.c \
+                caretransmission.c caqueueingthread.c cablockwisetransfer.c \
                 $(ADAPTER_UTILS)/caadapternetdtls.c $(ADAPTER_UTILS)/caadapterutils.c \
                 $(ADAPTER_UTILS)/cafragmentation.c \
                 bt_le_adapter/caleadapter.c $(LE_ADAPTER_PATH)/caleclient.c \
@@ -185,4 +185,3 @@ LOCAL_SRC_FILES = \
                 $(IP_ADAPTER_PATH)/android/caipnwmonitor.c \
 
 include $(BUILD_STATIC_LIBRARY)
-
index c9b7f5e..decc861 100644 (file)
@@ -167,13 +167,16 @@ CAResponseInfo_t *CACloneResponseInfo(const CAResponseInfo_t *rep)
         case CA_CREATED:
         case CA_DELETED:
         case CA_VALID:
-        case CA_CHANGED:
         case CA_CONTENT:
+        case CA_CHANGED:
+        case CA_CONTINUE:
         case CA_BAD_REQ:
         case CA_UNAUTHORIZED_REQ:
         case CA_BAD_OPT:
         case CA_FORBIDDEN_REQ:
         case CA_NOT_FOUND:
+        case CA_REQUEST_ENTITY_INCOMPLETE:
+        case CA_REQUEST_ENTITY_TOO_LARGE:
         case CA_INTERNAL_SERVER_ERROR:
         case CA_RETRANSMIT_TIMEOUT:
             break;
diff --git a/resource/csdk/connectivity/inc/cablockwisetransfer.h b/resource/csdk/connectivity/inc/cablockwisetransfer.h
new file mode 100644 (file)
index 0000000..b75b099
--- /dev/null
@@ -0,0 +1,501 @@
+/* *****************************************************************
+ *
+ * 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);
+
+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;
+
+typedef struct
+{
+    coap_block_t block;                 /**< block option */
+    uint16_t type;                      /**< block option type */
+    CAToken_t token;                    /**< token for CA */
+    uint8_t tokenLength;                /**< token length*/
+    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;
+
+/**
+ * CABlockState_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 CA_STATUS_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 CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CATerminateBlockWiseTransfer();
+
+/**
+ * initialize mutex
+ * @return CA_STATUS_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 CA_STATUS_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]   token   token of current message
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const unsigned char* token);
+
+/**
+ * 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 CA_STATUS_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 CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAReceiveBlockWiseData(const 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
+ * @return CA_STATUS_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);
+
+/**
+ * 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
+ * @return CA_STATUS_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);
+
+/**
+ * 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
+ * @return CA_STATUS_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);
+
+/**
+ * receive last block data
+ * @param[in]   pdu received pdu binary data
+ * @param[in]   receivedData    received CAData
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAReceiveLastBlock(const coap_pdu_t *pdu, 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 CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CASetNextBlockOption1(const 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 CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CASetNextBlockOption2(const 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 CA_STATUS_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
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block);
+
+/**
+ * Update the messageId in block-wise transfer list
+ * @param[in]   currData    stored block data information
+ * @param[in]   block block option of current message
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu);
+
+/**
+ * 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 CA_STATUS_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 CA_STATUS_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
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAAddBlockOption(coap_pdu_t **pdu, CAInfo_t info);
+
+/**
+ * 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
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, CAInfo_t info, size_t dataLength);
+
+/**
+ * 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
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, CAInfo_t info, size_t dataLength);
+
+/**
+ * Add the block option in pdu data
+ * @param[in]   pdu pdu object
+ * @param[out]  block block data
+ * @param[in]   blockType   block option type
+ * @return CA_STATUS_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 CA_STATUS_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(const 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
+ * @return CA_STATUS_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);
+
+/**
+ * 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 CA_STATUS_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);
+
+/**
+ * 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 CA_STATUS_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]   token   token of current message
+ * @param[in]   blockType   block option type
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CAUpdateBlockOptionType(const unsigned char* token, uint8_t blockType);
+
+/**
+ * Get the block option type from block-wise transfer list
+ * @param[in]   token   token of current message
+ * @return block option type
+ */
+uint8_t CAGetBlockOptionType(const unsigned char* token);
+
+/**
+ * Get the block data from block-wise transfer list
+ * @param[in]   token   token of current message
+ * @return CAData structure
+ */
+CAData_t *CAGetDataSetFromBlockDataList(const unsigned char* token);
+
+/**
+ * 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 CA_STATUS_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 CA_STATUS_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]   token   token of current message
+ * @return CABlockData_t structure
+ */
+CABlockData_t *CAGetBlockDataFromBlockDataList(const unsigned char* token);
+
+/**
+ * Get the block option from block-wise transfer list
+ * @param[in]   token   token of current message
+ * @return coap_block_t structure
+ */
+coap_block_t *CAGetBlockOption(const unsigned char* token);
+
+/**
+ * Get the full payload from block-wise list
+ * @param[in]   token   token of current message
+ * @param[out]  fullPayloadLen  received full payload length
+ * @return payload
+ */
+CAPayload_t CAGetPayloadFromBlockDataList(const unsigned char* token, 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]   token   token of current message
+ * @return CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
+ */
+CAResult_t CARemoveBlockDataFromList(const unsigned char* token);
+
+/**
+ * Check if data exist in block-wise transfer list.
+ * @param[in]   pdu pdu object
+ * @return true or false
+ */
+bool CAIsBlockDataInList(const coap_pdu_t *pdu);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif  // CA_BLOCKWISETRANSFER_H_
index 844cb5b..7dd323d 100644 (file)
@@ -1,4 +1,4 @@
-/******************************************************************
+/* *****************************************************************
  *
  * Copyright 2014 Samsung Electronics All Rights Reserved.
  *
@@ -20,7 +20,7 @@
 
 /**
  * @file camessagehandler.h
- * @brief This file contains message functionality.
+ * This file contains message functionality.
  */
 
 #ifndef CA_MESSAGE_HANDLER_H_
@@ -63,39 +63,39 @@ extern "C"
 #endif
 
 /**
- * @brief   Detaches control from the caller for sending unicast request
- * @param   endpoint       [IN]    endpoint information where the data has to be sent
- * @param   request        [IN]    request that needs to be sent
+ * Detaches control from the caller for sending unicast request
+ * @param[IN] endpoint    endpoint information where the data has to be sent
+ * @param[IN] request     request that needs to be sent
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
  */
 CAResult_t CADetachRequestMessage(const CAEndpoint_t *endpoint,
                                   const CARequestInfo_t *request);
 
 /**
- * @brief   Detaches control from the caller for sending multicast request
- * @param   object         [IN]    Group endpoint information where the data has to be sent
- * @param   request        [IN]    request that needs to be sent
+ * Detaches control from the caller for sending multicast request
+ * @param[IN] object     Group endpoint information where the data has to be sent
+ * @param[IN] request    request that needs to be sent
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
  */
 CAResult_t CADetachRequestToAllMessage(const CAEndpoint_t *object,
                                        const CARequestInfo_t *request);
 
 /**
- * @brief   Detaches control from the caller for sending response
- * @param   endpoint       [IN]    endpoint information where the data has to be sent
- * @param   response       [IN]    response that needs to be sent
+ * Detaches control from the caller for sending response
+ * @param[IN] endpoint    endpoint information where the data has to be sent
+ * @param[IN] response    response that needs to be sent
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
  */
 CAResult_t CADetachResponseMessage(const CAEndpoint_t *endpoint,
                                    const CAResponseInfo_t *response);
 
 /**
- * @brief   Detaches control from the caller for sending request
- * @param   resourceUri    [IN]    resource uri that needs to  be sent in the request
- * @param   token          [IN]    token information of the request
- * @param   tokenLength    [IN]    length of the token
- * @param   options        [IN]    header options that need to be append in the request
- * @param   numOptions     [IN]    number of options be appended
+ * Detaches control from the caller for sending request
+ * @param[IN] resourceUri    resource uri that needs to  be sent in the request
+ * @param[IN] token          token information of the request
+ * @param[IN] tokenLength    length of the token
+ * @param[IN] options        header options that need to be append in the request
+ * @param[IN] numOptions     number of options be appended
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
  */
 CAResult_t CADetachMessageResourceUri(const CAURI_t resourceUri, const CAToken_t token,
@@ -103,42 +103,53 @@ CAResult_t CADetachMessageResourceUri(const CAURI_t resourceUri, const CAToken_t
                                       uint8_t numOptions);
 
 /**
- * @brief   Setting the request and response callbacks for network packets
- * @param   ReqHandler     [IN]    callback for receiving the requests
- * @param   RespHandler    [IN]    callback for receiving the response
- * @param   ErrorHandler   [IN]    callback for receiving error response
- * @return  NONE
+ * Setting the request and response callbacks for network packets
+ * @param[IN] ReqHandler      callback for receiving the requests
+ * @param[IN] RespHandler     callback for receiving the response
+ * @param[IN] ErrorHandler    callback for receiving error response
  */
 void CASetInterfaceCallbacks(CARequestCallback ReqHandler, CAResponseCallback RespHandler,
                              CAErrorCallback ErrorHandler);
 
 /**
- * @brief   Initialize the message handler by starting thread pool and initializing the
- *          send and receive queue
+ * Initialize the message handler by starting thread pool and initializing the
+ * send and receive queue
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h)
  */
 CAResult_t CAInitializeMessageHandler();
 
 /**
- * @brief   Terminate the message handler by stopping  the thread pool and destroying the queues
- * @return  NONE
+ * Terminate the message handler by stopping  the thread pool and destroying the queues
  */
 void CATerminateMessageHandler();
 
 /**
- * @brief   Handler for receiving request and response callback in single thread model
+ * Handler for receiving request and response callback in single thread model
  */
 void CAHandleRequestResponseCallbacks();
 
 /**
- * @brief To log the PDU data
- * @param   pdu            [IN]    pdu data
+ * To log the PDU data
+ * @param[IN] pdu    pdu data
  */
 void CALogPDUInfo(coap_pdu_t *pdu);
 
+#ifdef WITH_BWT
+/**
+ * Add the data to the send queue thread
+ * @param[IN] data    send data
+ */
+void CAAddDataToSendThread(CAData_t *data);
+
+/**
+ * Add the data to the receive queue thread to notify received data
+ * @param[IN] data    received data
+ */
+void CAAddDataToReceiveThread(CAData_t *data);
+#endif
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
 
 #endif /* CA_MESSAGE_HANDLER_H_ */
-
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 */
 
index 4afae38..70313c1 100644 (file)
  */
 #define RS_CLIENT_PSK   ("AAAAAAAAAAAAAAAA")
 
+/**
+ * Max size for big payload.
+ */
+#define BIG_PAYLOAD_SIZE 15000
+
 static GMainLoop *g_mainloop = NULL;
 pthread_t thread;
 
@@ -91,6 +96,9 @@ void process();
 CAResult_t get_network_type();
 CAResult_t get_input_data(char *buf, int32_t length);
 
+bool select_payload();
+void populate_binary_payload(uint8_t *bigBuffer, size_t bigBufferLen);
+
 void start_listening_server();
 void start_discovery_server();
 void send_request();
@@ -411,6 +419,35 @@ void start_discovery_server()
     }
 }
 
+bool select_payload()
+{
+    char buf[MAX_BUF_LEN]={0};
+    printf("\n=============================================\n");
+    printf("0:Normal Payload\n1:Big Payload(~15KB)\n");
+    printf("select Payload type : ");
+
+    CAResult_t res = get_input_data(buf, sizeof(buf));
+    if (CA_STATUS_OK != res)
+    {
+        printf("Payload type selection error\n");
+        printf("Default: Using normal Payload\n");
+        return false;
+    }
+
+    return (buf[0] == '1') ? true : false;
+}
+
+void populate_binary_payload(uint8_t *bigBuffer, size_t bigBufferLen)
+{
+/**
+ * bigBuffer to be filled with binary data. For our sample application to verify, we may fill with
+ * any arbitrary value. Hence filling with '1' here.
+ */
+    memset(bigBuffer, '1', bigBufferLen-1);
+    //Last byte making NULL
+    bigBuffer[bigBufferLen-1] = '\0';
+}
+
 void send_request()
 {
     CAResult_t res = get_network_type();
@@ -517,23 +554,38 @@ void send_request()
         }
         snprintf((char *) requestData.payload, length, SECURE_INFO_DATA,
                  (const char *) resourceURI, g_local_secure_port);
-        requestData.payloadSize = length;
     }
     else
     {
-        size_t length = sizeof(NORMAL_INFO_DATA) + strlen(resourceURI);
-        requestData.payload = (CAPayload_t) calloc(length, sizeof(char));
-        if (NULL == requestData.payload)
+        bool useBigPayload = select_payload();
+        if (useBigPayload)
         {
-            printf("Memory allocation fail\n");
-            CADestroyEndpoint(endpoint);
-            CADestroyToken(token);
-            return;
+            requestData.payload = (CAPayload_t) calloc(BIG_PAYLOAD_SIZE, sizeof(char));
+            if (NULL == requestData.payload)
+            {
+                printf("Memory allocation fail\n");
+                CADestroyEndpoint(endpoint);
+                CADestroyToken(token);
+                return;
+            }
+            populate_binary_payload(requestData.payload, BIG_PAYLOAD_SIZE);
+        }
+        else
+        {
+            size_t length = sizeof(NORMAL_INFO_DATA) + strlen(resourceURI);
+            requestData.payload = (CAPayload_t) calloc(length, sizeof(char));
+            if (NULL == requestData.payload)
+            {
+                printf("Memory allocation fail\n");
+                CADestroyEndpoint(endpoint);
+                CADestroyToken(token);
+                return;
+            }
+            snprintf((char *) requestData.payload, length, NORMAL_INFO_DATA,
+                     (const char *) resourceURI);
         }
-        snprintf((char *) requestData.payload, length, NORMAL_INFO_DATA,
-                 (const char *) resourceURI);
-        requestData.payloadSize = length;
     }
+    requestData.payloadSize = strlen((char *)requestData.payload)+1;
     requestData.type = msgType;
 
     CARequestInfo_t requestInfo = { 0 };
@@ -599,6 +651,8 @@ void send_secure_request()
     requestData.token = token;
     requestData.tokenLength = tokenLength;
     requestData.type = msgType;
+    requestData.payload = "Temp Json Payload";
+    requestData.payloadSize = strlen(requestData.payload)+1;
 
     CARequestInfo_t requestInfo = { 0 };
     requestInfo.method = CA_GET;
@@ -1179,25 +1233,37 @@ void send_response(const CAEndpoint_t *endpoint, const CAInfo_t *info)
             }
             snprintf((char *) responseData.payload, length, SECURE_INFO_DATA,
                      (const char *) responseData.resourceUri, g_local_secure_port);
-            responseData.payloadSize = length;
         }
         else
         {
             printf("Sending response on non-secure communication\n");
 
-            uint32_t length = sizeof(NORMAL_INFO_DATA) + strlen(responseData.resourceUri);
-            responseData.payload = (CAPayload_t) calloc(length, sizeof(char));
-            if (NULL == responseData.payload)
+            bool useBigPayload = select_payload();
+            if (useBigPayload)
             {
-                printf("Memory allocation fail\n");
-                return;
+                responseData.payload = (CAPayload_t) calloc(BIG_PAYLOAD_SIZE, sizeof(char));
+                if (NULL == responseData.payload)
+                {
+                    printf("Memory allocation fail\n");
+                    return;
+                }
+                populate_binary_payload(responseData.payload, BIG_PAYLOAD_SIZE);
+            }
+            else
+            {
+                size_t length = sizeof(NORMAL_INFO_DATA) + strlen(responseData.resourceUri);
+                responseData.payload = (CAPayload_t) calloc(length, sizeof(char));
+                if (NULL == responseData.payload)
+                {
+                    printf("Memory allocation fail\n");
+                    return;
+                }
+                snprintf((char *) responseData.payload, length, NORMAL_INFO_DATA,
+                         (const char *) responseData.resourceUri);
             }
-            snprintf((char *) responseData.payload, length, NORMAL_INFO_DATA,
-                     (const char *) responseData.resourceUri);
-            responseData.payloadSize = length;
         }
     }
-
+    responseData.payloadSize = strlen((char *)responseData.payload)+1;
     CAResponseInfo_t responseInfo = { 0 };
     responseInfo.result = responseCode;
     responseInfo.info = responseData;
index 7b6ba7d..0f64df7 100755 (executable)
@@ -77,6 +77,9 @@ else:
                'caqueueingthread.c',
                'caretransmission.c',
                ]
+       if not 'BLE' 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':
diff --git a/resource/csdk/connectivity/src/cablockwisetransfer.c b/resource/csdk/connectivity/src/cablockwisetransfer.c
new file mode 100644 (file)
index 0000000..2084709
--- /dev/null
@@ -0,0 +1,2359 @@
+/* ****************************************************************
+ *
+ * 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    3
+#define BLOCK_NUMBER_IDX           4
+#define BLOCK_M_BIT_IDX            3
+
+#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");
+        CALogBlockInfo(&currData->block);
+
+        res = CAAddSendThreadQueue(currData->sentData,
+                                   (const unsigned char*) currData->token);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            return res;
+        }
+    }
+
+    return res;
+}
+
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const unsigned char* token)
+{
+    VERIFY_NON_NULL(sendData, TAG, "sendData");
+    VERIFY_NON_NULL(token, TAG, "token");
+
+    CAData_t *cloneData = CACloneCAData(sendData);
+    if (NULL == cloneData)
+    {
+        OIC_LOG(ERROR, TAG, "clone has failed");
+        CARemoveBlockDataFromList(token);
+        return CA_STATUS_FAILED;
+    }
+
+    if (g_context.sendThreadFunc)
+    {
+        ca_mutex_lock(g_context.blockDataSenderMutex);
+        g_context.sendThreadFunc(cloneData);
+        ca_mutex_unlock(g_context.blockDataSenderMutex);
+    }
+    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;
+    }
+
+    // check if next block are required to transfer
+    CAGetMoreBitFromBlock(payloadLen, &currData->block);
+
+    // set block option (COAP_OPTION_BLOCK2 or COAP_OPTION_BLOCK1)
+    if (NULL != currData->sentData->requestInfo) // request message
+    {
+        if (currData->block.m)
+        {
+            OIC_LOG(DEBUG, TAG, "no ACK, option1");
+            currData->type = COAP_OPTION_BLOCK1;
+        }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "no ACK, normal req");
+        }
+    }
+    else // response message
+    {
+        if (currData->block.m)
+        {
+            OIC_LOG(DEBUG, TAG, "ACK, option2");
+            currData->type = COAP_OPTION_BLOCK2;
+        }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "ACK, normal res");
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAReceiveBlockWiseData(const 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;
+        }
+
+        CARemoveBlockDataFromList((const unsigned char*) receivedData->responseInfo->info.token);
+        return CA_NOT_SUPPORTED;
+    }
+
+    // check if block option is set and get block data
+    coap_block_t block = {0};
+    if (coap_get_block(pdu, COAP_OPTION_BLOCK2, &block))
+    {
+        CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, block, dataLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "setting has failed");
+            return res;
+        }
+    }
+    else if (coap_get_block(pdu, COAP_OPTION_BLOCK1, &block)) // block1 option
+    {
+        CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, block, dataLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "setting has failed");
+            return res;
+        }
+    }
+    else
+    {
+        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+        if (CA_REQUEST_ENTITY_INCOMPLETE == code)
+        {
+            CABlockData_t *data = CAGetBlockDataFromBlockDataList(pdu->hdr->token);
+            if (NULL == data)
+            {
+                OIC_LOG(ERROR, TAG, "getting has failed");
+                return CA_STATUS_FAILED;
+            }
+
+            coap_block_t *block = CAGetBlockOption(pdu->hdr->token);
+            if (NULL == block)
+            {
+                OIC_LOG(ERROR, TAG, "block is null");
+                return CA_STATUS_FAILED;
+            }
+
+            if (COAP_OPTION_BLOCK2 == data->type)
+            {
+                CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block,
+                                                       dataLen);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "setting has failed");
+                    return res;
+                }
+            }
+            else if (COAP_OPTION_BLOCK1 == data->type)
+            {
+                CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block,
+                                                       dataLen);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "setting has failed");
+                    return res;
+                }
+            }
+        }
+        else
+        {
+            // normal pdu data
+            OIC_LOG(DEBUG, TAG, "it's normal pdu");
+            return CA_NOT_SUPPORTED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
+                             uint8_t blockWiseStatus)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+
+    CAResult_t res = CA_STATUS_OK;
+    CAData_t *data = NULL;
+
+    // process blockWiseStatus
+    switch (blockWiseStatus)
+    {
+        case CA_OPTION2_FIRST_BLOCK:
+            res = CAAddSendThreadQueue(receivedData, pdu->hdr->token);
+            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(pdu->hdr->token);
+            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, pdu->hdr->token);
+            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);
+            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(pdu, receivedData);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "receive has failed");
+                return res;
+            }
+
+            // remove data from list
+            res = CARemoveBlockDataFromList(pdu->hdr->token);
+            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(pdu, receivedData);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "receive has failed");
+                return res;
+            }
+
+            if (CA_MSG_CONFIRM == pdu->hdr->type)
+            {
+                // send ack message to remote device
+                res = CASendBlockMessage(pdu, CA_MSG_ACKNOWLEDGE, blockWiseStatus);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "send 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);
+                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);
+                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);
+                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);
+                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)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+
+    CAData_t *data = CAGetDataSetFromBlockDataList(pdu->hdr->token);
+    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, pdu->hdr->token);
+    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)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+
+    // create error responseInfo
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(pdu->hdr->token);
+    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
+    {
+        cloneData = CACreateNewDataSet(pdu, CACloneEndpoint(data->sentData->remoteEndpoint));
+        cloneData->responseInfo->info.type = CA_MSG_CONFIRM;
+        cloneData->responseInfo->result = responseResult;
+        OIC_LOG(DEBUG, TAG, "set CON message");
+    }
+
+    // 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);
+    }
+
+    // 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->block.num = 0;
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAReceiveLastBlock(const coap_pdu_t *pdu, const CAData_t *receivedData)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+    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(pdu->hdr->token, &fullPayloadLen);
+    if (NULL != fullPayload)
+    {
+        CAResult_t res = CAUpdatePayloadToCAData(cloneData, fullPayload, fullPayloadLen);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (g_context.receivedThreadFunc)
+    {
+        g_context.receivedThreadFunc(cloneData);
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CASetNextBlockOption1(const 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);
+
+    // BlockData data is created if it not existed
+    if (!CAIsBlockDataInList(pdu))
+    {
+        OIC_LOG(DEBUG, TAG, "no message in list");
+
+        CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+        if (NULL == data)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            return CA_STATUS_FAILED;
+        }
+
+        CABlockData_t *currData = CACreateNewBlockData(data);
+        if (NULL == currData)
+        {
+            OIC_LOG(ERROR, TAG, "currData is null");
+            CADestroyDataSet(data);
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    // update BLOCK OPTION1 type
+    CAResult_t res = CAUpdateBlockOptionType(pdu->hdr->token, COAP_OPTION_BLOCK1);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "update has failed");
+        CARemoveBlockDataFromList(pdu->hdr->token);
+        return res;
+    }
+
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(pdu->hdr->token);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        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->block.num = 0;
+            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");
+            return res;
+        }
+
+        res = CAUpdateBlockData(data, block);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CARemoveBlockDataFromList(pdu->hdr->token);
+            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);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(pdu->hdr->token);
+                return res;
+            }
+
+            res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(pdu->hdr->token);
+                return res;
+            }
+
+            // update block data
+            res = CAUpdateBlockData(data, block);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(pdu->hdr->token);
+                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);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "setting has failed");
+        CARemoveBlockDataFromList(pdu->hdr->token);
+    }
+
+    return res;
+}
+
+CAResult_t CASetNextBlockOption2(const 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");
+
+    // BlockData data is created if it not existed
+    if (!CAIsBlockDataInList(pdu))
+    {
+        OIC_LOG(DEBUG, TAG, "no msg in list.");
+
+        CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+        if (NULL == data)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            return CA_STATUS_FAILED;
+        }
+
+        CABlockData_t *currData = CACreateNewBlockData(data);
+        if (NULL == currData)
+        {
+            OIC_LOG(ERROR, TAG, "data is null");
+            CADestroyDataSet(data);
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    // set Block Option Type
+    CAResult_t res = CAUpdateBlockOptionType(pdu->hdr->token, COAP_OPTION_BLOCK2);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "update has failed");
+        CARemoveBlockDataFromList(pdu->hdr->token);
+        return res;
+    }
+
+    CABlockData_t *data = CAGetBlockDataFromBlockDataList(pdu->hdr->token);
+    if (NULL == data)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        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");
+            return res;
+        }
+
+        // first block data have to notify to Application
+        res = CAUpdateBlockData(data, block);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "update has failed");
+            CARemoveBlockDataFromList(pdu->hdr->token);
+            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);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "update has failed");
+                    CARemoveBlockDataFromList(pdu->hdr->token);
+                    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(pdu->hdr->token);
+                    return res;
+                }
+
+                res = CAUpdateBlockData(data, block);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "update has failed");
+                    CARemoveBlockDataFromList(pdu->hdr->token);
+                    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(pdu->hdr->token);
+                return res;
+            }
+
+            res = CAUpdateBlockData(data, block);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "update has failed");
+                CARemoveBlockDataFromList(pdu->hdr->token);
+                return res;
+            }
+        }
+    }
+
+    res = CAProcessNextStep(pdu, receivedData, blockWiseStatus);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "setting has failed");
+        CARemoveBlockDataFromList(pdu->hdr->token);
+        return res;
+    }
+
+    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->block.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->block.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->block.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 (((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->block.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->block.szx) - 1;
+                OIC_LOG(DEBUG, TAG, "num is set as Negotiation");
+                block->num += blockNum;
+                block->szx = currData->block.szx;
+                OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
+            }
+        }
+        else
+        {
+            if (block->szx > currData->block.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is big");
+                block->szx = currData->block.szx;
+            }
+        }
+    }
+    else if (COAP_OPTION_BLOCK1 == blockType)
+    {
+        if (CA_MSG_ACKNOWLEDGE == msgType)
+        {
+            if (block->szx < currData->block.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is small");
+
+                unsigned int blockNum = BLOCK_SIZE(currData->block.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->block.szx)
+            {
+                OIC_LOG(DEBUG, TAG, "sze is big");
+                block->szx = currData->block.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)
+{
+    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
+    currData->block = block;
+
+    OIC_LOG(DEBUG, TAG, "data has updated");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+
+    // if CON message is sent, update messageId in block-wise transfer list
+    if (CA_MSG_CONFIRM == pdu->hdr->type)
+    {
+        CAData_t * cadata = CAGetDataSetFromBlockDataList(pdu->hdr->token);
+        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, CAInfo_t info)
+{
+    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");
+
+    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;
+    }
+
+    uint8_t blockType = CAGetBlockOptionType((*pdu)->hdr->token);
+    if (COAP_OPTION_BLOCK2 == blockType)
+    {
+        CAResult_t res = CAAddBlockOption2(pdu, info, dataLength);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            return res;
+        }
+    }
+    else if (COAP_OPTION_BLOCK1 == blockType)
+    {
+        CAResult_t res = CAAddBlockOption1(pdu, info, dataLength);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            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);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "fail to update CON message id ");
+        return res;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, CAInfo_t info, size_t dataLength)
+{
+    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");
+
+    // get set block data from CABlock list-set.
+    coap_block_t *block = CAGetBlockOption((*pdu)->hdr->token);
+    if (NULL == block)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    CALogBlockInfo(block);
+
+    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(block, 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(block);
+
+        // if block number is 0, add size2 option
+        if (0 == block->num)
+        {
+            res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE2, dataLength);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                CARemoveBlockDataFromList((*pdu)->hdr->token);
+                return res;
+            }
+        }
+
+        if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+                            block->num, block->szx))
+        {
+            OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
+            return CA_STATUS_FAILED;
+        }
+
+        if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+        {
+            if (block->m)
+            {
+                OIC_LOG(DEBUG, TAG, "NON, send next block..");
+                // update block data
+                block->num++;
+                CAResult_t res = CAProcessNextStep(*pdu, NULL, CA_SENT_PREVIOUS_NON_MSG);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "failed to process next step");
+                    CARemoveBlockDataFromList((*pdu)->hdr->token);
+                    return res;
+                }
+            }
+            else
+            {
+                CARemoveBlockDataFromList((*pdu)->hdr->token);
+            }
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "option2, not ACK msg");
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block, COAP_OPTION_BLOCK2);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList((*pdu)->hdr->token);
+            return res;
+        }
+    }
+
+    return CA_STATUS_OK;
+
+error:
+    OIC_LOG_V(ERROR, TAG, "error : %d", code);
+    coap_add_data(*pdu, strlen(coap_response_phrase(code)),
+                  (unsigned char *) coap_response_phrase(code));
+    return CA_STATUS_FAILED;
+}
+
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, CAInfo_t info, size_t dataLength)
+{
+    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");
+
+    // get set block data from CABlock list-set.
+    coap_block_t *block = CAGetBlockOption((*pdu)->hdr->token);
+    if (NULL == block)
+    {
+        OIC_LOG(ERROR, TAG, "getting has failed");
+        return CA_STATUS_FAILED;
+    }
+
+    CALogBlockInfo(block);
+
+    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type)
+    {
+        OIC_LOG(DEBUG, TAG, "option1 and ACK msg..");
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block, COAP_OPTION_BLOCK1);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList((*pdu)->hdr->token);
+            return res;
+        }
+
+        // reset block-list after write block
+        if (0 == block->m)
+        {
+            // remove data from list
+            CAResult_t res = CARemoveBlockDataFromList((*pdu)->hdr->token);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "remove has failed");
+                return res;
+            }
+        }
+    }
+    else
+    {
+        CAGetMoreBitFromBlock(dataLength, block);
+        CAResult_t res = CAAddBlockOptionImpl(*pdu, block, COAP_OPTION_BLOCK1);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "add has failed");
+            CARemoveBlockDataFromList((*pdu)->hdr->token);
+            return res;
+        }
+        CALogBlockInfo(block);
+
+        // if block number is 0, add size1 option
+        if (0 == block->num)
+        {
+            res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE1, dataLength);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "add has failed");
+                CARemoveBlockDataFromList((*pdu)->hdr->token);
+                return res;
+            }
+        }
+
+        if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+                            block->num, block->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 (block->m)
+            {
+                OIC_LOG(DEBUG, TAG, "NON, send next block..");
+                // update block data
+                block->num++;
+                CAResult_t res = CAProcessNextStep(*pdu, NULL, CA_SENT_PREVIOUS_NON_MSG);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "failed to process next step");
+                    CARemoveBlockDataFromList((*pdu)->hdr->token);
+                    return res;
+                }
+            }
+            else
+            {
+                CARemoveBlockDataFromList((*pdu)->hdr->token);
+            }
+        }
+    }
+
+    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 };
+    coap_option *option = (coap_option *) OICMalloc(sizeof(coap_option));
+    if (NULL == option)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    option->key = sizeType;
+    option->length = coap_encode_var_bytes(value, dataLength);
+
+    if (!coap_add_option(pdu, option->key, option->length, value))
+    {
+        OIC_LOG(ERROR, TAG, "failed to add size option");
+        OICFree(option);
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT-CAAddBlockSizeOption");
+
+    return CA_STATUS_OK;
+}
+
+bool CAIsPayloadLengthInPduWithBlockSizeOption(const 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 != BLOCK_SIZE(receivedBlock->szx) * receivedBlock->num)
+        {
+            if (receivedBlock->num > currData->block.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->block.num)
+        {
+            if (receivedBlock->num > currData->block.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 != 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);
+                    currData->block.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)
+{
+    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 = BLOCK_SIZE(currData->block.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;
+            void *newPayload = realloc(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 = { 0 };
+    responseData.token = (CAToken_t) OICMalloc(pdu->hdr->token_length);
+    if (NULL == responseData.token)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return NULL;
+    }
+    memcpy(responseData.token, pdu->hdr->token, pdu->hdr->token_length);
+    responseData.tokenLength = pdu->hdr->token_length;
+    CAResponseInfo_t* responseInfo = (CAResponseInfo_t*) OICCalloc(1, sizeof(CAResponseInfo_t));
+    if (NULL == responseInfo)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        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;
+    }
+    memcpy(clone, data, sizeof(CAData_t));
+
+    if (data->requestInfo)
+    {
+        clone->requestInfo = CACloneRequestInfo(data->requestInfo);
+    }
+
+    if (data->responseInfo)
+    {
+        clone->responseInfo = CACloneResponseInfo(data->responseInfo);
+    }
+
+    if (data->remoteEndpoint)
+    {
+        clone->remoteEndpoint = CACloneEndpoint(data->remoteEndpoint);
+    }
+
+    if (NULL != data->options && 0 < data->numOptions)
+    {
+        // copy data
+        CAHeaderOption_t *headerOption = (CAHeaderOption_t *) OICMalloc(sizeof(CAHeaderOption_t)
+                                                                        * data->numOptions);
+        if (NULL == headerOption)
+        {
+            OIC_LOG(ERROR, TAG, "Out of memory");
+            CADestroyDataSet(clone);
+            return NULL;
+        }
+        memcpy(headerOption, data->options, sizeof(CAHeaderOption_t) * data->numOptions);
+
+        clone->options = headerOption;
+    }
+
+    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 unsigned char* token, uint8_t blockType)
+{
+    OIC_LOG(DEBUG, TAG, "IN-UpdateBlockOptionType");
+    VERIFY_NON_NULL(token, TAG, "token");
+
+    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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                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 unsigned char* token)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetBlockOptionType");
+    VERIFY_NON_NULL(token, TAG, "token");
+
+    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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                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 unsigned char* token)
+{
+    VERIFY_NON_NULL_RET(token, TAG, "token", 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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                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->token)
+                {
+                    responseInfo->info.tokenLength = currData->tokenLength;
+                    responseInfo->info.token = (char *) OICMalloc(currData->tokenLength);
+                    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->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_FAILED;
+}
+
+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) || (NULL == currData->token))
+        {
+            continue;
+        }
+
+        if (NULL != sendData->requestInfo) // sendData is requestMessage
+        {
+            OIC_LOG(DEBUG, TAG, "Send request");
+            if (NULL != currData->token && NULL != sendData->requestInfo->info.token)
+            {
+                if (!strncmp(currData->token, sendData->requestInfo->info.token,
+                             currData->tokenLength))
+                {
+                    OIC_LOG(ERROR, TAG, "already sent");
+                    continue;
+                }
+            }
+        }
+        else if (NULL != sendData->responseInfo) // sendData is responseMessage
+        {
+            OIC_LOG(DEBUG, TAG, "Send response");
+            if (NULL != currData->token && NULL != sendData->responseInfo->info.token)
+            {
+                if (!strncmp(currData->token, sendData->responseInfo->info.token,
+                             currData->tokenLength))
+                {
+                    // set sendData
+                    if (NULL != currData->sentData)
+                    {
+                        OIC_LOG(DEBUG, TAG, "init block number");
+                        currData->block.num = 0;
+                        CADestroyDataSet(currData->sentData);
+                    }
+                    currData->sentData = CACloneCAData(sendData);
+                    *blockData = currData;
+                    ca_mutex_unlock(g_context.blockDataListMutex);
+                    return CA_STATUS_OK;
+                }
+            }
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "no CAInfo data");
+            continue;
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return CA_STATUS_FAILED;
+}
+
+CABlockData_t *CAGetBlockDataFromBlockDataList(const unsigned char* token)
+{
+    VERIFY_NON_NULL_RET(token, TAG, "token", 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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                ca_mutex_unlock(g_context.blockDataListMutex);
+                return currData;
+            }
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return NULL;
+}
+
+coap_block_t *CAGetBlockOption(const unsigned char* token)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetBlockOption");
+    VERIFY_NON_NULL_RET(token, TAG, "token", 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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                ca_mutex_unlock(g_context.blockDataListMutex);
+                OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+                return &currData->block;
+            }
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+    return NULL;
+}
+
+CAPayload_t CAGetPayloadFromBlockDataList(const unsigned char* token, size_t *fullPayloadLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN-GetFullPayload");
+    VERIFY_NON_NULL_RET(token, TAG, "token", 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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                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-CreateBlockData");
+    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->block.num = 0;
+    data->block.m = 0;
+    data->block.szx = CA_DEFAULT_BLOCK_SIZE;
+    data->type = 0;
+    data->sentData = CACloneCAData(sendData);
+    data->payload = NULL;
+    data->payloadLength = 0;
+    data->receivedPayloadLen = 0;
+
+    if (data->sentData->requestInfo)
+    {
+        // update token info
+        uint8_t tokenLength = data->sentData->requestInfo->info.tokenLength;
+
+        data->tokenLength = tokenLength;
+        data->token = (char *) OICMalloc(tokenLength * sizeof(char));
+        if (!data->token)
+        {
+            OIC_LOG(ERROR, TAG, "memory alloc has failed");
+            OICFree(data);
+            return NULL;
+        }
+        memcpy(data->token, data->sentData->requestInfo->info.token, tokenLength);
+    }
+    else if(data->sentData->responseInfo)
+    {
+        uint8_t tokenLength = data->sentData->responseInfo->info.tokenLength;
+
+        data->tokenLength = tokenLength;
+        data->token = (char *) OICMalloc(tokenLength * sizeof(char));
+        if (!data->token)
+        {
+            OIC_LOG(ERROR, TAG, "memory alloc has failed");
+            OICFree(data);
+            return NULL;
+        }
+        memcpy(data->token, data->sentData->responseInfo->info.token, tokenLength);
+    }
+
+    ca_mutex_lock(g_context.blockDataListMutex);
+
+    CAResult_t res = u_arraylist_add(g_context.dataList, (void *) data);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "add has failed");
+        OICFree(data->token);
+        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 unsigned char* token)
+{
+    OIC_LOG(DEBUG, TAG, "CARemoveBlockData");
+    VERIFY_NON_NULL(token, TAG, "token");
+
+    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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) token, currData->tokenLength))
+            {
+                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);
+                OICFree(currData->token);
+                ca_mutex_unlock(g_context.blockDataListMutex);
+                return CA_STATUS_OK;
+            }
+        }
+    }
+    ca_mutex_unlock(g_context.blockDataListMutex);
+
+    return CA_STATUS_OK;
+}
+
+bool CAIsBlockDataInList(const coap_pdu_t *pdu)
+{
+    OIC_LOG(DEBUG, TAG, "IN-IsBlockDataInList");
+    VERIFY_NON_NULL_RET(pdu, TAG, "pdu", false);
+    VERIFY_NON_NULL_RET(pdu->hdr, TAG, "pdu->hdr", 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 (currData && currData->token)
+        {
+            if (!strncmp(currData->token, (const char *) pdu->hdr->token, currData->tokenLength))
+            {
+                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->options);
+    OICFree(data);
+}
+
+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 0b6e93e..a6f4c4d 100644 (file)
@@ -1,4 +1,4 @@
-/******************************************************************
+/* *****************************************************************
  *
  * Copyright 2014 Samsung Electronics All Rights Reserved.
  *
 #include "cainterfacecontroller.h"
 #include "caretransmission.h"
 
+#ifdef WITH_BWT
+#include "cablockwisetransfer.h"
+#endif
+
 #ifndef  SINGLE_THREAD
 #include "uqueue.h"
 #include "cathreadpool.h" /* for thread pool */
@@ -73,10 +77,34 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint, const void
 #ifdef SINGLE_THREAD
 static void CAProcessReceivedData(CAData_t *data);
 #endif
-static void CADataDestroyer(void *data, uint32_t size);
+static void CADestroyData(void *data, uint32_t size);
 static void CALogPayloadInfo(CAInfo_t *info);
 static bool CADropSecondRequest(const CAEndpoint_t *endpoint, uint16_t messageId);
 
+#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();
@@ -264,9 +292,9 @@ static void CATimeoutCallback(const CAEndpoint_t *endpoint, const void *pdu, uin
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-static void CADataDestroyer(void *data, uint32_t size)
+static void CADestroyData(void *data, uint32_t size)
 {
-    OIC_LOG(DEBUG, TAG, "CADataDestroyer IN");
+    OIC_LOG(DEBUG, TAG, "CADestroyData IN");
     CAData_t *cadata = (CAData_t *) data;
 
     if (NULL == cadata)
@@ -297,7 +325,7 @@ static void CADataDestroyer(void *data, uint32_t size)
 
     OICFree(cadata->options);
     OICFree(cadata);
-    OIC_LOG(DEBUG, TAG, "CADataDestroyer OUT");
+    OIC_LOG(DEBUG, TAG, "CADestroyData OUT");
 }
 
 #ifdef SINGLE_THREAD
@@ -333,7 +361,9 @@ static void CAProcessReceivedData(CAData_t *data)
         g_errorHandler(rep, data->errorInfo);
     }
 
-    CADataDestroyer(data, sizeof(CAData_t));
+#ifdef SINGLE_THREAD
+    CADestroyData(data, sizeof(CAData_t));
+#endif
 
     OIC_LOG(DEBUG, TAG, "CAProcessReceivedData OUT");
 }
@@ -373,12 +403,44 @@ static void CAProcessSendData(const CAData_t *data)
             OIC_LOG(DEBUG, TAG, "requestInfo is available..");
 
             pdu = CAGeneratePDU(data->requestInfo->method, &data->requestInfo->info);
+
+#ifdef WITH_BWT
+            if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+            {
+                // Blockwise transfer
+                CAResult_t res = CAAddBlockOption(&pdu,
+                                                  data->requestInfo->info);
+                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
         }
         else if (NULL != data->responseInfo)
         {
             OIC_LOG(DEBUG, TAG, "responseInfo is available..");
 
             pdu = CAGeneratePDU(data->responseInfo->result, &data->responseInfo->info);
+
+#ifdef WITH_BWT
+            if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+            {
+                // Blockwise transfer
+                CAResult_t res = CAAddBlockOption(&pdu,
+                                                  data->responseInfo->info);
+                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
         }
         else
         {
@@ -427,6 +489,21 @@ static void CAProcessSendData(const CAData_t *data)
             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);
+                    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);
@@ -547,14 +624,17 @@ static void CAReceivedPacketCallback(const CAEndpoint_t *remoteEndpoint, void *d
         // get token from saved data in retransmission list
         if (retransmissionPdu && CA_EMPTY == code)
         {
-            CAInfo_t *info = &cadata->responseInfo->info;
-            CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *)retransmissionPdu,
-                                               info);
-            if (CA_STATUS_OK != res)
+            if (cadata->responseInfo)
             {
-                OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
-                OICFree(info->token);
-                info->tokenLength = 0;
+                CAInfo_t *info = &cadata->responseInfo->info;
+                CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *)retransmissionPdu,
+                                                   info);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
+                    OICFree(info->token);
+                    info->tokenLength = 0;
+                }
             }
         }
         OICFree(retransmissionPdu);
@@ -565,7 +645,25 @@ static void CAReceivedPacketCallback(const CAEndpoint_t *remoteEndpoint, void *d
 #ifdef SINGLE_THREAD
     CAProcessReceivedData(cadata);
 #else
-    CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+#ifdef WITH_BWT
+        if (CA_ADAPTER_GATT_BTLE != remoteEndpoint->adapter)
+        {
+            CAResult_t res = CAReceiveBlockWiseData(pdu, remoteEndpoint, 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
+            {
+                CADestroyData(cadata, sizeof(CAData_t));
+            }
+        }
+        else
+#endif
+        {
+            CAQueueingThreadAddData(&g_receiveThread, cadata, sizeof(CAData_t));
+        }
 #endif
 
     coap_delete_pdu(pdu);
@@ -630,7 +728,7 @@ void CAHandleRequestResponseCallbacks()
         g_errorHandler(td->remoteEndpoint, td->errorInfo);
     }
 
-    CADataDestroyer(msg, sizeof(CAData_t));
+    CADestroyData(msg, sizeof(CAData_t));
     OICFree(item);
 
 #endif /* SINGLE_HANDLE */
@@ -693,7 +791,7 @@ static CAData_t* CAPrepareSendData(const CAEndpoint_t *endpoint, const void *sen
         if(!headerOption)
         {
             OIC_LOG(ERROR, TAG, "memory allocation failed");
-            CADataDestroyer(cadata, sizeof(CAData_t));
+            CADestroyData(cadata, sizeof(CAData_t));
             return NULL;
         }
 
@@ -707,13 +805,12 @@ static CAData_t* CAPrepareSendData(const CAEndpoint_t *endpoint, const void *sen
     if (!ep)
     {
         OIC_LOG(ERROR, TAG, "endpoint clone failed");
-        CADataDestroyer(cadata, sizeof(CAData_t));
+        CADestroyData(cadata, sizeof(CAData_t));
         return NULL;
     }
 
     cadata->remoteEndpoint = ep;
     return cadata;
-
 }
 
 CAResult_t CADetachRequestMessage(const CAEndpoint_t *object, const CARequestInfo_t *request)
@@ -746,9 +843,30 @@ CAResult_t CADetachRequestMessage(const CAEndpoint_t *object, const CARequestInf
 
 #ifdef SINGLE_THREAD
     CAProcessSendData(data);
-    CADataDestroyer(data, sizeof(CAData_t));
+    CADestroyData(data, sizeof(CAData_t));
 #else
-    CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+#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
+        {
+            CADestroyData(data, sizeof(CAData_t));
+        }
+        return res;
+    }
+    else
+#endif
+    {
+        CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+    }
 #endif
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -776,9 +894,30 @@ CAResult_t CADetachResponseMessage(const CAEndpoint_t *object,
 
 #ifdef SINGLE_THREAD
     CAProcessSendData(data);
-    CADataDestroyer(data, sizeof(CAData_t));
+    CADestroyData(data, sizeof(CAData_t));
 #else
-    CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+#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
+        {
+            CADestroyData(data, sizeof(CAData_t));
+        }
+        return res;
+    }
+    else
+#endif
+    {
+        CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+    }
 #endif
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -822,7 +961,7 @@ CAResult_t CAInitializeMessageHandler()
 
     // send thread initialize
     if (CA_STATUS_OK != CAQueueingThreadInitialize(&g_sendThread, g_threadPoolHandle,
-                                                   CASendThreadProcess, CADataDestroyer))
+                                                   CASendThreadProcess, CADestroyData))
     {
         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
         return CA_STATUS_FAILED;
@@ -841,7 +980,7 @@ CAResult_t CAInitializeMessageHandler()
 
     // receive thread initialize
     if (CA_STATUS_OK != CAQueueingThreadInitialize(&g_receiveThread, g_threadPoolHandle,
-                                                   CAReceiveThreadProcess, CADataDestroyer))
+                                                   CAReceiveThreadProcess, CADestroyData))
     {
         OIC_LOG(ERROR, TAG, "Failed to Initialize receive queue thread");
         return CA_STATUS_FAILED;
@@ -862,6 +1001,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);
 
@@ -935,6 +1079,9 @@ void CATerminateMessageHandler()
         g_threadPoolHandle = NULL;
     }
 
+#ifdef WITH_BWT
+    CATerminateBlockWiseTransfer();
+#endif
     CARetransmissionDestroy(&g_retransmissionContext);
     CAQueueingThreadDestroy(&g_sendThread);
     CAQueueingThreadDestroy(&g_receiveThread);
index 18ba048..78cea47 100644 (file)
@@ -187,7 +187,7 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info)
             coap_delete_list(optlist);
             return NULL;
         }
-        pdu = CAGeneratePDUImpl((code_t)code, optlist, info, info->payload, info->payloadSize);
+        pdu = CAGeneratePDUImpl((code_t) code, optlist, info, info->payload, info->payloadSize);
         if (NULL == pdu)
         {
             OIC_LOG(ERROR, TAG, "pdu NULL");
@@ -296,10 +296,12 @@ coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t
         }
     }
 
+#ifndef WITH_BWT
     if (NULL != payload)
     {
         coap_add_data(pdu, payloadSize, (const unsigned char *) payload);
     }
+#endif
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return pdu;
@@ -537,7 +539,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++;
         }
@@ -677,6 +681,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)