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