summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSangkwan Lee <skgood.lee@samsung.com>2015-09-03 11:27:18 +0900
committerYoungjae Shin <yj99.shin@samsung.com>2015-09-07 07:36:51 -0700
commit3544300719b02c32e0fa18ceb57b45732488ff7b (patch)
tree0ca47fa740ce2cebe3377aa12f5ebeff469ef077
parent4058a4feab73b8e59faaa0a2b3fd7fb8d0a520f0 (diff)
downloadiotivity-submit/tizen/20150908.015501.tar.gz
iotivity-submit/tizen/20150908.015501.tar.bz2
iotivity-submit/tizen/20150908.015501.zip
Patch for enabling blockwise and btsubmit/tizen/20150908.015501
1) Enable blockwise 2) Enable BT EDR 3) Fix : Notify bt discovery done sequence 4) Filtering connectivity type when sends multicast message (Now : When multicast message, send the message to all available connectivity) 5) patch Change-id I2ea9fdab45bef800f05ade65296d3c4014037dea from iotivity master branch 6) remove useless header Change-Id: If4aec07ac966ff71bb3699b876a52987b1f585e9 Signed-off-by: Sangkwan Lee <skgood.lee@samsung.com>
-rw-r--r--packaging/iotivity.spec2
-rw-r--r--resource/c_common/SConscript1
-rw-r--r--resource/c_common/platform_features.h44
-rw-r--r--resource/csdk/connectivity/api/cacommon.h22
-rw-r--r--resource/csdk/connectivity/inc/cablockwisetransfer.h557
-rw-r--r--resource/csdk/connectivity/inc/camessagehandler.h24
-rw-r--r--resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h1
-rw-r--r--[-rwxr-xr-x]resource/csdk/connectivity/src/SConscript3
-rw-r--r--resource/csdk/connectivity/src/bt_edr_adapter/tizen/caedrclient.c74
-rw-r--r--resource/csdk/connectivity/src/cablockwisetransfer.c2611
-rw-r--r--resource/csdk/connectivity/src/cainterfacecontroller.c4
-rw-r--r--resource/csdk/connectivity/src/camessagehandler.c168
-rw-r--r--resource/csdk/connectivity/src/caprotocolmessage.c9
-rw-r--r--resource/csdk/stack/include/internal/ocstackinternal.h2
-rw-r--r--resource/csdk/stack/include/ocpayload.h4
-rw-r--r--resource/csdk/stack/src/ocpayload.c160
-rw-r--r--resource/csdk/stack/src/ocpayloadconvert.c582
-rw-r--r--resource/csdk/stack/src/ocpayloadparse.c199
-rw-r--r--resource/csdk/stack/src/ocserverrequest.c7
-rw-r--r--resource/csdk/stack/src/ocstack.c13
20 files changed, 4005 insertions, 482 deletions
diff --git a/packaging/iotivity.spec b/packaging/iotivity.spec
index db615ef3e..38c6732e2 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 f0e140c49..d018d884d 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 000000000..8f39e19e2
--- /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 <stdassert.h>
+ #define OC_STATIC_ASSERT(condition, msg) static_assert(condition, msg)
+#else
+ #define OC_STATIC_ASSERT(condition, msg) ((void)sizeof(char[2*!!(condition) - 1]))
+#endif
+
+#endif
diff --git a/resource/csdk/connectivity/api/cacommon.h b/resource/csdk/connectivity/api/cacommon.h
index 2f18e5688..e42fde2b5 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 000000000..d3f883cb9
--- /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 <stdint.h>
+
+#include "coap.h"
+#include "cathreadpool.h"
+#include "camutex.h"
+#include "uarraylist.h"
+#include "cacommon.h"
+#include "caprotocolmessage.h"
+
+/**
+ * Callback to send block data.
+ * @param[in] data send data.
+ */
+typedef void (*CASendThreadFunc)(CAData_t *data);
+
+/**
+ * Callback to notify received data from the remote endpoint.
+ * @param[in] data received data.
+ */
+typedef void (*CAReceiveThreadFunc)(CAData_t *data);
+
+/**
+ * context of blockwise transfer.
+ */
+typedef struct
+{
+ /** send method for block data. **/
+ CASendThreadFunc sendThreadFunc;
+
+ /** callback function for received message. **/
+ CAReceiveThreadFunc receivedThreadFunc;
+
+ /** array list on which the thread is operating. **/
+ u_arraylist_t *dataList;
+
+ /** data list mutex for synchronization. **/
+ ca_mutex blockDataListMutex;
+
+ /** sender mutex for synchronization. **/
+ ca_mutex blockDataSenderMutex;
+} CABlockWiseContext_t;
+
+/**
+ * ID set of Blockwise transfer data set(::CABlockData_t).
+ */
+typedef struct
+{
+ uint8_t* id; /**< blockData ID for CA. */
+ size_t idLength; /**< length of blockData ID. */
+} CABlockDataID_t;
+
+/**
+ * Block Data Set.
+ */
+typedef struct
+{
+ coap_block_t block1; /**< block1 option. */
+ coap_block_t block2; /**< block2 option. */
+ uint16_t type; /**< block option type. */
+ CABlockDataID_t* blockDataId; /**< ID set of CABlockData. */
+ CAData_t *sentData; /**< sent request or response data information. */
+ CAPayload_t payload; /**< payload buffer. */
+ size_t payloadLength; /**< the total payload length to be received. */
+ size_t receivedPayloadLen; /**< currently received payload length. */
+} CABlockData_t;
+
+/**
+ * state of received block message from remote endpoint.
+ */
+typedef enum
+{
+ CA_BLOCK_UNKNOWN = 0,
+ CA_OPTION1_ACK,
+ CA_OPTION1_NO_ACK_LAST_BLOCK,
+ CA_OPTION1_NO_ACK_BLOCK,
+ CA_OPTION2_FIRST_BLOCK,
+ CA_OPTION2_LAST_BLOCK,
+ CA_OPTION2_ACK,
+ CA_OPTION2_NON,
+ CA_OPTION2_CON,
+ CA_SENT_PREVIOUS_NON_MSG,
+ CA_BLOCK_INCOMPLETE,
+ CA_BLOCK_TOO_LARGE,
+ CA_BLOCK_RECEIVED_ALREADY
+} CABlockState_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Initializes the block-wise transfer context.
+ * @param[in] CASendThreadFunc function point to add data in send queue thread.
+ * @param[in] CAReceiveThreadFunc function point to add data in receive queue thread.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc blockSendMethod,
+ CAReceiveThreadFunc receivedDataCallback);
+
+/**
+ * Terminate the block-wise transfer context.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CATerminateBlockWiseTransfer();
+
+/**
+ * initialize mutex.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAInitBlockWiseMutexVariables();
+
+/**
+ * terminate mutex.
+ */
+void CATerminateBlockWiseMutexVariables();
+
+/**
+ * Pass the bulk data. if block-wise transfer process need,
+ * bulk data will be sent to block messages.
+ * @param[in] data data for sending.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendBlockWiseData(const CAData_t *data);
+
+/**
+ * Add the data to send thread queue.
+ * @param[in] sendData data for sending.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const CABlockDataID_t *blockID);
+
+/**
+ * Check the block option type. If it has to be sent to a block,
+ * block option will be set.
+ * @param[in] currData block data.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CACheckBlockOptionType(CABlockData_t *currData);
+
+/**
+ * Pass the received pdu data. and check if block option is set.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] endpoint information of remote device.
+ * @param[in] receivedData received CAData.
+ * @param[in] dataLen received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, size_t dataLen);
+
+/**
+ * process next step by block-wise state.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] receivedData received CAData.
+ * @param[in] blockWiseStatus block-wise state to move next step.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
+ uint8_t blockWiseStatus, const CABlockDataID_t *blockID);
+
+/**
+ * send block message to remote device.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] msgType the message type of the block.
+ * @param[in] status block-wise state to move next step.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
+ uint8_t status, const CABlockDataID_t *blockID);
+
+/**
+ * send error message to remote device.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] status block-wise state to move next step.
+ * @param[in] responseResult response result code.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
+ CAResponseResult_t responseResult,
+ const CABlockDataID_t *blockID);
+
+/**
+ * receive last block data.
+ * @param[in] blockID ID set of CABlockData.
+ * @param[in] receivedData received CAData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAReceiveLastBlock(const CABlockDataID_t *blockID,
+ const CAData_t *receivedData);
+
+/**
+ * set next block option 1.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] endpoint information of remote device.
+ * @param[in] receivedData received CAData.
+ * @param[in] block block option data.
+ * @param[in] dataLen received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, coap_block_t block,
+ size_t dataLen);
+
+/**
+ * set next block option 2.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] endpoint information of remote device.
+ * @param[in] receivedData received CAData.
+ * @param[in] block block option data.
+ * @param[in] dataLen received data length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, coap_block_t block,
+ size_t dataLen);
+
+/**
+ * Update the block option in block-wise transfer list.
+ * @param[in] currData stored block data information.
+ * @param[in] block block option to update.
+ * @param[in] msgType message type of pdu.
+ * @param[in] blockType block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
+ CAMessageType_t msgType, uint16_t blockType);
+
+/**
+ * Update the block option in block-wise transfer list.
+ * @param[in] currData stored block data information.
+ * @param[in] block block option of current message.
+ * @param[in] blockType block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block,
+ uint16_t blockType);
+
+/**
+ * Update the messageId in block-wise transfer list.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID);
+
+/**
+ * Update the block option items.
+ * @param[in] currData stored block data information.
+ * @param[in] pdu received pdu binary data.
+ * @param[in/out] block block option of current message.
+ * @param[in] blockType block option type.
+ * @param[in] status current flow status for block-wise transfer.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *pdu,
+ coap_block_t *block, uint16_t blockType,
+ uint32_t status);
+/**
+ * Set the M-bit of block option.
+ * @param[in] payloadLen payload length of current bulk data.
+ * @param[out] block block option.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetMoreBitFromBlock(size_t payloadLen, coap_block_t *block);
+
+/**
+ * check the block option what kind of option have to set.
+ * @param[out] pdu pdu object.
+ * @param[in] info information of the request/response.
+ * @param[in] endpoint port of transport.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
+ const CAEndpoint_t *endpoint);
+
+/**
+ * Write the block option2 in pdu binary data.
+ * @param[out] pdu pdu object.
+ * @param[in] info information of the request/response.
+ * @param[in] dataLength length of payload.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+ const CABlockDataID_t *blockID);
+
+/**
+ * Write the block option1 in pdu binary data.
+ * @param[out] pdu pdu object.
+ * @param[in] info information of the request/response.
+ * @param[in] dataLength length of payload.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+ const CABlockDataID_t *blockID);
+
+/**
+ * Add the block option in pdu data.
+ * @param[in] pdu pdu object.
+ * @param[out] block block data.
+ * @param[in] blockType block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockOptionImpl(coap_pdu_t *pdu, coap_block_t *block, uint8_t blockType);
+
+/**
+ * Add the size option in pdu data.
+ * @param[in/out] pdu pdu object.
+ * @param[in] sizeType size option type.
+ * @param[in] dataLength the total payload length to be sent.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataLength);
+
+/**
+ * Get the size option from pdu data.
+ * @param[in] pdu pdu object.
+ * @param[in] sizeType size option type.
+ * @param[out] totalPayloadLen the total payload length to be received.
+ * @return true or false.
+ */
+bool CAIsPayloadLengthInPduWithBlockSizeOption(coap_pdu_t *pdu,
+ uint16_t sizeType,
+ size_t *totalPayloadLen);
+
+/**
+ * update the total payload with the received payload.
+ * @param[in] currData stored block data information.
+ * @param[in] receivedData received CAData.
+ * @param[in] status block-wise state.
+ * @param[in] isSizeOption size option.
+ * @param[in] blockType block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdatePayloadData(CABlockData_t *currData, const CAData_t *receivedData,
+ uint8_t status, bool isSizeOption, uint16_t blockType);
+
+/**
+ * Generate CAData structure from the given information.
+ * @param[in] pdu pdu object.
+ * @param[in] endpoint information of remote device.
+ * @return generated CAData.
+ */
+CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint);
+
+/**
+ * Update the block option items.
+ * @param[in/out] blockblock option of current message.
+ * @param[in] blockType block option type.
+ * @param[in] responseResult result code of pdu.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAHandleBlockErrorResponse(coap_block_t *block, uint16_t blockType,
+ uint32_t responseResult);
+
+/**
+ * Check the received payload and if an error happens, return error type.
+ * @param[in/out] currData stored block data information.
+ * @param[in] receivedBlock received block option.
+ * @param[in] receivedData message type of pdu.
+ * @param[in] blockType block option type.
+ * @param[in] dataLen received data length.
+ * @return block state.
+ */
+uint8_t CACheckBlockErrorType(CABlockData_t *currData, coap_block_t *receivedBlock,
+ const CAData_t *receivedData, uint16_t blockType,
+ size_t dataLen);
+
+/**
+ * Destroys the given CAData.
+ * @param[in] data CAData to destroy.
+ * @return generated CAData.
+ */
+void CADestroyDataSet(CAData_t* data);
+
+/**
+ * Create the blockId for CABlockData.
+ * @param[in] token token of current message.
+ * @param[in] tokenLength token length of current message.
+ * @param[in] portNumber port.
+ * @return ID set of CABlockData.
+ */
+CABlockDataID_t* CACreateBlockDatablockId(const CAToken_t token, uint8_t tokenLength,
+ uint16_t portNumber);
+
+/**
+ * Destroy the blockId set.
+ * @param[in] blockID ID set of CABlockData.
+ */
+void CADestroyBlockID(CABlockDataID_t *blockID);
+
+/**
+ * check whether Block ID is matched or not.
+ * @param[in] currData block data.
+ * @param[in] blockID ID set of CABlockData.
+ * @return true or false.
+ */
+bool CABlockidMatches(const CABlockData_t *currData, const CABlockDataID_t *blockID);
+/**
+ * Print the given block option information.
+ * @param[in] block block option information.
+ */
+void CALogBlockInfo(coap_block_t *block);
+
+/**
+ * Create new CAData structure from the input information.
+ * @param[in] data CAData information that needs to be duplicated.
+ * @return created CAData structure.
+ */
+CAData_t *CACloneCAData(const CAData_t *data);
+
+/**
+ * Update payload from the input information.
+ * @param[in] data CAData information that needs to be updated.
+ * @param[in] payload received new payload from the remote endpoint.
+ * @param[in] payloadLen received full payload length.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdatePayloadToCAData(CAData_t *data, const CAPayload_t payload,
+ size_t payloadLen);
+
+/**
+ * Get payload and payload length from the input information.
+ * @param[in] data CAData information.
+ * @param[out] payloadLen The payload length is stored.
+ * @return payload.
+ */
+CAPayload_t CAGetPayloadInfo(const CAData_t *data, size_t *payloadLen);
+
+/**
+ * Set the block option type.
+ * @param[in] blockID ID set of CABlockData.
+ * @param[in] blockType block option type.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAUpdateBlockOptionType(const CABlockDataID_t *blockID,
+ uint8_t blockType);
+
+/**
+ * Get the block option type from block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @return block option type.
+ */
+uint8_t CAGetBlockOptionType(const CABlockDataID_t *blockID);
+
+/**
+ * Get the block data from block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @return CAData structure.
+ */
+CAData_t *CAGetDataSetFromBlockDataList(const CABlockDataID_t *blockID);
+
+/**
+ * Get token from block-wise transfer list.
+ * @param[in] pdu received pdu binary data.
+ * @param[in] endpoint remote endpoint information.
+ * @param[in] responseInfo received response information.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ CAResponseInfo_t *responseInfo);
+
+/**
+ * check whether the block data is valid or not.
+ * @param[in] sendData CAData information.
+ * @param[out] blockData block data when it is valid.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **blockData);
+
+/**
+ * Get the block data from block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @return CABlockData_t structure.
+ */
+CABlockData_t *CAGetBlockDataFromBlockDataList(const CABlockDataID_t *blockID);
+
+/**
+ * Get the block option from block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @param[in] blockType block option type.
+ * @return coap_block_t structure.
+ */
+coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID,
+ uint16_t blockType);
+
+/**
+ * Get the full payload from block-wise list.
+ * @param[in] blockID ID set of CABlockData.
+ * @param[out] fullPayloadLen received full payload length.
+ * @return payload.
+ */
+CAPayload_t CAGetPayloadFromBlockDataList(const CABlockDataID_t *blockID,
+ size_t *fullPayloadLen);
+
+/**
+ * Create the block data from given data and add the data in block-wise transfer list.
+ * @param[in] sendData data to be added to a list.
+ * @return created CABlockData_t structure.
+ * and NULL point will be returned if there is error case..
+ */
+CABlockData_t *CACreateNewBlockData(const CAData_t *sendData);
+
+/**
+ * Remove the block data in block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @return ::CASTATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID);
+
+/**
+ * Check if data exist in block-wise transfer list.
+ * @param[in] blockID ID set of CABlockData.
+ * @return true or false.
+ */
+bool CAIsBlockDataInList(const CABlockDataID_t *blockID);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // CA_BLOCKWISETRANSFER_H_
diff --git a/resource/csdk/connectivity/inc/camessagehandler.h b/resource/csdk/connectivity/inc/camessagehandler.h
index 9e587352e..986738f42 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 f45831a78..792ee924b 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
index 7a912740f..33da62910 100755..100644
--- 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 5c7ae3022..1ad29808e 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 000000000..54dda9be8
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "caadapterutils.h"
+#include "cainterface.h"
+#include "camessagehandler.h"
+#include "caremotehandler.h"
+#include "cablockwisetransfer.h"
+#include "oic_malloc.h"
+#include "camutex.h"
+#include "logger.h"
+
+#define TAG "CA_BWT"
+
+#define BLOCKWISE_OPTION_BUFFER (sizeof(unsigned int))
+#define BLOCK_NUMBER_IDX 4
+#define BLOCK_M_BIT_IDX 3
+#define PORT_LENGTH 2
+
+#define BLOCK_SIZE(arg) (1 << ((arg) + 4))
+
+// context for block-wise transfer
+static CABlockWiseContext_t g_context = { 0 };
+
+CAResult_t CAInitializeBlockWiseTransfer(CASendThreadFunc sendThreadFunc,
+ CAReceiveThreadFunc receivedThreadFunc)
+{
+ OIC_LOG(DEBUG, TAG, "initialize");
+
+ // set block-wise transfer context
+ if (!g_context.sendThreadFunc)
+ {
+ g_context.sendThreadFunc = sendThreadFunc;
+ }
+
+ if (!g_context.receivedThreadFunc)
+ {
+ g_context.receivedThreadFunc = receivedThreadFunc;
+ }
+
+ if (!g_context.dataList)
+ {
+ g_context.dataList = u_arraylist_create();
+ }
+
+ CAResult_t res = CAInitBlockWiseMutexVariables();
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "init has failed");
+ }
+
+ return res;
+}
+
+CAResult_t CATerminateBlockWiseTransfer()
+{
+ OIC_LOG(DEBUG, TAG, "terminate");
+
+ if (g_context.dataList)
+ {
+ u_arraylist_free(&g_context.dataList);
+ }
+
+ CATerminateBlockWiseMutexVariables();
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAInitBlockWiseMutexVariables()
+{
+ OIC_LOG(DEBUG, TAG, "IN");
+
+ if (NULL == g_context.blockDataListMutex)
+ {
+ g_context.blockDataListMutex = ca_mutex_new();
+ if (NULL == g_context.blockDataListMutex)
+ {
+ OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ if (NULL == g_context.blockDataSenderMutex)
+ {
+ g_context.blockDataSenderMutex = ca_mutex_new();
+ if (NULL == g_context.blockDataSenderMutex)
+ {
+ OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+ CATerminateBlockWiseMutexVariables();
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ return CA_STATUS_OK;
+}
+
+void CATerminateBlockWiseMutexVariables()
+{
+ OIC_LOG(DEBUG, TAG, "IN");
+
+ if (g_context.blockDataListMutex)
+ {
+ ca_mutex_free(g_context.blockDataListMutex);
+ g_context.blockDataListMutex = NULL;
+ }
+
+ if (g_context.blockDataSenderMutex)
+ {
+ ca_mutex_free(g_context.blockDataSenderMutex);
+ g_context.blockDataSenderMutex = NULL;
+ }
+}
+
+CAResult_t CASendBlockWiseData(const CAData_t *sendData)
+{
+ VERIFY_NON_NULL(sendData, TAG, "sendData");
+
+ // check if message type is CA_MSG_RESET
+ if (NULL != sendData->responseInfo)
+ {
+ if (CA_MSG_RESET == sendData->responseInfo->info.type)
+ {
+ OIC_LOG(DEBUG, TAG, "reset message can't be sent to the block");
+ return CA_NOT_SUPPORTED;
+ }
+ }
+
+ // #1. check if it is already included in block data list
+ CABlockData_t *currData = NULL;
+ CAResult_t res = CACheckBlockDataValidation(sendData, &currData);
+ if (CA_STATUS_OK != res)
+ {
+ // #2. if it is not included, add the data into list
+ if (NULL == currData)
+ {
+ OIC_LOG(DEBUG, TAG, "There is no block data");
+ currData = CACreateNewBlockData(sendData);
+ if (NULL == currData)
+ {
+ OIC_LOG(ERROR, TAG, "failed to create block data");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+ }
+ }
+
+ // #3. check request/response block option type and payload length
+ res = CACheckBlockOptionType(currData);
+ if (CA_STATUS_OK == res)
+ {
+ // #4. send block message
+ OIC_LOG(DEBUG, TAG, "send first block msg");
+ res = CAAddSendThreadQueue(currData->sentData, (const CABlockDataID_t *)&currData->blockDataId);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ return res;
+ }
+ }
+
+ return res;
+}
+
+CAResult_t CAAddSendThreadQueue(const CAData_t *sendData, const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL(sendData, TAG, "sendData");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ CAData_t *cloneData = CACloneCAData(sendData);
+ if (NULL == cloneData)
+ {
+ OIC_LOG(ERROR, TAG, "clone has failed");
+ CARemoveBlockDataFromList(blockID);
+ return CA_STATUS_FAILED;
+ }
+
+ if (g_context.sendThreadFunc)
+ {
+ ca_mutex_lock(g_context.blockDataSenderMutex);
+ g_context.sendThreadFunc(cloneData);
+ ca_mutex_unlock(g_context.blockDataSenderMutex);
+ }
+ else
+ {
+ CADestroyDataSet(cloneData);
+ }
+ return CA_STATUS_OK;
+}
+
+CAResult_t CACheckBlockOptionType(CABlockData_t *currData)
+{
+ VERIFY_NON_NULL(currData, TAG, "currData");
+ VERIFY_NON_NULL(currData->sentData, TAG, "currData->sentData");
+
+ size_t payloadLen = 0;
+ CAGetPayloadInfo(currData->sentData, &payloadLen);
+
+ // check if message has to be transfered to a block
+ size_t maxBlockSize = BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE);
+ if (payloadLen <= maxBlockSize)
+ {
+ OIC_LOG_V(DEBUG, TAG, "payloadLen=%d, maxBlockSize=%d", payloadLen, maxBlockSize);
+ return CA_NOT_SUPPORTED;
+ }
+
+ // set block option (COAP_OPTION_BLOCK2 or COAP_OPTION_BLOCK1)
+ if (NULL != currData->sentData->requestInfo) // request message
+ {
+ currData->type = COAP_OPTION_BLOCK1;
+ }
+ else // response message
+ {
+ currData->type = COAP_OPTION_BLOCK2;
+ }
+
+ return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, size_t dataLen)
+{
+ OIC_LOG(DEBUG, TAG, "CAReceiveBlockWiseData");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+ // check if received message type is CA_MSG_RESET
+ if (CA_EMPTY == pdu->hdr->code)
+ {
+ OIC_LOG(DEBUG, TAG, "code is CA_EMPTY..");
+
+ // get token from block-wise transfer list when CA_EMPTY(RST/ACK) is received
+ CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint, receivedData->responseInfo);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "fail to get token");
+ return res;
+ }
+
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ receivedData->responseInfo->info.token,
+ receivedData->responseInfo->info.tokenLength,
+ endpoint->port);
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return CA_NOT_SUPPORTED;
+ }
+
+ // check if block option is set and get block data
+ coap_block_t block = {0, 0, 0};
+
+ // get block1 option
+ int isBlock1 = coap_get_block(pdu, COAP_OPTION_BLOCK1, &block);
+ if (isBlock1)
+ {
+ CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, block, dataLen);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ return res;
+ }
+ }
+
+ // get block2 option
+ int isBlock2 = coap_get_block(pdu, COAP_OPTION_BLOCK2, &block);
+ if (isBlock2)
+ {
+ CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, block, dataLen);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ return res;
+ }
+ }
+
+ // check if there is error code
+ if (!isBlock1 && !isBlock2)
+ {
+ uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+ if (CA_REQUEST_ENTITY_INCOMPLETE == code)
+ {
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)pdu->hdr->token,
+ pdu->hdr->token_length,
+ endpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "getting has failed");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ if (COAP_OPTION_BLOCK2 == data->type)
+ {
+ coap_block_t *block2 = CAGetBlockOption(blockDataID,
+ COAP_OPTION_BLOCK2);
+ if (NULL == block2)
+ {
+ OIC_LOG(ERROR, TAG, "block is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CAResult_t res = CASetNextBlockOption2(pdu, endpoint, receivedData, *block2,
+ dataLen);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ else if (COAP_OPTION_BLOCK1 == data->type)
+ {
+ coap_block_t *block1 = CAGetBlockOption(blockDataID,
+ COAP_OPTION_BLOCK1);
+ if (NULL == block1)
+ {
+ OIC_LOG(ERROR, TAG, "block is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CAResult_t res = CASetNextBlockOption1(pdu, endpoint, receivedData, *block1,
+ dataLen);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ }
+ else
+ {
+ // normal pdu data
+ OIC_LOG(DEBUG, TAG, "it's normal pdu");
+
+ // if received data is response message
+ // and sent data remain in block data list, remove block data
+ if (receivedData->responseInfo)
+ {
+ CAResult_t res = CAGetTokenFromBlockDataList(pdu, endpoint,
+ receivedData->responseInfo);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "fail to get token");
+ return res;
+ }
+ }
+ return CA_NOT_SUPPORTED;
+ }
+ }
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData,
+ uint8_t blockWiseStatus, const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ CAResult_t res = CA_STATUS_OK;
+ CAData_t *data = NULL;
+
+ // process blockWiseStatus
+ switch (blockWiseStatus)
+ {
+ case CA_OPTION2_FIRST_BLOCK:
+ res = CAAddSendThreadQueue(receivedData, blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ return res;
+ }
+ break;
+
+ case CA_OPTION2_CON:
+ // add data to send thread
+ data = CAGetDataSetFromBlockDataList(blockID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "it's unavailable");
+ return CA_STATUS_FAILED;
+ }
+
+ if (data->requestInfo)
+ {
+ data->requestInfo->info.messageId = pdu->hdr->id;
+ }
+
+ if (data->responseInfo)
+ {
+ data->responseInfo->info.messageId = pdu->hdr->id;
+ }
+
+ res = CAAddSendThreadQueue(data, blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ return res;
+ }
+
+ break;
+
+ case CA_OPTION1_ACK:
+ case CA_OPTION2_ACK:
+ case CA_SENT_PREVIOUS_NON_MSG:
+ res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "send has failed");
+ return res;
+ }
+ break;
+
+ case CA_OPTION2_LAST_BLOCK:
+ // process last block and send upper layer
+ res = CAReceiveLastBlock(blockID, receivedData);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "receive has failed");
+ return res;
+ }
+
+ // remove data from list
+ res = CARemoveBlockDataFromList(blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "remove has failed");
+ return res;
+ }
+ break;
+
+ case CA_OPTION1_NO_ACK_LAST_BLOCK:
+ // process last block and send upper layer
+ res = CAReceiveLastBlock(blockID, receivedData);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "receive has failed");
+ return res;
+ }
+
+ if (CA_MSG_NONCONFIRM == pdu->hdr->type)
+ {
+ // remove data from list
+ res = CARemoveBlockDataFromList(blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "remove has failed");
+ return res;
+ }
+ }
+ break;
+
+ case CA_OPTION1_NO_ACK_BLOCK:
+ if (CA_MSG_CONFIRM == pdu->hdr->type)
+ {
+ // add data to send thread
+ res = CASendBlockMessage(pdu, CA_MSG_ACKNOWLEDGE, blockWiseStatus,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "send has failed");
+ return res;
+ }
+ }
+ break;
+
+ case CA_BLOCK_INCOMPLETE:
+ if (CA_MSG_CONFIRM == pdu->hdr->type || CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+ {
+ // add data to send thread
+ res = CASendErrorMessage(pdu, blockWiseStatus,
+ CA_REQUEST_ENTITY_INCOMPLETE,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "send has failed");
+ return res;
+ }
+ }
+ break;
+
+ case CA_BLOCK_TOO_LARGE:
+ if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+ {
+ res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "send has failed");
+ return res;
+ }
+ }
+ else if (CA_MSG_CONFIRM == pdu->hdr->type)
+ {
+ res = CASendErrorMessage(pdu, blockWiseStatus,
+ CA_REQUEST_ENTITY_TOO_LARGE,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "send has failed");
+ return res;
+ }
+ }
+ break;
+ default:
+ OIC_LOG_V(ERROR, TAG, "no logic [%d]", blockWiseStatus);
+ }
+ return CA_STATUS_OK;
+}
+
+CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
+ uint8_t status, const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ CAData_t *data = CAGetDataSetFromBlockDataList(blockID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "CAData is unavailable");
+ return CA_STATUS_FAILED;
+ }
+
+ if (CA_MSG_CONFIRM == msgType)
+ {
+ OIC_LOG(DEBUG, TAG, "need new msgID");
+ if (data->requestInfo)
+ {
+ data->requestInfo->info.messageId = 0;
+ }
+
+ if (data->responseInfo)
+ {
+ data->responseInfo->info.messageId = 0;
+ }
+ }
+ else if (CA_MSG_ACKNOWLEDGE == msgType)
+ {
+ if (data->responseInfo)
+ {
+ OIC_LOG(DEBUG, TAG, "set ACK message");
+ data->responseInfo->info.messageId = pdu->hdr->id;
+ data->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
+ if (CA_OPTION1_NO_ACK_LAST_BLOCK == status)
+ {
+ data->responseInfo->result = CA_CHANGED;
+ }
+ else if (CA_OPTION1_NO_ACK_BLOCK == status)
+ {
+ data->responseInfo->result = CA_CONTINUE;
+ }
+ }
+ }
+
+ // add data to send thread
+ CAResult_t res = CAAddSendThreadQueue(data, blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ }
+
+ return res;
+}
+
+CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
+ CAResponseResult_t responseResult,
+ const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ // create error responseInfo
+ CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "data is unavailable");
+ return CA_STATUS_FAILED;
+ }
+
+ CAData_t *cloneData = NULL;
+ if (data->sentData && data->sentData->responseInfo)
+ {
+ data->sentData->responseInfo->info.messageId = pdu->hdr->id;
+ data->sentData->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
+ data->sentData->responseInfo->result = responseResult;
+ cloneData = CACloneCAData(data->sentData);
+ if (NULL == cloneData)
+ {
+ OIC_LOG(ERROR, TAG, "clone has failed");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+ OIC_LOG(DEBUG, TAG, "set ACK message");
+ }
+ else if (data->sentData)
+ {
+ cloneData = CACreateNewDataSet(pdu, data->sentData->remoteEndpoint);
+
+ if(!cloneData)
+ {
+ OIC_LOG(ERROR, TAG, PCF("CACreateNewDataSet failed"));
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ cloneData->responseInfo->info.type = CA_MSG_CONFIRM;
+ cloneData->responseInfo->result = responseResult;
+ OIC_LOG(DEBUG, TAG, "set CON message");
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "data has no sent-data");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ // add data to send thread
+ if (g_context.sendThreadFunc)
+ {
+ ca_mutex_lock(g_context.blockDataSenderMutex);
+ g_context.sendThreadFunc(cloneData);
+ ca_mutex_unlock(g_context.blockDataSenderMutex);
+ }
+ else
+ {
+ CADestroyDataSet(cloneData);
+ }
+
+ // if error code is 4.08, remove the stored payload and initialize block number
+ if (CA_BLOCK_INCOMPLETE == status)
+ {
+ OICFree(data->payload);
+ data->payload = NULL;
+ data->payloadLength = 0;
+ data->receivedPayloadLen = 0;
+ data->block1.num = 0;
+ data->block2.num = 0;
+ }
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAReceiveLastBlock(const CABlockDataID_t *blockID,
+ const CAData_t *receivedData)
+{
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+ // total block data have to notify to Application
+ CAData_t *cloneData = CACloneCAData(receivedData);
+ if (NULL == cloneData)
+ {
+ OIC_LOG(ERROR, TAG, "clone has failed");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ // update payload
+ size_t fullPayloadLen = 0;
+ CAPayload_t fullPayload = CAGetPayloadFromBlockDataList(blockID,
+ &fullPayloadLen);
+ if (NULL != fullPayload)
+ {
+ CAResult_t res = CAUpdatePayloadToCAData(cloneData, fullPayload, fullPayloadLen);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CADestroyDataSet(cloneData);
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ if (g_context.receivedThreadFunc)
+ {
+ g_context.receivedThreadFunc(cloneData);
+ }
+ else
+ {
+ CADestroyDataSet(cloneData);
+ }
+
+ return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, coap_block_t block,
+ size_t dataLen)
+{
+ OIC_LOG(INFO, TAG, "CASetNextBlockOption1");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+ OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
+
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)pdu->hdr->token,
+ pdu->hdr->token_length,
+ endpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ // BlockData data is created if it not existed
+ if (!CAIsBlockDataInList(blockDataID))
+ {
+ OIC_LOG(DEBUG, TAG, "no message in list");
+
+ CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "data is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CABlockData_t *currData = CACreateNewBlockData(data);
+ if (NULL == currData)
+ {
+ OIC_LOG(ERROR, TAG, "currData is null");
+ CADestroyDataSet(data);
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ // update BLOCK OPTION1 type
+ CAResult_t res = CAUpdateBlockOptionType(blockDataID,
+ COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "getting has failed");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
+ // received type from remote device
+ if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+ {
+ uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+ if (0 == block.m &&
+ (CA_REQUEST_ENTITY_INCOMPLETE != code && CA_REQUEST_ENTITY_TOO_LARGE != code))
+ {
+ OIC_LOG(INFO, TAG, "Data has sent");
+ // initialize block number for response message
+ data->block1.num = 0;
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_OK;
+ }
+
+ blockWiseStatus = CA_OPTION1_ACK;
+ res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ else // CON or NON message
+ {
+ OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
+
+ // check the size option
+ bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
+ COAP_OPTION_SIZE1,
+ &(data->payloadLength));
+
+ // check if received payload is exact
+ if (CA_MSG_CONFIRM == pdu->hdr->type)
+ {
+ blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
+ COAP_OPTION_BLOCK1, dataLen);
+ }
+
+ if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
+ {
+ // store the received payload and merge
+ res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
+ isSizeOption, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK1, blockWiseStatus);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ // update block data
+ res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+
+ // check the blcok-wise transfer status for next step
+ if (CA_BLOCK_UNKNOWN == blockWiseStatus || CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
+ {
+ if (0 == block.m) // Last block is received
+ {
+ OIC_LOG(DEBUG, TAG, "M bit is 0");
+ blockWiseStatus = CA_OPTION1_NO_ACK_LAST_BLOCK;
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "M bit is 1");
+ blockWiseStatus = CA_OPTION1_NO_ACK_BLOCK;
+ }
+ }
+ }
+
+ res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ }
+
+ CADestroyBlockID(blockDataID);
+ return res;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ const CAData_t *receivedData, coap_block_t block,
+ size_t dataLen)
+{
+ OIC_LOG(DEBUG, TAG, "CASetNextBlockOption2");
+ OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
+
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(pdu->hdr, TAG, "pdu->hdr");
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)pdu->hdr->token,
+ pdu->hdr->token_length,
+ endpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ // BlockData data is created if it not existed
+ if (!CAIsBlockDataInList(blockDataID))
+ {
+ OIC_LOG(DEBUG, TAG, "no msg in list.");
+
+ CAData_t *data = CACreateNewDataSet(pdu, endpoint);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "data is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ CABlockData_t *currData = CACreateNewBlockData(data);
+ if (NULL == currData)
+ {
+ OIC_LOG(ERROR, TAG, "data is null");
+ CADestroyDataSet(data);
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ // set Block Option Type
+ CAResult_t res = CAUpdateBlockOptionType(blockDataID,
+ COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ CABlockData_t *data = CAGetBlockDataFromBlockDataList(blockDataID);
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "getting has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
+ if (0 == block.num && CA_GET == pdu->hdr->code && 0 == block.m)
+ {
+ OIC_LOG(INFO, TAG, "first block number");
+
+ res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ // first block data have to notify to Application
+ res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ blockWiseStatus = CA_OPTION2_FIRST_BLOCK;
+ }
+ else
+ {
+ // received type from remote device
+ if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type ||
+ (CA_MSG_NONCONFIRM == pdu->hdr->type && NULL != receivedData->responseInfo))
+ {
+ OIC_LOG(DEBUG, TAG, "received ACK or NON");
+
+ // check the size option
+ bool isSizeOption = CAIsPayloadLengthInPduWithBlockSizeOption(pdu,
+ COAP_OPTION_SIZE2,
+ &(data->payloadLength));
+
+ // check if received payload is exact
+ if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+ {
+ blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
+ COAP_OPTION_BLOCK2, dataLen);
+ }
+
+ if (CA_BLOCK_RECEIVED_ALREADY != blockWiseStatus)
+ {
+ // store the received payload and merge
+ res = CAUpdatePayloadData(data, receivedData, blockWiseStatus,
+ isSizeOption, COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+
+ if (0 == block.m && CA_BLOCK_UNKNOWN == blockWiseStatus) // Last block is received
+ {
+ OIC_LOG(DEBUG, TAG, "M bit is 0");
+ blockWiseStatus = CA_OPTION2_LAST_BLOCK;
+ }
+ else
+ {
+ if (CA_BLOCK_UNKNOWN == blockWiseStatus ||
+ CA_BLOCK_RECEIVED_ALREADY == blockWiseStatus)
+ {
+ OIC_LOG(DEBUG, TAG, "M bit is 1");
+
+ if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+ {
+ blockWiseStatus = CA_OPTION2_ACK;
+ }
+ else
+ {
+ blockWiseStatus = CA_OPTION2_NON;
+ }
+ }
+
+ res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2,
+ blockWiseStatus);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ }
+ else // CON message and so on.
+ {
+ OIC_LOG_V(INFO, TAG, "num:%d, M:%d", block.num, block.m);
+
+ blockWiseStatus = CA_OPTION2_CON;
+
+ res = CAUpdateBlockOptionItems(data, pdu, &block, COAP_OPTION_BLOCK2, blockWiseStatus);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ res = CAUpdateBlockData(data, block, COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "update has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ }
+
+ res = CAProcessNextStep(pdu, receivedData, blockWiseStatus, blockDataID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "setting has failed");
+ CARemoveBlockDataFromList(blockDataID);
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *pdu,
+ coap_block_t *block, uint16_t blockType,
+ uint32_t status)
+{
+ VERIFY_NON_NULL(currData, TAG, "currData");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(block, TAG, "block");
+
+ // update block data
+ CAResult_t res = CA_STATUS_OK;
+ uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+
+ if (CA_REQUEST_ENTITY_INCOMPLETE == code || CA_REQUEST_ENTITY_TOO_LARGE == code)
+ {
+ // response error code of the received block message
+ res = CAHandleBlockErrorResponse(block, blockType, code);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "error handle has failed");
+ return res;
+ }
+ }
+ else
+ {
+ // update block option items
+ switch (status)
+ {
+ case CA_OPTION1_ACK:
+ if (currData->block1.num > block->num)
+ {
+ OIC_LOG(ERROR, TAG, "received incorrect block num");
+ return CA_STATUS_FAILED;
+ }
+ block->num++;
+ break;
+ case CA_OPTION2_NON:
+ block->num++;
+ block->m = 0;
+ break;
+ case CA_OPTION2_CON:
+ block->m = 0;
+ break;
+ case CA_OPTION2_ACK:
+ if (currData->block2.num > block->num)
+ {
+ OIC_LOG(ERROR, TAG, "received incorrect block num");
+ return CA_STATUS_FAILED;
+ }
+ block->num++;
+ block->m = 0;
+ break;
+ case CA_BLOCK_TOO_LARGE:
+ // if state of received block message is CA_BLOCK_TOO_LARGE or CA_BLOCK_INCOMPLETE
+ // we set the response error code appropriately and send
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ block->num++;
+ block->m = 0;
+ block->szx = currData->block2.szx;
+ }
+ else
+ {
+ block->szx = currData->block1.szx;
+ }
+ break;
+ default:
+ OIC_LOG_V(ERROR, TAG, "no logic [%d]", status);
+ }
+
+ if (CA_BLOCK_INCOMPLETE != status && CA_BLOCK_TOO_LARGE != status)
+ {
+ // negotiate block size
+ res = CANegotiateBlockSize(currData, block, pdu->hdr->type, blockType);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "negotiation has failed");
+ return res;
+ }
+ }
+ }
+ return res;
+}
+
+CAResult_t CAGetMoreBitFromBlock(size_t payloadLen, coap_block_t *block)
+{
+ VERIFY_NON_NULL(block, TAG, "block");
+
+ if ((size_t)((block->num + 1) << (block->szx + BLOCK_NUMBER_IDX))
+ < payloadLen)
+ {
+ OIC_LOG(DEBUG, TAG, "Set the M-bit(1)");
+ block->m = 1;
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "Set the M-bit(0)");
+ block->m = 0;
+ }
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CANegotiateBlockSize(CABlockData_t *currData, coap_block_t *block,
+ CAMessageType_t msgType, uint16_t blockType)
+{
+ OIC_LOG(DEBUG, TAG, "IN-NegotiateBlockSize");
+
+ VERIFY_NON_NULL(currData, TAG, "currData");
+ VERIFY_NON_NULL(block, TAG, "block");
+
+ // #1. check the block option type
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ // #2. check the message type
+ if (CA_MSG_ACKNOWLEDGE == msgType)
+ {
+ if (block->szx > currData->block2.szx)
+ {
+ OIC_LOG(DEBUG, TAG, "sze is big");
+
+ // #3. calculate new block number from block size
+ unsigned int blockNum = BLOCK_SIZE(block->szx) /
+ BLOCK_SIZE(currData->block2.szx) - 1;
+ OIC_LOG(DEBUG, TAG, "num is set as Negotiation");
+ block->num += blockNum;
+ block->szx = currData->block2.szx;
+ OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
+ }
+ }
+ else
+ {
+ if (block->szx > currData->block2.szx)
+ {
+ OIC_LOG(DEBUG, TAG, "sze is big");
+ block->szx = currData->block2.szx;
+ }
+ }
+ }
+ else if (COAP_OPTION_BLOCK1 == blockType)
+ {
+ if (CA_MSG_ACKNOWLEDGE == msgType)
+ {
+ if (block->szx < currData->block1.szx)
+ {
+ OIC_LOG(DEBUG, TAG, "sze is small");
+
+ unsigned int blockNum = BLOCK_SIZE(currData->block1.szx) /
+ BLOCK_SIZE(block->szx) - 1;
+ block->num += blockNum;
+ OIC_LOG_V(DEBUG, TAG, "updated block num: %d", block->num);
+ }
+ }
+ else
+ {
+ if (block->szx > currData->block1.szx)
+ {
+ OIC_LOG(DEBUG, TAG, "sze is big");
+ block->szx = currData->block1.szx;
+ }
+ }
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "Invalid block option");
+ return CA_STATUS_FAILED;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-NegotiateBlockSize");
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockData(CABlockData_t *currData, coap_block_t block,
+ uint16_t blockType)
+{
+ VERIFY_NON_NULL(currData, TAG, "currData");
+
+ // check if block size is bigger than CABlockSize_t
+ if (block.szx > CA_BLOCK_SIZE_1024_BYTE)
+ {
+ OIC_LOG(DEBUG, TAG, "invalid block szx");
+ return CA_STATUS_FAILED;
+ }
+
+ // update block option
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ currData->block2 = block;
+ }
+ else
+ {
+ currData->block1 = block;
+ }
+
+ OIC_LOG(DEBUG, TAG, "data has updated");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ // if CON message is sent, update messageId in block-wise transfer list
+ if (CA_MSG_CONFIRM == pdu->hdr->type)
+ {
+ CAData_t * cadata = CAGetDataSetFromBlockDataList(blockID);
+ if (NULL == cadata)
+ {
+ OIC_LOG(ERROR, TAG, "CAData is unavailable");
+ return CA_STATUS_FAILED;
+ }
+
+ if (NULL != cadata->requestInfo)
+ {
+ cadata->requestInfo->info.messageId = pdu->hdr->id;
+ }
+ }
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
+ const CAEndpoint_t *endpoint)
+{
+ OIC_LOG(DEBUG, TAG, "IN-AddBlockOption");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+ VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+
+ size_t dataLength = 0;
+ if (info.payload)
+ {
+ dataLength = info.payloadSize;
+ OIC_LOG_V(DEBUG, TAG, "dataLength - %d", dataLength);
+ }
+
+ OIC_LOG_V(DEBUG, TAG, "previous payload - %s", (*pdu)->data);
+
+ uint32_t code = CA_RESPONSE_CODE((*pdu)->hdr->code);
+ if (CA_REQUEST_ENTITY_INCOMPLETE == code)
+ {
+ OIC_LOG(INFO, TAG, "don't use option");
+ return CA_STATUS_OK;
+ }
+
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)(*pdu)->hdr->token,
+ (*pdu)->hdr->token_length,
+ endpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ uint8_t blockType = CAGetBlockOptionType(blockDataID);
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ CAResult_t res = CAAddBlockOption2(pdu, info, dataLength,
+ blockDataID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ else if (COAP_OPTION_BLOCK1 == blockType)
+ {
+ CAResult_t res = CAAddBlockOption1(pdu, info, dataLength,
+ blockDataID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "no BLOCK option");
+ // if response data is so large. it have to send as block transfer
+ if (!coap_add_data(*pdu, dataLength, (const unsigned char *) info.payload))
+ {
+ OIC_LOG(INFO, TAG, "it have to use block");
+ }
+ else
+ {
+ OIC_LOG(INFO, TAG, "not Blockwise Transfer");
+ }
+ }
+
+ CAResult_t res = CAUpdateMessageId(*pdu, blockDataID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "fail to update CON message id ");
+ CADestroyBlockID(blockDataID);
+ return res;
+ }
+
+ CADestroyBlockID(blockDataID);
+ OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+ const CABlockDataID_t *blockID)
+{
+ OIC_LOG(DEBUG, TAG, "IN-AddBlockOption2");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+ VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ // get set block data from CABlock list-set.
+ coap_block_t *block1 = CAGetBlockOption(blockID,
+ COAP_OPTION_BLOCK1);
+ coap_block_t *block2 = CAGetBlockOption(blockID,
+ COAP_OPTION_BLOCK2);
+ if (!block1 || !block2)
+ {
+ OIC_LOG(ERROR, TAG, "getting has failed");
+ return CA_STATUS_FAILED;
+ }
+
+ CALogBlockInfo(block2);
+
+ uint8_t code = 0;
+ if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type ||
+ (CA_MSG_NONCONFIRM == (*pdu)->hdr->type && CA_GET != (*pdu)->hdr->code))
+ {
+ int32_t res = coap_write_block_opt(block2, COAP_OPTION_BLOCK2, *pdu, dataLength);
+ switch (res)
+ {
+ case -2: /* illegal block */
+ code = COAP_RESPONSE_CODE(CA_BAD_REQ);
+ OIC_LOG(ERROR, TAG, "write block option : -2");
+ goto error;
+ case -1: /* should really not happen */
+ OIC_LOG(ERROR, TAG, "write block option : -1");
+ break;
+ case -3: /* cannot handle request */
+ code = COAP_RESPONSE_CODE(CA_INTERNAL_SERVER_ERROR);
+ OIC_LOG(ERROR, TAG, "write block option : -3");
+ goto error;
+ default:
+ OIC_LOG(INFO, TAG, "success write block option");
+ }
+ CALogBlockInfo(block2);
+
+ if (block1->num)
+ {
+ OIC_LOG(DEBUG, TAG, "combining block1 and block2");
+ CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ // initialize block number
+ block1->num = 0;
+ }
+
+ // if block number is 0, add size2 option
+ if (0 == block2->num)
+ {
+ res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE2, dataLength);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ }
+
+ if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+ block2->num, block2->szx))
+ {
+ OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
+ return CA_STATUS_FAILED;
+ }
+
+ if (!block2->m)
+ {
+ // if sent message is last response block message, remove data
+ CARemoveBlockDataFromList(blockID);
+ }
+ else
+ {
+ if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+ {
+ OIC_LOG(DEBUG, TAG, "NON, send next block..");
+ // update block data
+ block2->num++;
+ CAResult_t res = CAProcessNextStep(*pdu, NULL,
+ CA_SENT_PREVIOUS_NON_MSG,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "failed to process next step");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ }
+ }
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "option2, not ACK msg");
+ CAResult_t res = CAAddBlockOptionImpl(*pdu, block2, COAP_OPTION_BLOCK2);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ }
+
+ return CA_STATUS_OK;
+
+error:
+ OIC_LOG_V(ERROR, TAG, "error : %d", code);
+
+ char* phrase = coap_response_phrase(code);
+ if(phrase)
+ {
+ coap_add_data(*pdu, strlen(phrase),
+ (unsigned char *) phrase);
+ }
+ return CA_STATUS_FAILED;
+}
+
+CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataLength,
+ const CABlockDataID_t *blockID)
+{
+ OIC_LOG(DEBUG, TAG, "IN-AddBlockOption1");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL((*pdu), TAG, "(*pdu)");
+ VERIFY_NON_NULL((*pdu)->hdr, TAG, "(*pdu)->hdr");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ // get set block data from CABlock list-set.
+ coap_block_t *block1 = CAGetBlockOption(blockID,
+ COAP_OPTION_BLOCK1);
+ if (NULL == block1)
+ {
+ OIC_LOG(ERROR, TAG, "getting has failed");
+ return CA_STATUS_FAILED;
+ }
+
+ CALogBlockInfo(block1);
+
+ if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type)
+ {
+ OIC_LOG(DEBUG, TAG, "option1 and ACK msg..");
+ CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+
+ // reset block-list after write block
+ if (0 == block1->m)
+ {
+ // remove data from list
+ CAResult_t res = CARemoveBlockDataFromList(blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "remove has failed");
+ return res;
+ }
+ }
+ }
+ else
+ {
+ CAGetMoreBitFromBlock(dataLength, block1);
+ CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ CALogBlockInfo(block1);
+
+ // if block number is 0, add size1 option
+ if (0 == block1->num)
+ {
+ res = CAAddBlockSizeOption(*pdu, COAP_OPTION_SIZE1, dataLength);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "add has failed");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ }
+
+ if (!coap_add_block(*pdu, dataLength, (const unsigned char *) info.payload,
+ block1->num, block1->szx))
+ {
+ OIC_LOG(ERROR, TAG, "Data length is smaller than the start index");
+ return CA_STATUS_FAILED;
+ }
+
+ // check the message type and if message type is NON, next block message will be sent
+ if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+ {
+ if (block1->m)
+ {
+ OIC_LOG(DEBUG, TAG, "NON, send next block..");
+ // update block data
+ block1->num++;
+ CAResult_t res = CAProcessNextStep(*pdu, NULL,
+ CA_SENT_PREVIOUS_NON_MSG,
+ blockID);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG(ERROR, TAG, "failed to process next step");
+ CARemoveBlockDataFromList(blockID);
+ return res;
+ }
+ }
+ else
+ {
+ CARemoveBlockDataFromList(blockID);
+ }
+ }
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-AddBlockOption1");
+
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockOptionImpl(coap_pdu_t *pdu, coap_block_t *block, uint8_t blockType)
+{
+ OIC_LOG(DEBUG, TAG, "IN-AddBlockOptionImpl");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(block, TAG, "block");
+
+ coap_option *option = (coap_option *) OICMalloc(sizeof(coap_option));
+ if (NULL == option)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ unsigned char buf[BLOCKWISE_OPTION_BUFFER] = { 0 };
+ option->key = blockType;
+ option->length = coap_encode_var_bytes(buf,
+ ((block->num << BLOCK_NUMBER_IDX)
+ | (block->m << BLOCK_M_BIT_IDX) | block->szx));
+ if (!coap_add_option(pdu, option->key, option->length, buf))
+ {
+ OIC_LOG(ERROR, TAG, "coap_add_option has failed");
+ OICFree(option);
+ return CA_STATUS_FAILED;
+ }
+
+ OICFree(option);
+
+ OIC_LOG(DEBUG, TAG, "OUT-AddBlockOptionImpl");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataLength)
+{
+ OIC_LOG(DEBUG, TAG, "IN-CAAddBlockSizeOption");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+
+ if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
+ {
+ OIC_LOG(ERROR, TAG, "unknown option type");
+ return CA_STATUS_FAILED;
+ }
+
+ unsigned char value[BLOCKWISE_OPTION_BUFFER] = { 0 };
+ unsigned int optionLength = coap_encode_var_bytes(value, dataLength);
+
+ if (!coap_add_option(pdu, sizeType, optionLength, value))
+ {
+ OIC_LOG(ERROR, TAG, "failed to add size option");
+ return CA_STATUS_FAILED;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-CAAddBlockSizeOption");
+
+ return CA_STATUS_OK;
+}
+
+// TODO make pdu const after libcoap is updated to support that.
+bool CAIsPayloadLengthInPduWithBlockSizeOption(coap_pdu_t *pdu,
+ uint16_t sizeType,
+ size_t *totalPayloadLen)
+{
+ OIC_LOG(DEBUG, TAG, "IN-CAIsPayloadLengthInPduWithBlockSizeOption");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(totalPayloadLen, TAG, "totalPayloadLen");
+
+ if (sizeType != COAP_OPTION_SIZE1 && sizeType != COAP_OPTION_SIZE2)
+ {
+ OIC_LOG(ERROR, TAG, "unknown option type");
+ return CA_STATUS_FAILED;
+ }
+
+ coap_opt_iterator_t opt_iter;
+ coap_opt_t *option = coap_check_option(pdu, sizeType, &opt_iter);
+ if (option)
+ {
+ OIC_LOG(DEBUG, TAG, "get size option from pdu");
+ *totalPayloadLen = coap_decode_var_bytes(COAP_OPT_VALUE(option),
+ COAP_OPT_LENGTH(option));
+
+ OIC_LOG_V(DEBUG, TAG, "the total payload length to be received is [%d]bytes",
+ *totalPayloadLen);
+
+ return true;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-CAIsPayloadLengthInPduWithBlockSizeOption");
+
+ return false;
+}
+
+uint8_t CACheckBlockErrorType(CABlockData_t *currData, coap_block_t *receivedBlock,
+ const CAData_t *receivedData, uint16_t blockType,
+ size_t dataLen)
+{
+ OIC_LOG(DEBUG, TAG, "IN-CheckBlockError");
+
+ VERIFY_NON_NULL(currData, TAG, "currData is NULL");
+ VERIFY_NON_NULL(receivedBlock, TAG, "receivedBlock is NULL");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData is NULL");
+
+ // #1. check the received payload length
+ size_t blockPayloadLen = 0;
+ CAGetPayloadInfo(receivedData, &blockPayloadLen);
+
+ // #2. check if the block sequence is right
+ if (COAP_OPTION_BLOCK1 == blockType)
+ {
+ size_t prePayloadLen = currData->receivedPayloadLen;
+ if (prePayloadLen != (size_t)BLOCK_SIZE(receivedBlock->szx)
+ * receivedBlock->num)
+ {
+ if (receivedBlock->num > currData->block1.num + 1)
+ {
+ // 408 Error handling of block loss
+ OIC_LOG(ERROR, TAG, "option1: error 4.08");
+ OIC_LOG(ERROR, TAG, "it didn't order");
+ return CA_BLOCK_INCOMPLETE;
+ }
+ return CA_BLOCK_RECEIVED_ALREADY;
+ }
+ }
+ else if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ if (receivedBlock->num != currData->block2.num)
+ {
+ if (receivedBlock->num > currData->block2.num)
+ {
+ // 408 Error handling of block loss
+ OIC_LOG(ERROR, TAG, "option2: error 4.08");
+ OIC_LOG(ERROR, TAG, "it didn't order");
+ return CA_BLOCK_INCOMPLETE;
+ }
+ return CA_BLOCK_RECEIVED_ALREADY;
+ }
+ }
+
+ // #3. check if error check logic is required
+ size_t optionLen = dataLen - blockPayloadLen;
+ if (receivedBlock->m && blockPayloadLen !=
+ (size_t)BLOCK_SIZE(receivedBlock->szx))
+ {
+ // 413 Error handling of too large entity
+ if (COAP_MAX_PDU_SIZE < BLOCK_SIZE(receivedBlock->szx) + optionLen)
+ {
+ // buffer size is smaller than received block size
+ OIC_LOG(ERROR, TAG, "error type 4.13");
+ OIC_LOG(ERROR, TAG, "too large size");
+
+ // set the block size to be smaller than COAP_MAX_PDU_SIZE
+ for (int32_t size = CA_DEFAULT_BLOCK_SIZE; size >= 0; size--)
+ {
+ if (COAP_MAX_PDU_SIZE >= BLOCK_SIZE(size) + optionLen)
+ {
+ OIC_LOG_V(ERROR, TAG, "replace sze with %d", size);
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ currData->block2.szx = size;
+ }
+ else
+ {
+ currData->block1.szx = size;
+ }
+ break;
+ }
+ }
+ return CA_BLOCK_TOO_LARGE;
+ }
+ else
+ {
+ // 408 Error handling of payload loss
+ OIC_LOG(ERROR, TAG, "error type 4.08");
+ OIC_LOG(ERROR, TAG, "payload len != block sze");
+ return CA_BLOCK_INCOMPLETE;
+ }
+ }
+ else if (0 == receivedBlock->m && 0 != currData->payloadLength)
+ {
+ // if the received block is last block, check the total payload length
+ size_t receivedPayloadLen = currData->receivedPayloadLen;
+ receivedPayloadLen += blockPayloadLen;
+
+ if (receivedPayloadLen != currData->payloadLength)
+ {
+ OIC_LOG(ERROR, TAG, "error type 4.08");
+ OIC_LOG(ERROR, TAG, "total payload length is wrong");
+ return CA_BLOCK_INCOMPLETE;
+ }
+ }
+
+ OIC_LOG(DEBUG, TAG, "received all data normally");
+
+ OIC_LOG(DEBUG, TAG, "OUT-CheckBlockError");
+
+ return CA_BLOCK_UNKNOWN;
+}
+
+CAResult_t CAUpdatePayloadData(CABlockData_t *currData, const CAData_t *receivedData,
+ uint8_t status, bool isSizeOption, uint16_t blockType)
+{
+ OIC_LOG(DEBUG, TAG, "IN-UpdatePayloadData");
+
+ VERIFY_NON_NULL(currData, TAG, "currData");
+ VERIFY_NON_NULL(receivedData, TAG, "receivedData");
+
+ // if error code is 4.08, do not update payload
+ if (CA_BLOCK_INCOMPLETE == status)
+ {
+ OIC_LOG(ERROR, TAG, "no require to update");
+ return CA_STATUS_OK;
+ }
+
+ size_t blockPayloadLen = 0;
+ CAPayload_t blockPayload = CAGetPayloadInfo(receivedData, &blockPayloadLen);
+
+ if (CA_BLOCK_TOO_LARGE == status)
+ {
+ blockPayloadLen = (COAP_OPTION_BLOCK2 == blockType) ?
+ BLOCK_SIZE(currData->block2.szx) : BLOCK_SIZE(currData->block1.szx);
+ }
+
+ // memory allocation for the received block payload
+ size_t prePayloadLen = currData->receivedPayloadLen;
+ if (NULL != blockPayload)
+ {
+ if (0 != currData->payloadLength)
+ {
+ // in case the block message has the size option
+ // allocate the memory for the total payload
+ if (true == isSizeOption)
+ {
+ CAPayload_t prePayload = currData->payload;
+
+ OIC_LOG(DEBUG, TAG, "allocate memory for the total payload");
+ currData->payload = (CAPayload_t) OICCalloc(currData->payloadLength + 1,
+ sizeof(char));
+ if (NULL == currData->payload)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+ memcpy(currData->payload, prePayload, prePayloadLen);
+ OICFree(prePayload);
+ }
+
+ // update the total payload
+ memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
+ }
+ else
+ {
+ OIC_LOG(DEBUG, TAG, "allocate memory for the received block payload");
+
+ size_t totalPayloadLen = prePayloadLen + blockPayloadLen + 1;
+ CAPayload_t newPayload = OICRealloc(currData->payload, totalPayloadLen);
+ if (NULL == newPayload)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ // update the total payload
+ memset(newPayload + prePayloadLen, 0, blockPayloadLen + 1);
+ currData->payload = newPayload;
+ memcpy(currData->payload + prePayloadLen, blockPayload, blockPayloadLen);
+ }
+
+ // update received payload length
+ currData->receivedPayloadLen += blockPayloadLen;
+
+ OIC_LOG_V(DEBUG, TAG, "updated payload: %s, len: %d", currData->payload,
+ currData->receivedPayloadLen);
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-UpdatePayloadData");
+ return CA_STATUS_OK;
+}
+
+CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint)
+{
+ VERIFY_NON_NULL_RET(pdu, TAG, "pdu", NULL);
+ VERIFY_NON_NULL_RET(pdu->hdr, TAG, "pdu->hdr", NULL);
+ VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
+
+ CAInfo_t responseData = { .tokenLength = pdu->hdr->token_length };
+ responseData.token = (CAToken_t) OICMalloc(responseData.tokenLength);
+ if (NULL == responseData.token)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return NULL;
+ }
+ memcpy(responseData.token, pdu->hdr->token, responseData.tokenLength);
+
+ CAResponseInfo_t* responseInfo = (CAResponseInfo_t*) OICCalloc(1, sizeof(CAResponseInfo_t));
+ if (NULL == responseInfo)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ OICFree(responseData.token);
+ return NULL;
+ }
+ responseInfo->info = responseData;
+
+ CAData_t *data = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ OICFree(responseInfo);
+ return NULL;
+ }
+
+ data->requestInfo = NULL;
+ data->responseInfo = responseInfo;
+ data->remoteEndpoint = CACloneEndpoint(endpoint);
+ data->type = SEND_TYPE_UNICAST;
+
+ return data;
+}
+
+CAData_t *CACloneCAData(const CAData_t *data)
+{
+ VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
+
+ CAData_t *clone = (CAData_t *) OICCalloc(1, sizeof(CAData_t));
+ if (NULL == clone)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return NULL;
+ }
+ *clone = *data;
+
+ if (data->requestInfo)
+ {
+ clone->requestInfo = CACloneRequestInfo(data->requestInfo);
+ }
+
+ if (data->responseInfo)
+ {
+ clone->responseInfo = CACloneResponseInfo(data->responseInfo);
+ }
+
+ if (data->remoteEndpoint)
+ {
+ clone->remoteEndpoint = CACloneEndpoint(data->remoteEndpoint);
+ }
+
+ return clone;
+}
+
+CAResult_t CAUpdatePayloadToCAData(CAData_t *data, const CAPayload_t payload,
+ size_t payloadLen)
+{
+ OIC_LOG(DEBUG, TAG, "IN-UpdatePayload");
+
+ VERIFY_NON_NULL(data, TAG, "data is NULL");
+ VERIFY_NON_NULL(payload, TAG, "payload is NULL");
+
+ if (NULL != data->requestInfo)
+ {
+ // allocate payload field
+ if (NULL != data->requestInfo->info.payload)
+ {
+ char *temp = (char *) OICCalloc(payloadLen, sizeof(char));
+ if (NULL == temp)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return CA_STATUS_FAILED;
+ }
+ memcpy(temp, payload, payloadLen);
+
+ // save the full payload
+ OICFree(data->requestInfo->info.payload);
+ data->requestInfo->info.payload = (CAPayload_t) temp;
+ }
+ data->requestInfo->info.payloadSize = payloadLen;
+ }
+
+ if (NULL != data->responseInfo)
+ {
+ // allocate payload field
+ if (NULL != data->responseInfo->info.payload)
+ {
+ char *temp = (char *) OICCalloc(payloadLen, sizeof(char));
+ if (NULL == temp)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ return CA_STATUS_FAILED;
+ }
+ memcpy(temp, payload, payloadLen);
+
+ // save the full payload
+ OICFree(data->responseInfo->info.payload);
+ data->responseInfo->info.payload = (CAPayload_t) temp;
+ }
+ data->responseInfo->info.payloadSize = payloadLen;
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-UpdatePayload");
+
+ return CA_STATUS_OK;
+}
+
+CAPayload_t CAGetPayloadInfo(const CAData_t *data, size_t *payloadLen)
+{
+ VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
+ VERIFY_NON_NULL_RET(payloadLen, TAG, "payloadLen", NULL);
+
+ if (NULL != data->requestInfo)
+ {
+ if (NULL != data->requestInfo->info.payload)
+ {
+ *payloadLen = data->requestInfo->info.payloadSize;
+ return data->requestInfo->info.payload;
+ }
+ }
+ else
+ {
+ if (NULL != data->responseInfo->info.payload)
+ {
+ *payloadLen = data->responseInfo->info.payloadSize;
+ return data->responseInfo->info.payload;
+ }
+ }
+
+ return NULL;
+}
+
+CAResult_t CAHandleBlockErrorResponse(coap_block_t *block, uint16_t blockType,
+ uint32_t responseResult)
+{
+ OIC_LOG(DEBUG, TAG, "IN-HandleBlockErrorRes");
+ VERIFY_NON_NULL(block, TAG, "block is NULL");
+
+ // update block data
+ switch (responseResult)
+ {
+ case CA_REQUEST_ENTITY_INCOMPLETE:
+ block->num = 0;
+ break;
+ case CA_REQUEST_ENTITY_TOO_LARGE:
+ if (COAP_OPTION_BLOCK1 == blockType)
+ {
+ block->num++;
+ }
+ block->m = 0;
+ break;
+ default:
+ OIC_LOG_V(ERROR, TAG, "there is no Error Code of BWT[%d]", responseResult);
+ }
+
+ OIC_LOG(DEBUG, TAG, "OUT-HandleBlockErrorRes");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAUpdateBlockOptionType(const CABlockDataID_t *blockID,
+ uint8_t blockType)
+{
+ OIC_LOG(DEBUG, TAG, "IN-UpdateBlockOptionType");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ currData->type = blockType;
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
+ return CA_STATUS_OK;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-UpdateBlockOptionType");
+ return CA_STATUS_FAILED;
+}
+
+uint8_t CAGetBlockOptionType(const CABlockDataID_t *blockID)
+{
+ OIC_LOG(DEBUG, TAG, "IN-GetBlockOptionType");
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", 0);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
+ return currData->type;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-GetBlockOptionType");
+ return 0;
+}
+
+CAData_t *CAGetDataSetFromBlockDataList(const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return currData->sentData;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ return NULL;
+}
+
+CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+ CAResponseInfo_t *responseInfo)
+{
+ OIC_LOG(DEBUG, TAG, "IN-CAGetTokenFromBlockDataList");
+ VERIFY_NON_NULL(pdu, TAG, "pdu");
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+ VERIFY_NON_NULL(responseInfo, TAG, "responseInfo");
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (NULL == currData)
+ {
+ continue;
+ }
+
+ if (NULL != currData->sentData && NULL != currData->sentData->requestInfo)
+ {
+ if (pdu->hdr->id == currData->sentData->requestInfo->info.messageId &&
+ endpoint->adapter == currData->sentData->remoteEndpoint->adapter)
+ {
+ if (NULL != currData->sentData->requestInfo->info.token)
+ {
+ uint8_t length = currData->sentData->requestInfo->info.tokenLength;
+ responseInfo->info.tokenLength = length;
+ responseInfo->info.token = (char *) OICMalloc(length);
+ if (NULL == responseInfo->info.token)
+ {
+ OIC_LOG(ERROR, TAG, "out of memory");
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+ memcpy(responseInfo->info.token, currData->sentData->requestInfo->info.token,
+ responseInfo->info.tokenLength);
+
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
+ return CA_STATUS_OK;
+ }
+ }
+ }
+ }
+
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-CAGetTokenFromBlockDataList");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CACheckBlockDataValidation(const CAData_t *sendData, CABlockData_t **blockData)
+{
+ VERIFY_NON_NULL(sendData, TAG, "sendData");
+ VERIFY_NON_NULL(blockData, TAG, "blockData");
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+
+ if (NULL == currData)
+ {
+ continue;
+ }
+
+ if (NULL != sendData->requestInfo) // sendData is requestMessage
+ {
+ OIC_LOG(DEBUG, TAG, "Send request");
+ if (NULL != currData->blockDataId
+ && NULL != currData->blockDataId->id
+ && currData->blockDataId->idLength > 0
+ && NULL != sendData->requestInfo->info.token)
+ {
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)sendData->requestInfo->info.token,
+ sendData->requestInfo->info.tokenLength,
+ sendData->remoteEndpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ if (CABlockidMatches(currData, blockDataID))
+ {
+ OIC_LOG(ERROR, TAG, "already sent");
+ CADestroyBlockID(blockDataID);
+ continue;
+ }
+ CADestroyBlockID(blockDataID);
+ }
+ }
+ else if (NULL != sendData->responseInfo) // sendData is responseMessage
+ {
+ OIC_LOG(DEBUG, TAG, "Send response");
+ if (NULL != currData->blockDataId
+ && NULL != currData->blockDataId->id
+ && currData->blockDataId->idLength > 0
+ && NULL != sendData->responseInfo->info.token)
+ {
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ (CAToken_t)sendData->responseInfo->info.token,
+ sendData->responseInfo->info.tokenLength,
+ sendData->remoteEndpoint->port);
+
+ if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return CA_STATUS_FAILED;
+ }
+
+ if (CABlockidMatches(currData, blockDataID))
+ {
+ // set sendData
+ if (NULL != currData->sentData)
+ {
+ OIC_LOG(DEBUG, TAG, "init block number");
+ CADestroyDataSet(currData->sentData);
+ }
+ currData->sentData = CACloneCAData(sendData);
+ *blockData = currData;
+ CADestroyBlockID(blockDataID);
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return CA_STATUS_OK;
+ }
+ CADestroyBlockID(blockDataID);
+ }
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "no CAInfo data");
+ continue;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ return CA_STATUS_FAILED;
+}
+
+CABlockData_t *CAGetBlockDataFromBlockDataList(const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return currData;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ return NULL;
+}
+
+coap_block_t *CAGetBlockOption(const CABlockDataID_t *blockID,
+ uint16_t blockType)
+{
+ OIC_LOG(DEBUG, TAG, "IN-GetBlockOption");
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+ if (COAP_OPTION_BLOCK2 == blockType)
+ {
+ return &currData->block2;
+ }
+ else
+ {
+ return &currData->block1;
+ }
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-GetBlockOption");
+ return NULL;
+}
+
+CAPayload_t CAGetPayloadFromBlockDataList(const CABlockDataID_t *blockID,
+ size_t *fullPayloadLen)
+{
+ OIC_LOG(DEBUG, TAG, "IN-GetFullPayload");
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", NULL);
+ VERIFY_NON_NULL_RET(fullPayloadLen, TAG, "fullPayloadLen", NULL);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ *fullPayloadLen = currData->receivedPayloadLen;
+ OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
+ return currData->payload;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-GetFullPayload");
+ return NULL;
+}
+
+CABlockData_t *CACreateNewBlockData(const CAData_t *sendData)
+{
+ OIC_LOG(DEBUG, TAG, "IN-CACreateNewBlockData");
+ VERIFY_NON_NULL_RET(sendData, TAG, "sendData", NULL);
+
+ // create block data
+ CABlockData_t *data = (CABlockData_t *) OICCalloc(1, sizeof(CABlockData_t));
+ if (NULL == data)
+ {
+ OIC_LOG(ERROR, TAG, "memory alloc has failed");
+ return NULL;
+ }
+
+ data->block1.szx = CA_DEFAULT_BLOCK_SIZE;
+ data->block2.szx = CA_DEFAULT_BLOCK_SIZE;
+ data->sentData = CACloneCAData(sendData);
+ if(!data->sentData)
+ {
+ OIC_LOG(ERROR, TAG, PCF("memory alloc has failed"));
+ OICFree(data);
+ return NULL;
+ }
+
+ CAToken_t token = NULL;
+ uint8_t tokenLength = 0;
+ if (data->sentData->requestInfo)
+ {
+ // update token info
+ tokenLength = data->sentData->requestInfo->info.tokenLength;
+ token = data->sentData->requestInfo->info.token;
+ }
+ else if(data->sentData->responseInfo)
+ {
+ tokenLength = data->sentData->responseInfo->info.tokenLength;
+ token = data->sentData->responseInfo->info.token;
+ }
+
+ CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
+ token, tokenLength,
+ data->sentData->remoteEndpoint->port);
+ if (NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
+ {
+ OIC_LOG(ERROR, TAG, "blockId is null");
+ CADestroyBlockID(blockDataID);
+ return NULL;
+ }
+ data->blockDataId = blockDataID;
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ CAResult_t res = u_arraylist_add(g_context.dataList, (void *) data);
+ if (CA_STATUS_OK != res)
+ {
+ OIC_LOG_V(ERROR, TAG, "add has failed(%d)", res);
+ CADestroyBlockID(data->blockDataId);
+ OICFree(data);
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return NULL;
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-CreateBlockData");
+ return data;
+}
+
+CAResult_t CARemoveBlockDataFromList(const CABlockDataID_t *blockID)
+{
+ OIC_LOG(DEBUG, TAG, "CARemoveBlockData");
+ VERIFY_NON_NULL(blockID, TAG, "blockID");
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ CABlockData_t *removedData = u_arraylist_remove(g_context.dataList, i);
+ if (NULL == removedData)
+ {
+ OIC_LOG(ERROR, TAG, "data is NULL");
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return CA_STATUS_FAILED;
+ }
+
+ // destroy memory
+ if (currData->sentData)
+ {
+ CADestroyDataSet(currData->sentData);
+ }
+ OICFree(currData->payload);
+ CADestroyBlockID(currData->blockDataId);
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return CA_STATUS_OK;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ return CA_STATUS_OK;
+}
+
+bool CAIsBlockDataInList(const CABlockDataID_t *blockID)
+{
+ OIC_LOG(DEBUG, TAG, "IN-IsBlockDataInList");
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
+
+ ca_mutex_lock(g_context.blockDataListMutex);
+
+ size_t len = u_arraylist_length(g_context.dataList);
+ for (size_t i = 0; i < len; i++)
+ {
+ CABlockData_t *currData = (CABlockData_t *) u_arraylist_get(g_context.dataList, i);
+ if (CABlockidMatches(currData, blockID))
+ {
+ OIC_LOG(DEBUG, TAG, "found block data");
+ ca_mutex_unlock(g_context.blockDataListMutex);
+ return true;
+ }
+ }
+ ca_mutex_unlock(g_context.blockDataListMutex);
+
+ OIC_LOG(DEBUG, TAG, "OUT-IsBlockDataInList");
+ return false;
+}
+
+void CADestroyDataSet(CAData_t* data)
+{
+ VERIFY_NON_NULL_VOID(data, TAG, "data");
+
+ CAFreeEndpoint(data->remoteEndpoint);
+ CADestroyRequestInfoInternal(data->requestInfo);
+ CADestroyResponseInfoInternal(data->responseInfo);
+ OICFree(data);
+}
+
+CABlockDataID_t* CACreateBlockDatablockId(const CAToken_t token, uint8_t tokenLength,
+ uint16_t portNumber)
+{
+ VERIFY_NON_NULL_RET(token, TAG, "token", NULL);
+
+ char port[PORT_LENGTH] = {0,};
+ port[0] = (char)((portNumber>>8) & 0xFF);
+ port[1] = (char)(portNumber & 0xFF);
+
+ CABlockDataID_t* blockDataID = (CABlockDataID_t *) OICMalloc(sizeof(CABlockDataID_t));
+ blockDataID->idLength = tokenLength + sizeof(port);
+ blockDataID->id = (uint8_t *) OICMalloc(blockDataID->idLength);
+ if (!blockDataID->id)
+ {
+ OIC_LOG(ERROR, TAG, "memory alloc has failed");
+ OICFree(blockDataID);
+ return NULL;
+ }
+
+ memcpy(blockDataID->id, token, tokenLength);
+ memcpy(blockDataID->id + tokenLength, port, sizeof(port));
+
+ OIC_LOG(DEBUG, TAG, "BlockID is ");
+ OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)blockDataID->id, blockDataID->idLength);
+
+ return blockDataID;
+}
+
+void CADestroyBlockID(CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL_VOID(blockID, TAG, "blockID");
+ OICFree(blockID->id);
+ OICFree(blockID);
+ blockID = NULL;
+}
+
+bool CABlockidMatches(const CABlockData_t *currData, const CABlockDataID_t *blockID)
+{
+ VERIFY_NON_NULL_RET(currData, TAG, "currData", false);
+ VERIFY_NON_NULL_RET(blockID, TAG, "blockID", false);
+ VERIFY_NON_NULL_RET(blockID->id, TAG, "blockID->id", false);
+
+ if ((currData->blockDataId)
+ && (currData->blockDataId->id)
+ && (currData->blockDataId->idLength == blockID->idLength)
+ && !memcmp(currData->blockDataId->id, blockID->id, currData->blockDataId->idLength))
+ {
+ return true;
+ }
+ return false;
+}
+
+void CALogBlockInfo(coap_block_t *block)
+{
+ VERIFY_NON_NULL_VOID(block, TAG, "block");
+
+ OIC_LOG(DEBUG, TAG, "block option info");
+
+ OIC_LOG_V(DEBUG, TAG, "block option-num : %d", block->num);
+
+ OIC_LOG_V(DEBUG, TAG, "block option-m : %d", block->m);
+
+ OIC_LOG_V(DEBUG, TAG, "block option-szx : %d", block->szx);
+}
diff --git a/resource/csdk/connectivity/src/cainterfacecontroller.c b/resource/csdk/connectivity/src/cainterfacecontroller.c
index 6c4a81f51..cb412413e 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 9695e2f40..38d722cdb 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 b6e3b0533..16024c7f3 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 709a4b044..6a88b0dc7 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 91776c469..fc6aaea8f 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 afb870011..3c7bcc571 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 3b6bd0248..02a5b0f74 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 <stdlib.h>
#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 203986f0b..aa63c530d 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 9f8b0dc82..d2c6aee05 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 be6fa9611..3eda85a17 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;
}