From: hyuna0213.jo Date: Wed, 22 Jul 2015 02:49:01 +0000 (+0900) Subject: blockwise-transfer rebase into master for merge/review X-Git-Tag: 1.2.0+RC1~1396 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8a309a7c694c898a16437572e3c9c619a9e1e6de;p=platform%2Fupstream%2Fiotivity.git blockwise-transfer rebase into master for merge/review - 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 Signed-off-by: jihwan.seo Signed-off-by: Sandipan Patra Reviewed-on: https://gerrit.iotivity.org/gerrit/1667 Tested-by: jenkins-iotivity Reviewed-by: Erich Keane --- diff --git a/resource/csdk/connectivity/api/cacommon.h b/resource/csdk/connectivity/api/cacommon.h index 00dac16..666bec0 100644 --- a/resource/csdk/connectivity/api/cacommon.h +++ b/resource/csdk/connectivity/api/cacommon.h @@ -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_ diff --git a/resource/csdk/connectivity/build/android/jni/Android.mk b/resource/csdk/connectivity/build/android/jni/Android.mk index c0e68fd..ed86105 100644 --- a/resource/csdk/connectivity/build/android/jni/Android.mk +++ b/resource/csdk/connectivity/build/android/jni/Android.mk @@ -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) - diff --git a/resource/csdk/connectivity/common/src/caremotehandler.c b/resource/csdk/connectivity/common/src/caremotehandler.c index c9b7f5e..decc861 100644 --- a/resource/csdk/connectivity/common/src/caremotehandler.c +++ b/resource/csdk/connectivity/common/src/caremotehandler.c @@ -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 index 0000000..b75b099 --- /dev/null +++ b/resource/csdk/connectivity/inc/cablockwisetransfer.h @@ -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 + +#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_ diff --git a/resource/csdk/connectivity/inc/camessagehandler.h b/resource/csdk/connectivity/inc/camessagehandler.h index 844cb5b..7dd323d 100644 --- a/resource/csdk/connectivity/inc/camessagehandler.h +++ b/resource/csdk/connectivity/inc/camessagehandler.h @@ -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_ */ - diff --git a/resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h b/resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h index f45831a..792ee92 100644 --- a/resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h +++ b/resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h @@ -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 */ diff --git a/resource/csdk/connectivity/samples/tizen/casample.c b/resource/csdk/connectivity/samples/tizen/casample.c index 4afae38..70313c1 100644 --- a/resource/csdk/connectivity/samples/tizen/casample.c +++ b/resource/csdk/connectivity/samples/tizen/casample.c @@ -72,6 +72,11 @@ */ #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; diff --git a/resource/csdk/connectivity/src/SConscript b/resource/csdk/connectivity/src/SConscript index 7b6ba7d..0f64df7 100755 --- a/resource/csdk/connectivity/src/SConscript +++ b/resource/csdk/connectivity/src/SConscript @@ -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 index 0000000..2084709 --- /dev/null +++ b/resource/csdk/connectivity/src/cablockwisetransfer.c @@ -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 +#include +#include + +#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); +} diff --git a/resource/csdk/connectivity/src/camessagehandler.c b/resource/csdk/connectivity/src/camessagehandler.c index 0b6e93e..a6f4c4d 100644 --- a/resource/csdk/connectivity/src/camessagehandler.c +++ b/resource/csdk/connectivity/src/camessagehandler.c @@ -1,4 +1,4 @@ -/****************************************************************** +/* ***************************************************************** * * Copyright 2014 Samsung Electronics All Rights Reserved. * @@ -35,6 +35,10 @@ #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); diff --git a/resource/csdk/connectivity/src/caprotocolmessage.c b/resource/csdk/connectivity/src/caprotocolmessage.c index 18ba048..78cea47 100644 --- a/resource/csdk/connectivity/src/caprotocolmessage.c +++ b/resource/csdk/connectivity/src/caprotocolmessage.c @@ -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)