mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 23:57:47 +00:00
[coap] add CoAP(s) block-wise transfer support to CoAP(s) client and server (#4247)
Implemented CoAP/-s block-wise transfer according to RFC 7959. The implementation includes methods and functions available to the application layer to add Block1 and Block2 option values to a coap message and an automatic block-wise transfer enabled by the compile switch "COAP_BLOCK".
This commit is contained in:
@@ -117,6 +117,11 @@ if(OT_COAPS)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE=1")
|
||||
endif()
|
||||
|
||||
option(OT_COAP_BLOCK "enable coap block-wise transfer (RFC7959) api support")
|
||||
if(OT_COAP_BLOCK)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE=1")
|
||||
endif()
|
||||
|
||||
option(OT_COAP_OBSERVE "enable coap observe (RFC7641) api support")
|
||||
if(OT_COAP_OBSERVE)
|
||||
list(APPEND OT_PRIVATE_DEFINES "OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE=1")
|
||||
|
||||
@@ -38,6 +38,7 @@ DEBUG ?= 0
|
||||
BORDER_AGENT ?= 1
|
||||
BORDER_ROUTER ?= 1
|
||||
COAP ?= 1
|
||||
COAP_BLOCK ?= 1
|
||||
COAP_OBSERVE ?= 1
|
||||
COAPS ?= 1
|
||||
COMMISSIONER ?= 1
|
||||
|
||||
@@ -34,6 +34,7 @@ BORDER_AGENT ?= 0
|
||||
BORDER_ROUTER ?= 0
|
||||
BORDER_ROUTING ?= 0
|
||||
COAP ?= 0
|
||||
COAP_BLOCK ?= 0
|
||||
COAP_OBSERVE ?= 0
|
||||
COAPS ?= 0
|
||||
COMMISSIONER ?= 0
|
||||
@@ -112,6 +113,10 @@ ifeq ($(COAPS),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(COAP_BLOCK),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(COAP_OBSERVE),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE=1
|
||||
endif
|
||||
|
||||
+228
-17
@@ -144,25 +144,12 @@ typedef enum otCoapOptionType
|
||||
OT_COAP_OPTION_LOCATION_QUERY = 20, ///< Location-Query
|
||||
OT_COAP_OPTION_BLOCK2 = 23, ///< Block2 (RFC7959)
|
||||
OT_COAP_OPTION_BLOCK1 = 27, ///< Block1 (RFC7959)
|
||||
OT_COAP_OPTION_SIZE2 = 28, ///< Size2 (RFC7959)
|
||||
OT_COAP_OPTION_PROXY_URI = 35, ///< Proxy-Uri
|
||||
OT_COAP_OPTION_PROXY_SCHEME = 39, ///< Proxy-Scheme
|
||||
OT_COAP_OPTION_SIZE1 = 60, ///< Size1
|
||||
} otCoapOptionType;
|
||||
|
||||
/**
|
||||
* CoAP Block Size Exponents
|
||||
*/
|
||||
typedef enum otCoapBlockSize
|
||||
{
|
||||
OT_COAP_BLOCK_SIZE_16 = 0,
|
||||
OT_COAP_BLOCK_SIZE_32 = 1,
|
||||
OT_COAP_BLOCK_SIZE_64 = 2,
|
||||
OT_COAP_BLOCK_SIZE_128 = 3,
|
||||
OT_COAP_BLOCK_SIZE_256 = 4,
|
||||
OT_COAP_BLOCK_SIZE_512 = 5,
|
||||
OT_COAP_BLOCK_SIZE_1024 = 6,
|
||||
} otCoapBlockSize;
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP option.
|
||||
*
|
||||
@@ -327,6 +314,20 @@ typedef enum otCoapOptionContentFormat
|
||||
OT_COAP_OPTION_CONTENT_FORMAT_SENSML_XML = 311
|
||||
} otCoapOptionContentFormat;
|
||||
|
||||
/**
|
||||
* CoAP Block Size Exponents
|
||||
*/
|
||||
typedef enum otCoapBlockSzx
|
||||
{
|
||||
OT_COAP_OPTION_BLOCK_SZX_16 = 0,
|
||||
OT_COAP_OPTION_BLOCK_SZX_32 = 1,
|
||||
OT_COAP_OPTION_BLOCK_SZX_64 = 2,
|
||||
OT_COAP_OPTION_BLOCK_SZX_128 = 3,
|
||||
OT_COAP_OPTION_BLOCK_SZX_256 = 4,
|
||||
OT_COAP_OPTION_BLOCK_SZX_512 = 5,
|
||||
OT_COAP_OPTION_BLOCK_SZX_1024 = 6
|
||||
} otCoapBlockSzx;
|
||||
|
||||
/**
|
||||
* This function pointer is called when a CoAP response is received or on the request timeout.
|
||||
*
|
||||
@@ -355,6 +356,58 @@ typedef void (*otCoapResponseHandler)(void * aContext,
|
||||
*/
|
||||
typedef void (*otCoapRequestHandler)(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
|
||||
/**
|
||||
* This function pointer is called when a CoAP message with an block-wise transfer option is received.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[in] aBlock A pointer to the block segment.
|
||||
* @param[in] aPosition The position of @p aBlock in a sequence in bytes.
|
||||
* @param[in] aBlockLength The length of the block segment in bytes.
|
||||
* @param[in] aMore Flag if more block segments are following.
|
||||
* @param[in] aTotalLength The total length in bytes of the transfered information (indicated by a Size1 or Size2
|
||||
* option).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Block segment was stored successfully.
|
||||
* @retval OT_ERROR_NO_BUFS No more memory to store blocks.
|
||||
* @retval OT_ERROR_NO_FRAME_RECEIVED Block segment missing.
|
||||
*
|
||||
*/
|
||||
typedef otError (*otCoapBlockwiseReceiveHook)(void * aContext,
|
||||
const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength);
|
||||
|
||||
/**
|
||||
* This function pointer is called before the next block in a block-wise transfer is sent.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[inout] aBlock A pointer to where the block segment can be written to.
|
||||
* @param[in] aPosition The position in a sequence from which to obtain the block segment.
|
||||
* @param[inout] aBlockLength On entry, the maximum block segment length in bytes.
|
||||
* @param[out] aMore A pointer to the flag if more block segments will follow.
|
||||
*
|
||||
* @warning By changing the value of aBlockLength, the block size of the whole exchange is
|
||||
* renegotiated. It is recommended to do this after the first block has been received as
|
||||
* later changes could cause problems with other CoAP implementations.
|
||||
*
|
||||
* @retval OT_ERROR_NONE No error occurred.
|
||||
* @retval OT_ERROR_INVALID_ARGS Block at @p aPosition does not exist.
|
||||
*
|
||||
*/
|
||||
typedef otError (*otCoapBlockwiseTransmitHook)(void * aContext,
|
||||
uint8_t * aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t *aBlockLength,
|
||||
bool * aMore);
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP resource.
|
||||
*
|
||||
@@ -367,6 +420,30 @@ typedef struct otCoapResource
|
||||
struct otCoapResource *mNext; ///< The next CoAP resource in the list
|
||||
} otCoapResource;
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP resource with block-wise transfer.
|
||||
*
|
||||
*/
|
||||
typedef struct otCoapBlockwiseResource
|
||||
{
|
||||
const char * mUriPath; ///< The URI Path string
|
||||
otCoapRequestHandler mHandler; ///< The callback for handling a received request
|
||||
|
||||
/** The callback for handling incoming block-wise transfer.
|
||||
* This callback is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
* configuration is enabled.
|
||||
*/
|
||||
otCoapBlockwiseReceiveHook mReceiveHook;
|
||||
|
||||
/** The callback for handling outgoing block-wise transfer.
|
||||
* This callback is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
* configuration is enabled.
|
||||
*/
|
||||
otCoapBlockwiseTransmitHook mTransmitHook;
|
||||
void * mContext; ///< Application-specific context
|
||||
struct otCoapBlockwiseResource *mNext; ///< The next CoAP resource in the list
|
||||
} otCoapBlockwiseResource;
|
||||
|
||||
/**
|
||||
* This structure represents the CoAP transmission parameters.
|
||||
*
|
||||
@@ -539,7 +616,7 @@ otError otCoapMessageAppendUriPathOptions(otMessage *aMessage, const char *aUriP
|
||||
* @returns The actual size exponent value.
|
||||
*
|
||||
*/
|
||||
uint16_t otCoapBlockSizeFromExponent(otCoapBlockSize aSize);
|
||||
uint16_t otCoapBlockSizeFromExponent(otCoapBlockSzx aSize);
|
||||
|
||||
/**
|
||||
* This function appends a Block2 option
|
||||
@@ -554,7 +631,7 @@ uint16_t otCoapBlockSizeFromExponent(otCoapBlockSize aSize);
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSize aSize);
|
||||
otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize);
|
||||
|
||||
/**
|
||||
* This function appends a Block1 option
|
||||
@@ -569,7 +646,7 @@ otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
otError otCoapMessageAppendBlock1Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSize aSize);
|
||||
otError otCoapMessageAppendBlock1Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize);
|
||||
|
||||
/**
|
||||
* This function appends a Proxy-Uri option.
|
||||
@@ -804,6 +881,72 @@ otError otCoapSendRequestWithParameters(otInstance * aInstance,
|
||||
void * aContext,
|
||||
const otCoapTxParameters *aTxParameters);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP request block-wise with custom transmission parameters.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If the response is expected to be block-wise, a respective hook function should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the message to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or timeout.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTxParameters A pointer to transmission parameters for this request. Use NULL for defaults.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
* @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendRequestBlockWiseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
const otCoapTxParameters * aTxParameters,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP request block-wise.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If the response is expected to be block-wise, a respective hook function should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the message to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or timeout.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
* @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
static inline otError otCoapSendRequestBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
{
|
||||
return otCoapSendRequestBlockWiseWithParameters(aInstance, aMessage, aMessageInfo, aHandler, aContext, nullptr,
|
||||
aTransmitHook, aReceiveHook);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function sends a CoAP request.
|
||||
*
|
||||
@@ -870,6 +1013,24 @@ void otCoapAddResource(otInstance *aInstance, otCoapResource *aResource);
|
||||
*/
|
||||
void otCoapRemoveResource(otInstance *aInstance, otCoapResource *aResource);
|
||||
|
||||
/**
|
||||
* This function adds a block-wise resource to the CoAP server.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aResource A pointer to the resource.
|
||||
*
|
||||
*/
|
||||
void otCoapAddBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
|
||||
|
||||
/**
|
||||
* This function removes a block-wise resource from the CoAP server.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aResource A pointer to the resource.
|
||||
*
|
||||
*/
|
||||
void otCoapRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
|
||||
|
||||
/**
|
||||
* This function sets the default handler for unhandled CoAP requests.
|
||||
*
|
||||
@@ -897,6 +1058,56 @@ otError otCoapSendResponseWithParameters(otInstance * aInstance,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
const otCoapTxParameters *aTxParameters);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response block-wise from the server with custom transmission parameters.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the CoAP response to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aTxParameters A pointer to transmission parameters for this response. Use NULL for defaults.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendResponseBlockWiseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
const otCoapTxParameters * aTxParameters,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response block-wise from the server.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the CoAP response to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
static inline otError otCoapSendResponseBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook)
|
||||
{
|
||||
return otCoapSendResponseBlockWiseWithParameters(aInstance, aMessage, aMessageInfo, nullptr, aContext,
|
||||
aTransmitHook);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response from the server.
|
||||
*
|
||||
|
||||
@@ -229,6 +229,35 @@ bool otCoapSecureIsConnected(otInstance *aInstance);
|
||||
*/
|
||||
bool otCoapSecureIsConnectionActive(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP request block-wise over secure DTLS connection.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTransmitHook A function pointer that is called on Block1 response reception.
|
||||
* @param[in] aReceiveHook A function pointer that is called on Block2 response reception.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
* @retval OT_ERROR_INVALID_STATE DTLS connection was not initialized.
|
||||
*
|
||||
*/
|
||||
otError otCoapSecureSendRequestBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP request over secure DTLS connection.
|
||||
*
|
||||
@@ -269,6 +298,24 @@ void otCoapSecureAddResource(otInstance *aInstance, otCoapResource *aResource);
|
||||
*/
|
||||
void otCoapSecureRemoveResource(otInstance *aInstance, otCoapResource *aResource);
|
||||
|
||||
/**
|
||||
* This function adds a block-wise resource to the CoAP Secure server.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aResource A pointer to the resource.
|
||||
*
|
||||
*/
|
||||
void otCoapSecureAddBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
|
||||
|
||||
/**
|
||||
* This function removes a block-wise resource from the CoAP Secure server.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aResource A pointer to the resource.
|
||||
*
|
||||
*/
|
||||
void otCoapSecureRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
|
||||
|
||||
/**
|
||||
* This function sets the default handler for unhandled CoAP Secure requests.
|
||||
*
|
||||
@@ -292,6 +339,28 @@ void otCoapSecureSetClientConnectedCallback(otInstance * aIns
|
||||
otHandleCoapSecureClientConnect aHandler,
|
||||
void * aContext);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response block-wise from the CoAP Secure server.
|
||||
*
|
||||
* This function is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
|
||||
* is enabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the CoAP response to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTransmitHook A function pointer that is called on Block1 request reception.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
otError otCoapSecureSendResponseBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response from the CoAP Secure server.
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (65)
|
||||
#define OPENTHREAD_API_VERSION (66)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -69,6 +69,7 @@ readonly OT_POSIX_SIM_COMMON_OPTIONS=(
|
||||
"-DOT_BORDER_AGENT=ON"
|
||||
"-DOT_BORDER_ROUTER=ON"
|
||||
"-DOT_COAP=ON"
|
||||
"-DOT_COAP_BLOCK=ON"
|
||||
"-DOT_COAP_OBSERVE=ON"
|
||||
"-DOT_COAPS=ON"
|
||||
"-DOT_COMMISSIONER=ON"
|
||||
|
||||
@@ -85,6 +85,7 @@ readonly OT_CLANG_TIDY_BUILD_OPTS=(
|
||||
'-DOT_CHANNEL_MONITOR=ON'
|
||||
'-DOT_CHILD_SUPERVISION=ON'
|
||||
'-DOT_COAP=ON'
|
||||
'-DOT_COAP_BLOCK=ON'
|
||||
'-DOT_COAP_OBSERVE=ON'
|
||||
'-DOT_COAPS=ON'
|
||||
'-DOT_COMMISSIONER=ON'
|
||||
|
||||
+20
-5
@@ -115,13 +115,18 @@ Done
|
||||
|
||||
- address: IPv6 address of the CoAP server.
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" if the response should be transferred block-wise. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
|
||||
```bash
|
||||
> coap get fdde:ad00:beef:0:2780:9423:166c:1aac test-resource
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coap get fdde:ad00:beef:0:2780:9423:166c:1aac test-resource block-1024
|
||||
Done
|
||||
```
|
||||
|
||||
### observe \<address\> \<uri-path\> \[type\]
|
||||
|
||||
This is the same a `get`, but the `Observe` parameter will be sent, set to 0 triggering a subscription request.
|
||||
@@ -176,26 +181,36 @@ Done
|
||||
|
||||
- address: IPv6 address of the CoAP server.
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- payload: CoAP request payload.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" to send blocks with random payload. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
- payload: CoAP request payload. If \[type\] is "block-<block-size>", the amount of blocks to be sent can be set here.
|
||||
|
||||
```bash
|
||||
> coap post fdde:ad00:beef:0:2780:9423:166c:1aac test-resource con payload
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coap post fdde:ad00:beef:0:2780:9423:166c:1aac test-resource block-1024 10
|
||||
Done
|
||||
```
|
||||
|
||||
### put \<address\> \<uri-path\> \[type\] \[payload\]
|
||||
|
||||
- address: IPv6 address of the CoAP server.
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- payload: CoAP request payload.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" to send blocks with random payload. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
- payload: CoAP request payload. If \[type\] is "block-<block-size>", the amount of blocks to be sent can be set here.
|
||||
|
||||
```bash
|
||||
> coap put fdde:ad00:beef:0:2780:9423:166c:1aac test-resource con payload
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coap put fdde:ad00:beef:0:2780:9423:166c:1aac test-resource block-1024 10
|
||||
Done
|
||||
```
|
||||
|
||||
### resource \[uri-path\]
|
||||
|
||||
Sets the URI path for the test resource.
|
||||
|
||||
+20
-5
@@ -163,24 +163,34 @@ Done
|
||||
### get \<uri-path\> \[type\]
|
||||
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" if the response should be transferred block-wise. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
|
||||
```bash
|
||||
> coaps get test-resource
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coaps get test-resource block-1024
|
||||
Done
|
||||
```
|
||||
|
||||
### post \<uri-path\> \[type\] \[payload\]
|
||||
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- payload: CoAPS request payload.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" to send blocks with random payload. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
- payload: CoAP request payload. If \[type\] is "block-<block-size>", the amount of blocks to be sent can be set here.
|
||||
|
||||
```bash
|
||||
> coaps post test-resource con payload
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coaps post test-resource block-1024 10
|
||||
Done
|
||||
```
|
||||
|
||||
### psk \<psk\> \<pskid\>
|
||||
|
||||
Set DTLS ciphersuite to `TLS_PSK_WITH_AES_128_CCM_8`.
|
||||
@@ -196,14 +206,19 @@ Done
|
||||
### put \<uri-path\> \[type\] \[payload\]
|
||||
|
||||
- uri-path: URI path of the resource.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default).
|
||||
- payload: CoAPS request payload.
|
||||
- type: "con" for Confirmable or "non-con" for Non-confirmable (default). Use "block-<block-size>" to send blocks with random payload. ("block-16","block-32","block-64","block-128","block-256","block-512","block-1024")
|
||||
- payload: CoAP request payload. If \[type\] is "block-<block-size>", the amount of blocks to be sent can be set here.
|
||||
|
||||
```bash
|
||||
> coaps put test-resource con payload
|
||||
Done
|
||||
```
|
||||
|
||||
```bash
|
||||
> coaps put test-resource block-1024 10
|
||||
Done
|
||||
```
|
||||
|
||||
### resource \[uri-path\]
|
||||
|
||||
Sets the URI path for the test resource.
|
||||
|
||||
+251
-15
@@ -35,6 +35,8 @@
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_API_ENABLE
|
||||
|
||||
#include <openthread/random_noncrypto.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cli/cli.hpp"
|
||||
@@ -60,6 +62,9 @@ Coap::Coap(Interpreter &aInterpreter)
|
||||
, mSubscriberTokenLength(0)
|
||||
, mSubscriberConfirmableNotifications(false)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
, mBlockCount(1)
|
||||
#endif
|
||||
{
|
||||
memset(&mResource, 0, sizeof(mResource));
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
@@ -180,8 +185,22 @@ otError Coap::ProcessResource(uint8_t aArgsLength, char *aArgs[])
|
||||
mResource.mContext = this;
|
||||
mResource.mHandler = &Coap::HandleRequest;
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
mResource.mReceiveHook = &Coap::BlockwiseReceiveHook;
|
||||
mResource.mTransmitHook = &Coap::BlockwiseTransmitHook;
|
||||
|
||||
if (aArgsLength > 2)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[2], mBlockCount));
|
||||
}
|
||||
#endif
|
||||
|
||||
strncpy(mUriPath, aArgs[1], sizeof(mUriPath) - 1);
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapAddBlockWiseResource(mInterpreter.mInstance, &mResource);
|
||||
#else
|
||||
otCoapAddResource(mInterpreter.mInstance, &mResource);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -267,7 +286,11 @@ otError Coap::ProcessStop(uint8_t aArgsLength, char *aArgs[])
|
||||
OT_UNUSED_VARIABLE(aArgsLength);
|
||||
OT_UNUSED_VARIABLE(aArgs);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapRemoveBlockWiseResource(mInterpreter.mInstance, &mResource);
|
||||
#else
|
||||
otCoapRemoveResource(mInterpreter.mInstance, &mResource);
|
||||
#endif
|
||||
|
||||
return otCoapStop(mInterpreter.mInstance);
|
||||
}
|
||||
@@ -348,6 +371,11 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
bool coapObserve = false;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
bool coapBlock = false;
|
||||
otCoapBlockSzx coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
|
||||
ot::Coap::Message::BlockType coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
|
||||
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
@@ -355,6 +383,9 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
if (strcmp(aArgs[0], "get") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_GET;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType2;
|
||||
#endif
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
else if (strcmp(aArgs[0], "observe") == 0)
|
||||
@@ -367,10 +398,16 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
else if (strcmp(aArgs[0], "post") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_POST;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(aArgs[0], "put") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_PUT;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(aArgs[0], "delete") == 0)
|
||||
{
|
||||
@@ -409,6 +446,50 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
else if (strcmp(aArgs[3], "block-16") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-32") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_32;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-64") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_64;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-128") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_128;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-256") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_256;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-512") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_512;
|
||||
}
|
||||
else if (strcmp(aArgs[3], "block-1024") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_1024;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
@@ -434,14 +515,39 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
if (coapBlockType == ot::Coap::Message::kBlockType1)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock1Option(message, 0, true, coapBlockSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock2Option(message, 0, false, coapBlockSize));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aArgsLength > 4)
|
||||
{
|
||||
payloadLength = static_cast<uint16_t>(strlen(aArgs[4]));
|
||||
|
||||
if (payloadLength > 0)
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[4], mBlockCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
payloadLength = static_cast<uint16_t>(strlen(aArgs[4]));
|
||||
|
||||
if (payloadLength > 0)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Embed content into message if given
|
||||
@@ -468,8 +574,25 @@ otError Coap::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
|
||||
{
|
||||
error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleResponse,
|
||||
this, GetRequestTxParameters());
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
if (coapCode == OT_COAP_CODE_PUT || coapCode == OT_COAP_CODE_POST)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
|
||||
}
|
||||
error = otCoapSendRequestBlockWiseWithParameters(mInterpreter.mInstance, message, &messageInfo,
|
||||
&Coap::HandleResponse, this, GetRequestTxParameters(),
|
||||
Coap::BlockwiseTransmitHook, Coap::BlockwiseReceiveHook);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo,
|
||||
&Coap::HandleResponse, this, GetRequestTxParameters());
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -514,8 +637,14 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
otMessage *responseMessage = nullptr;
|
||||
otCoapCode responseCode = OT_COAP_CODE_EMPTY;
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
uint64_t observe = 0;
|
||||
bool observePresent = false;
|
||||
uint64_t observe = 0;
|
||||
bool observePresent = false;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint64_t blockValue = 0;
|
||||
bool blockPresent = false;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE || OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
otCoapOptionIterator iterator;
|
||||
#endif
|
||||
|
||||
@@ -527,15 +656,24 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
case OT_COAP_CODE_GET:
|
||||
mInterpreter.OutputFormat("GET");
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE || OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
SuccessOrExit(error = otCoapOptionIteratorInit(&iterator, aMessage));
|
||||
if (otCoapOptionIteratorGetFirstOptionMatching(&iterator, OT_COAP_OPTION_OBSERVE) != nullptr)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
if (otCoapOptionIteratorGetFirstOptionMatching(&iterator, OT_COAP_OPTION_OBSERVE) != NULL)
|
||||
{
|
||||
SuccessOrExit(error = otCoapOptionIteratorGetOptionUintValue(&iterator, &observe));
|
||||
observePresent = true;
|
||||
|
||||
mInterpreter.OutputFormat(" OBS=%lu", static_cast<uint32_t>(observe));
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (otCoapOptionIteratorGetFirstOptionMatching(&iterator, OT_COAP_OPTION_BLOCK2) != nullptr)
|
||||
{
|
||||
SuccessOrExit(error = otCoapOptionIteratorGetOptionUintValue(&iterator, &blockValue));
|
||||
blockPresent = true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -626,13 +764,40 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
SuccessOrExit(error = otCoapMessageAppendObserveOption(responseMessage, mObserveSerial++));
|
||||
}
|
||||
#endif
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
|
||||
SuccessOrExit(error = otMessageAppend(responseMessage, mResourceContent,
|
||||
static_cast<uint16_t>(strlen(mResourceContent))));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (blockPresent)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock2Option(responseMessage,
|
||||
static_cast<uint32_t>(blockValue >> 4), true,
|
||||
static_cast<otCoapBlockSzx>(blockValue & 0x7)));
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
|
||||
SuccessOrExit(error = otMessageAppend(responseMessage, mResourceContent,
|
||||
static_cast<uint16_t>(strlen(mResourceContent))));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otCoapSendResponseWithParameters(mInterpreter.mInstance, responseMessage, aMessageInfo,
|
||||
GetResponseTxParameters()));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (blockPresent)
|
||||
{
|
||||
SuccessOrExit(error = otCoapSendResponseBlockWiseWithParameters(mInterpreter.mInstance, responseMessage,
|
||||
aMessageInfo, GetResponseTxParameters(),
|
||||
this, mResource.mTransmitHook));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
SuccessOrExit(error = otCoapSendResponseWithParameters(mInterpreter.mInstance, responseMessage,
|
||||
aMessageInfo, GetResponseTxParameters()));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -726,6 +891,77 @@ void Coap::HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError Coap::BlockwiseReceiveHook(void * aContext,
|
||||
const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength)
|
||||
{
|
||||
return static_cast<Coap *>(aContext)->BlockwiseReceiveHook(aBlock, aPosition, aBlockLength, aMore, aTotalLength);
|
||||
}
|
||||
|
||||
otError Coap::BlockwiseReceiveHook(const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMore);
|
||||
OT_UNUSED_VARIABLE(aTotalLength);
|
||||
|
||||
mInterpreter.OutputLine("received block: Num %i Len %i", aPosition / aBlockLength, aBlockLength);
|
||||
|
||||
for (uint16_t i = 0; i < aBlockLength / 16; i++)
|
||||
{
|
||||
mInterpreter.OutputBytes(&aBlock[i * 16], 16);
|
||||
mInterpreter.OutputLine("");
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError Coap::BlockwiseTransmitHook(void * aContext,
|
||||
uint8_t * aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t *aBlockLength,
|
||||
bool * aMore)
|
||||
{
|
||||
return static_cast<Coap *>(aContext)->BlockwiseTransmitHook(aBlock, aPosition, aBlockLength, aMore);
|
||||
}
|
||||
|
||||
otError Coap::BlockwiseTransmitHook(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore)
|
||||
{
|
||||
static uint32_t blockCount = 0;
|
||||
OT_UNUSED_VARIABLE(aPosition);
|
||||
|
||||
// Send a random payload
|
||||
otRandomNonCryptoFillBuffer(aBlock, *aBlockLength);
|
||||
|
||||
mInterpreter.OutputLine("send block: Num %i Len %i", blockCount, *aBlockLength);
|
||||
|
||||
for (uint16_t i = 0; i < *aBlockLength / 16; i++)
|
||||
{
|
||||
mInterpreter.OutputBytes(&aBlock[i * 16], 16);
|
||||
mInterpreter.OutputLine("");
|
||||
}
|
||||
|
||||
if (blockCount == mBlockCount - 1)
|
||||
{
|
||||
blockCount = 0;
|
||||
*aMore = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*aMore = true;
|
||||
blockCount++;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -115,6 +115,27 @@ private:
|
||||
static void HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
void HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
static otError BlockwiseReceiveHook(void * aContext,
|
||||
const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength);
|
||||
otError BlockwiseReceiveHook(const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength);
|
||||
static otError BlockwiseTransmitHook(void * aContext,
|
||||
uint8_t * aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t *aBlockLength,
|
||||
bool * aMore);
|
||||
otError BlockwiseTransmitHook(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore);
|
||||
#endif
|
||||
|
||||
const otCoapTxParameters *GetRequestTxParameters(void) const
|
||||
{
|
||||
return mUseDefaultRequestTxParameters ? nullptr : &mRequestTxParameters;
|
||||
@@ -154,7 +175,11 @@ private:
|
||||
otCoapTxParameters mRequestTxParameters;
|
||||
otCoapTxParameters mResponseTxParameters;
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapBlockwiseResource mResource;
|
||||
#else
|
||||
otCoapResource mResource;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
otIp6Address mRequestAddr;
|
||||
otSockAddr mSubscriberSock;
|
||||
@@ -170,6 +195,9 @@ private:
|
||||
uint8_t mSubscriberTokenLength;
|
||||
bool mSubscriberConfirmableNotifications;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint32_t mBlockCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Cli
|
||||
|
||||
+241
-10
@@ -37,6 +37,7 @@
|
||||
|
||||
#include <mbedtls/debug.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/random_noncrypto.h>
|
||||
|
||||
#include "cli/cli.hpp"
|
||||
#include "utils/parse_cmdline.hpp"
|
||||
@@ -46,6 +47,7 @@
|
||||
|
||||
using ot::Utils::CmdLineParser::ParseAsIp6Address;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint16;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint32;
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
@@ -58,6 +60,9 @@ CoapSecure::CoapSecure(Interpreter &aInterpreter)
|
||||
, mUseCertificate(false)
|
||||
, mPskLength(0)
|
||||
, mPskIdLength(0)
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
, mBlockCount(1)
|
||||
#endif
|
||||
{
|
||||
memset(&mResource, 0, sizeof(mResource));
|
||||
memset(&mPsk, 0, sizeof(mPsk));
|
||||
@@ -117,8 +122,22 @@ otError CoapSecure::ProcessResource(uint8_t aArgsLength, char *aArgs[])
|
||||
mResource.mContext = this;
|
||||
mResource.mHandler = &CoapSecure::HandleRequest;
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
mResource.mReceiveHook = &CoapSecure::BlockwiseReceiveHook;
|
||||
mResource.mTransmitHook = &CoapSecure::BlockwiseTransmitHook;
|
||||
|
||||
if (aArgsLength > 2)
|
||||
{
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[2], mBlockCount));
|
||||
}
|
||||
#endif
|
||||
|
||||
strncpy(mUriPath, aArgs[1], sizeof(mUriPath) - 1);
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapSecureAddBlockWiseResource(mInterpreter.mInstance, &mResource);
|
||||
#else
|
||||
otCoapSecureAddResource(mInterpreter.mInstance, &mResource);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,7 +202,11 @@ otError CoapSecure::ProcessStop(uint8_t aArgsLength, char *aArgs[])
|
||||
OT_UNUSED_VARIABLE(aArgsLength);
|
||||
OT_UNUSED_VARIABLE(aArgs);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapRemoveBlockWiseResource(mInterpreter.mInstance, &mResource);
|
||||
#else
|
||||
otCoapRemoveResource(mInterpreter.mInstance, &mResource);
|
||||
#endif
|
||||
|
||||
if (otCoapSecureIsConnectionActive(mInterpreter.mInstance))
|
||||
{
|
||||
@@ -211,6 +234,11 @@ otError CoapSecure::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
otCoapType coapType = OT_COAP_TYPE_NON_CONFIRMABLE;
|
||||
otCoapCode coapCode = OT_COAP_CODE_GET;
|
||||
otIp6Address coapDestinationIp;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
bool coapBlock = false;
|
||||
otCoapBlockSzx coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
|
||||
ot::Coap::Message::BlockType coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
|
||||
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
@@ -218,14 +246,23 @@ otError CoapSecure::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
if (strcmp(aArgs[0], "get") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_GET;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType2;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(aArgs[0], "post") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_POST;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(aArgs[0], "put") == 0)
|
||||
{
|
||||
coapCode = OT_COAP_CODE_PUT;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
coapBlockType = ot::Coap::Message::kBlockType1;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(aArgs[0], "delete") == 0)
|
||||
{
|
||||
@@ -270,6 +307,50 @@ otError CoapSecure::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-16") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-32") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_32;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-64") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_64;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-128") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_128;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-256") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_256;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-512") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_512;
|
||||
}
|
||||
else if (strcmp(aArgs[3 - indexShifter], "block-1024") == 0)
|
||||
{
|
||||
coapType = OT_COAP_TYPE_CONFIRMABLE;
|
||||
coapBlock = true;
|
||||
coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_1024;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
|
||||
message = otCoapNewMessage(mInterpreter.mInstance, nullptr);
|
||||
@@ -279,14 +360,39 @@ otError CoapSecure::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
otCoapMessageGenerateToken(message, OT_COAP_DEFAULT_TOKEN_LENGTH);
|
||||
SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
if (coapBlockType == ot::Coap::Message::kBlockType1)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock1Option(message, 0, true, coapBlockSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock2Option(message, 0, false, coapBlockSize));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aArgsLength > (4 - indexShifter))
|
||||
{
|
||||
payloadLength = static_cast<uint16_t>(strlen(aArgs[4 - indexShifter]));
|
||||
|
||||
if (payloadLength > 0)
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[4 - indexShifter], mBlockCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
payloadLength = static_cast<uint16_t>(strlen(aArgs[4 - indexShifter]));
|
||||
|
||||
if (payloadLength > 0)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// add payload
|
||||
@@ -301,7 +407,20 @@ otError CoapSecure::ProcessRequest(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
|
||||
{
|
||||
error = otCoapSecureSendRequest(mInterpreter.mInstance, message, &CoapSecure::HandleResponse, this);
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (coapBlock)
|
||||
{
|
||||
error =
|
||||
otCoapSecureSendRequestBlockWise(mInterpreter.mInstance, message, &CoapSecure::HandleResponse, this,
|
||||
&CoapSecure::BlockwiseTransmitHook, &CoapSecure::BlockwiseReceiveHook);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
error = otCoapSecureSendRequest(mInterpreter.mInstance, message, &CoapSecure::HandleResponse, this);
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -415,7 +534,11 @@ exit:
|
||||
|
||||
void CoapSecure::Stop(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapRemoveBlockWiseResource(mInterpreter.mInstance, &mResource);
|
||||
#else
|
||||
otCoapRemoveResource(mInterpreter.mInstance, &mResource);
|
||||
#endif
|
||||
otCoapSecureStop(mInterpreter.mInstance);
|
||||
}
|
||||
|
||||
@@ -452,6 +575,11 @@ void CoapSecure::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessag
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMessage *responseMessage = nullptr;
|
||||
otCoapCode responseCode = OT_COAP_CODE_EMPTY;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint64_t blockValue = 0;
|
||||
bool blockPresent = false;
|
||||
otCoapOptionIterator iterator;
|
||||
#endif
|
||||
|
||||
mInterpreter.OutputFormat("coaps request from ");
|
||||
mInterpreter.OutputIp6Address(aMessageInfo->mPeerAddr);
|
||||
@@ -461,6 +589,14 @@ void CoapSecure::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessag
|
||||
{
|
||||
case OT_COAP_CODE_GET:
|
||||
mInterpreter.OutputFormat("GET");
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
SuccessOrExit(error = otCoapOptionIteratorInit(&iterator, aMessage));
|
||||
if (otCoapOptionIteratorGetFirstOptionMatching(&iterator, OT_COAP_OPTION_BLOCK2) != nullptr)
|
||||
{
|
||||
SuccessOrExit(error = otCoapOptionIteratorGetOptionUintValue(&iterator, &blockValue));
|
||||
blockPresent = true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OT_COAP_CODE_DELETE:
|
||||
@@ -502,16 +638,39 @@ void CoapSecure::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessag
|
||||
|
||||
if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (blockPresent)
|
||||
{
|
||||
SuccessOrExit(error = otCoapMessageAppendBlock2Option(responseMessage,
|
||||
static_cast<uint32_t>(blockValue >> 4), true,
|
||||
static_cast<otCoapBlockSzx>(blockValue & 0x7)));
|
||||
}
|
||||
#endif
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (!blockPresent)
|
||||
{
|
||||
#endif
|
||||
SuccessOrExit(error = otMessageAppend(responseMessage, &mResourceContent,
|
||||
static_cast<uint16_t>(strlen(mResourceContent))));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
if (blockPresent)
|
||||
{
|
||||
SuccessOrExit(error = otMessageAppend(responseMessage, &mResourceContent,
|
||||
static_cast<uint16_t>(strlen(mResourceContent))));
|
||||
SuccessOrExit(error = otCoapSecureSendResponseBlockWise(mInterpreter.mInstance, responseMessage,
|
||||
aMessageInfo, this, mResource.mTransmitHook));
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
|
||||
else
|
||||
{
|
||||
#endif
|
||||
SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -583,6 +742,78 @@ exit:
|
||||
}
|
||||
#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError CoapSecure::BlockwiseReceiveHook(void * aContext,
|
||||
const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength)
|
||||
{
|
||||
return static_cast<CoapSecure *>(aContext)->BlockwiseReceiveHook(aBlock, aPosition, aBlockLength, aMore,
|
||||
aTotalLength);
|
||||
}
|
||||
|
||||
otError CoapSecure::BlockwiseReceiveHook(const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aMore);
|
||||
OT_UNUSED_VARIABLE(aTotalLength);
|
||||
|
||||
mInterpreter.OutputLine("received block: Num %i Len %i", aPosition / aBlockLength, aBlockLength);
|
||||
|
||||
for (uint16_t i = 0; i < aBlockLength / 16; i++)
|
||||
{
|
||||
mInterpreter.OutputBytes(&aBlock[i * 16], 16);
|
||||
mInterpreter.OutputLine("");
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError CoapSecure::BlockwiseTransmitHook(void * aContext,
|
||||
uint8_t * aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t *aBlockLength,
|
||||
bool * aMore)
|
||||
{
|
||||
return static_cast<CoapSecure *>(aContext)->BlockwiseTransmitHook(aBlock, aPosition, aBlockLength, aMore);
|
||||
}
|
||||
|
||||
otError CoapSecure::BlockwiseTransmitHook(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore)
|
||||
{
|
||||
static uint32_t blockCount = 0;
|
||||
OT_UNUSED_VARIABLE(aPosition);
|
||||
|
||||
// Send a random payload
|
||||
otRandomNonCryptoFillBuffer(aBlock, *aBlockLength);
|
||||
|
||||
mInterpreter.OutputLine("send block: Num %i Len %i", blockCount, *aBlockLength);
|
||||
|
||||
for (uint16_t i = 0; i < *aBlockLength / 16; i++)
|
||||
{
|
||||
mInterpreter.OutputBytes(&aBlock[i * 16], 16);
|
||||
mInterpreter.OutputLine("");
|
||||
}
|
||||
|
||||
if (blockCount == mBlockCount - 1)
|
||||
{
|
||||
blockCount = 0;
|
||||
*aMore = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*aMore = true;
|
||||
blockCount++;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -111,6 +111,27 @@ private:
|
||||
static void HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
void HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
static otError BlockwiseReceiveHook(void * aContext,
|
||||
const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength);
|
||||
otError BlockwiseReceiveHook(const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength);
|
||||
static otError BlockwiseTransmitHook(void * aContext,
|
||||
uint8_t * aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t *aBlockLength,
|
||||
bool * aMore);
|
||||
otError BlockwiseTransmitHook(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore);
|
||||
#endif
|
||||
|
||||
#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
|
||||
static void DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
void DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
@@ -143,9 +164,13 @@ private:
|
||||
|
||||
Interpreter &mInterpreter;
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapBlockwiseResource mResource;
|
||||
#else
|
||||
otCoapResource mResource;
|
||||
char mUriPath[kMaxUriLength];
|
||||
char mResourceContent[kMaxBufferSize];
|
||||
#endif
|
||||
char mUriPath[kMaxUriLength];
|
||||
char mResourceContent[kMaxBufferSize];
|
||||
|
||||
bool mShutdownFlag;
|
||||
bool mUseCertificate;
|
||||
@@ -153,6 +178,9 @@ private:
|
||||
uint8_t mPskLength;
|
||||
uint8_t mPskId[kPskIdMaxLength];
|
||||
uint8_t mPskIdLength;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint32_t mBlockCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Cli
|
||||
|
||||
@@ -101,18 +101,18 @@ otError otCoapMessageAppendUriPathOptions(otMessage *aMessage, const char *aUriP
|
||||
return static_cast<Coap::Message *>(aMessage)->AppendUriPathOptions(aUriPath);
|
||||
}
|
||||
|
||||
uint16_t otCoapBlockSizeFromExponent(otCoapBlockSize aSize)
|
||||
uint16_t otCoapBlockSizeFromExponent(otCoapBlockSzx aSize)
|
||||
{
|
||||
return static_cast<uint16_t>(
|
||||
1 << (static_cast<uint8_t>(aSize) + static_cast<uint8_t>(Coap::Message::kBlockSzxBase)));
|
||||
}
|
||||
|
||||
otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSize aSize)
|
||||
otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
|
||||
{
|
||||
return static_cast<Coap::Message *>(aMessage)->AppendBlockOption(Coap::Message::kBlockType2, aNum, aMore, aSize);
|
||||
}
|
||||
|
||||
otError otCoapMessageAppendBlock1Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSize aSize)
|
||||
otError otCoapMessageAppendBlock1Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
|
||||
{
|
||||
return static_cast<Coap::Message *>(aMessage)->AppendBlockOption(Coap::Message::kBlockType1, aNum, aMore, aSize);
|
||||
}
|
||||
@@ -214,6 +214,34 @@ otError otCoapOptionIteratorGetOptionValue(otCoapOptionIterator *aIterator, void
|
||||
return static_cast<Coap::Option::Iterator *>(aIterator)->ReadOptionValue(aValue);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError otCoapSendRequestBlockWiseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
const otCoapTxParameters * aTxParameters,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
{
|
||||
otError error;
|
||||
Instance & instance = *static_cast<Instance *>(aInstance);
|
||||
const Coap::TxParameters &txParameters = Coap::TxParameters::From(aTxParameters);
|
||||
|
||||
if (aTxParameters != nullptr)
|
||||
{
|
||||
VerifyOrExit(txParameters.IsValid(), error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
error = instance.GetApplicationCoap().SendMessage(*static_cast<Coap::Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
txParameters, aHandler, aContext, aTransmitHook, aReceiveHook);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
otError otCoapSendRequestWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
@@ -252,6 +280,22 @@ otError otCoapStop(otInstance *aInstance)
|
||||
return instance.GetApplicationCoap().Stop();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
void otCoapAddBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
instance.GetApplicationCoap().AddBlockWiseResource(*static_cast<Coap::ResourceBlockWise *>(aResource));
|
||||
}
|
||||
|
||||
void otCoapRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
instance.GetApplicationCoap().RemoveBlockWiseResource(*static_cast<Coap::ResourceBlockWise *>(aResource));
|
||||
}
|
||||
#endif
|
||||
|
||||
void otCoapAddResource(otInstance *aInstance, otCoapResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
@@ -273,6 +317,22 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle
|
||||
instance.GetApplicationCoap().SetDefaultHandler(aHandler, aContext);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError otCoapSendResponseBlockWiseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
const otCoapTxParameters * aTxParameters,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetApplicationCoap().SendMessage(
|
||||
*static_cast<Coap::Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
Coap::TxParameters::From(aTxParameters), nullptr, aContext, aTransmitHook, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
otError otCoapSendResponseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
|
||||
@@ -151,6 +151,21 @@ void otCoapSecureStop(otInstance *aInstance)
|
||||
instance.GetApplicationCoapSecure().Stop();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError otCoapSecureSendRequestBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetApplicationCoapSecure().SendMessage(*static_cast<Coap::Message *>(aMessage), aHandler, aContext,
|
||||
aTransmitHook, aReceiveHook);
|
||||
}
|
||||
#endif
|
||||
|
||||
otError otCoapSecureSendRequest(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
otCoapResponseHandler aHandler,
|
||||
@@ -161,6 +176,22 @@ otError otCoapSecureSendRequest(otInstance * aInstance,
|
||||
return instance.GetApplicationCoapSecure().SendMessage(*static_cast<Coap::Message *>(aMessage), aHandler, aContext);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
void otCoapSecureAddBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
instance.GetApplicationCoapSecure().AddBlockWiseResource(*static_cast<Coap::ResourceBlockWise *>(aResource));
|
||||
}
|
||||
|
||||
void otCoapSecureRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
instance.GetApplicationCoapSecure().RemoveBlockWiseResource(*static_cast<Coap::ResourceBlockWise *>(aResource));
|
||||
}
|
||||
#endif
|
||||
|
||||
void otCoapSecureAddResource(otInstance *aInstance, otCoapResource *aResource)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
@@ -191,6 +222,21 @@ void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler a
|
||||
instance.GetApplicationCoapSecure().SetDefaultHandler(aHandler, aContext);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError otCoapSecureSendResponseBlockWise(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetApplicationCoapSecure().SendMessage(*static_cast<Coap::Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
nullptr, aContext, aTransmitHook);
|
||||
}
|
||||
#endif
|
||||
|
||||
otError otCoapSecureSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
@@ -56,6 +56,9 @@ CoapBase::CoapBase(Instance &aInstance, Sender aSender)
|
||||
, mDefaultHandler(nullptr)
|
||||
, mDefaultHandlerContext(nullptr)
|
||||
, mSender(aSender)
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
, mLastResponse(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -88,6 +91,19 @@ void CoapBase::ClearRequests(const Ip6::Address *aAddress)
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
void CoapBase::AddBlockWiseResource(ResourceBlockWise &aResource)
|
||||
{
|
||||
IgnoreError(mBlockWiseResources.Add(aResource));
|
||||
}
|
||||
|
||||
void CoapBase::RemoveBlockWiseResource(ResourceBlockWise &aResource)
|
||||
{
|
||||
IgnoreError(mBlockWiseResources.Remove(aResource));
|
||||
aResource.SetNext(nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CoapBase::AddResource(Resource &aResource)
|
||||
{
|
||||
IgnoreError(mResources.Add(aResource));
|
||||
@@ -141,25 +157,76 @@ otError CoapBase::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError CoapBase::SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const TxParameters & aTxParameters,
|
||||
ResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
#else
|
||||
otError CoapBase::SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const TxParameters & aTxParameters,
|
||||
ResponseHandler aHandler,
|
||||
void * aContext)
|
||||
#endif
|
||||
{
|
||||
otError error;
|
||||
Message *storedCopy = nullptr;
|
||||
uint16_t copyLength = 0;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint8_t buf[kMaxBlockLength] = {0};
|
||||
uint16_t bufLen = kMaxBlockLength;
|
||||
bool moreBlocks = false;
|
||||
#endif
|
||||
|
||||
switch (aMessage.GetType())
|
||||
{
|
||||
case kTypeAck:
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
// Check for block-wise transfer
|
||||
if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock2) == OT_ERROR_NONE) &&
|
||||
(aMessage.GetBlockWiseBlockNumber() == 0))
|
||||
{
|
||||
// Set payload for first block of the transfer
|
||||
VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
|
||||
&moreBlocks));
|
||||
SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
|
||||
|
||||
SuccessOrExit(error = CacheLastBlockResponse(&aMessage));
|
||||
}
|
||||
#endif
|
||||
|
||||
mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo, aTxParameters);
|
||||
break;
|
||||
case kTypeReset:
|
||||
OT_ASSERT(aMessage.GetCode() == kCodeEmpty);
|
||||
break;
|
||||
default:
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
// Check for block-wise transfer
|
||||
if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock1) == OT_ERROR_NONE) &&
|
||||
(aMessage.GetBlockWiseBlockNumber() == 0))
|
||||
{
|
||||
// Set payload for first block of the transfer
|
||||
VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
|
||||
&moreBlocks));
|
||||
SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
|
||||
|
||||
// Block-Wise messages always have to be confirmable
|
||||
if (aMessage.IsNonConfirmable())
|
||||
{
|
||||
aMessage.SetType(kTypeConfirmable);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
aMessage.SetMessageId(mMessageId++);
|
||||
break;
|
||||
}
|
||||
@@ -228,6 +295,10 @@ otError CoapBase::SendMessage(Message & aMessage,
|
||||
metadata.mHopLimit = aMessageInfo.GetHopLimit();
|
||||
metadata.mIsHostInterface = aMessageInfo.IsHostInterface();
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
metadata.mBlockwiseReceiveHook = aReceiveHook;
|
||||
metadata.mBlockwiseTransmitHook = aTransmitHook;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
metadata.mObserve = observe;
|
||||
#endif
|
||||
@@ -256,7 +327,11 @@ otError CoapBase::SendMessage(Message & aMessage,
|
||||
ResponseHandler aHandler,
|
||||
void * aContext)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext, nullptr, nullptr);
|
||||
#else
|
||||
return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
otError CoapBase::SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
|
||||
@@ -470,6 +545,402 @@ void CoapBase::DequeueMessage(Message &aMessage)
|
||||
// the timer would just shoot earlier and then it'd be setup again.
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
void CoapBase::FreeLastBlockResponse(void)
|
||||
{
|
||||
if (mLastResponse != nullptr)
|
||||
{
|
||||
mLastResponse->Free();
|
||||
mLastResponse = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
otError CoapBase::CacheLastBlockResponse(Message *aResponse)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
// Save last response for block-wise transfer
|
||||
FreeLastBlockResponse();
|
||||
|
||||
if ((mLastResponse = aResponse->Clone()) == nullptr)
|
||||
{
|
||||
error = OT_ERROR_NO_BUFS;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
|
||||
bool aMoreBlocks,
|
||||
Message & aRequestOld,
|
||||
Message & aRequest,
|
||||
Message & aMessage)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool isOptionSet = false;
|
||||
uint64_t optionBuf = 0;
|
||||
uint16_t blockOption = 0;
|
||||
Option::Iterator iterator;
|
||||
|
||||
blockOption = (aType == Message::kBlockType1) ? kOptionBlock1 : kOptionBlock2;
|
||||
|
||||
aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.GetCode()));
|
||||
SuccessOrExit(error = iterator.Init(aRequestOld));
|
||||
|
||||
// Copy options from last response to next message
|
||||
for (; !iterator.IsDone() && iterator.GetOption()->GetLength() != 0; error = iterator.Advance())
|
||||
{
|
||||
uint16_t optionNumber = iterator.GetOption()->GetNumber();
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
// Check if option to copy next is higher than or equal to Block1 option
|
||||
if (optionNumber >= blockOption && !isOptionSet)
|
||||
{
|
||||
// Write Block1 option to next message
|
||||
SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
|
||||
aMessage.GetBlockWiseBlockSize()));
|
||||
aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
|
||||
aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
|
||||
aRequest.SetMoreBlocksFlag(aMoreBlocks);
|
||||
|
||||
isOptionSet = true;
|
||||
|
||||
// If option to copy next is Block1 or Block2 option, option is not copied
|
||||
if (optionNumber == kOptionBlock1 || optionNumber == kOptionBlock2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy option
|
||||
SuccessOrExit(error = iterator.ReadOptionValue(&optionBuf));
|
||||
SuccessOrExit(error = aRequest.AppendOption(optionNumber, iterator.GetOption()->GetLength(), &optionBuf));
|
||||
}
|
||||
|
||||
if (!isOptionSet)
|
||||
{
|
||||
// Write Block1 option to next message
|
||||
SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
|
||||
aMessage.GetBlockWiseBlockSize()));
|
||||
aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
|
||||
aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
|
||||
aRequest.SetMoreBlocksFlag(aMoreBlocks);
|
||||
|
||||
isOptionSet = true;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapBase::SendNextBlock1Request(Message & aRequest,
|
||||
Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const Metadata & aCoapMetadata)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message *request = nullptr;
|
||||
bool moreBlocks = false;
|
||||
uint8_t buf[kMaxBlockLength] = {0};
|
||||
uint16_t bufLen = kMaxBlockLength;
|
||||
|
||||
SuccessOrExit(error = aRequest.ReadBlockOptionValues(kOptionBlock1));
|
||||
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
|
||||
|
||||
// Conclude block-wise transfer if last block has been received
|
||||
if (!aRequest.IsMoreBlocksFlagSet())
|
||||
{
|
||||
FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, OT_ERROR_NONE);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Get next block
|
||||
VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
|
||||
SuccessOrExit(
|
||||
error = aCoapMetadata.mBlockwiseTransmitHook(aCoapMetadata.mResponseContext, buf,
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
|
||||
(aMessage.GetBlockWiseBlockNumber() + 1),
|
||||
&bufLen, &moreBlocks));
|
||||
|
||||
// Check if block length is valid
|
||||
VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
// Init request for next block
|
||||
VerifyOrExit((request = NewMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType1, moreBlocks, aRequest, *request, aMessage));
|
||||
|
||||
SuccessOrExit(error = request->SetPayloadMarker());
|
||||
|
||||
SuccessOrExit(error = request->AppendBytes(buf, bufLen));
|
||||
|
||||
DequeueMessage(aRequest);
|
||||
|
||||
otLogInfoCoap("Send Block1 Nr. %d, Size: %d bytes, More Blocks Flag: %d", request->GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()), request->IsMoreBlocksFlagSet());
|
||||
|
||||
SuccessOrExit(error = SendMessage(*request, aMessageInfo, TxParameters::GetDefault(),
|
||||
aCoapMetadata.mResponseHandler, aCoapMetadata.mResponseContext,
|
||||
aCoapMetadata.mBlockwiseTransmitHook, aCoapMetadata.mBlockwiseReceiveHook));
|
||||
|
||||
exit:
|
||||
FreeMessageOnError(request, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapBase::SendNextBlock2Request(Message & aRequest,
|
||||
Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const Metadata & aCoapMetadata,
|
||||
uint32_t aTotalLength,
|
||||
bool aBeginBlock1Transfer)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message *request = nullptr;
|
||||
uint8_t buf[kMaxBlockLength] = {0};
|
||||
uint16_t bufLen = kMaxBlockLength;
|
||||
|
||||
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
|
||||
|
||||
// Check payload and block length
|
||||
VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <=
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) &&
|
||||
(aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
|
||||
// Read and then forward payload to receive hook function
|
||||
bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
|
||||
SuccessOrExit(
|
||||
error = aCoapMetadata.mBlockwiseReceiveHook(aCoapMetadata.mResponseContext, buf,
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
|
||||
aMessage.GetBlockWiseBlockNumber(),
|
||||
bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
|
||||
|
||||
// CoAP Block-Wise Transfer continues
|
||||
otLogInfoCoap("Received Block2 Nr. %d , Size: %d bytes, More Blocks Flag: %d", aMessage.GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), aMessage.IsMoreBlocksFlagSet());
|
||||
|
||||
// Conclude block-wise transfer if last block has been received
|
||||
if (!aMessage.IsMoreBlocksFlagSet())
|
||||
{
|
||||
FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, OT_ERROR_NONE);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Init request for next block
|
||||
VerifyOrExit((request = NewMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType2, aMessage.IsMoreBlocksFlagSet(), aRequest,
|
||||
*request, aMessage));
|
||||
|
||||
if (!aBeginBlock1Transfer)
|
||||
{
|
||||
DequeueMessage(aRequest);
|
||||
}
|
||||
|
||||
otLogInfoCoap("Request Block2 Nr. %d, Size: %d bytes", request->GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()));
|
||||
|
||||
SuccessOrExit(error =
|
||||
SendMessage(*request, aMessageInfo, TxParameters::GetDefault(), aCoapMetadata.mResponseHandler,
|
||||
aCoapMetadata.mResponseContext, nullptr, aCoapMetadata.mBlockwiseReceiveHook));
|
||||
|
||||
exit:
|
||||
FreeMessageOnError(request, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapBase::ProcessBlock1Request(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const ResourceBlockWise &aResource,
|
||||
uint32_t aTotalLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message *response = nullptr;
|
||||
uint8_t buf[kMaxBlockLength] = {0};
|
||||
uint16_t bufLen = kMaxBlockLength;
|
||||
|
||||
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
|
||||
|
||||
// Read and then forward payload to receive hook function
|
||||
VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength, error = OT_ERROR_NO_BUFS);
|
||||
bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
|
||||
SuccessOrExit(error = aResource.HandleBlockReceive(buf,
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
|
||||
aMessage.GetBlockWiseBlockNumber(),
|
||||
bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
|
||||
|
||||
if (aMessage.IsMoreBlocksFlagSet())
|
||||
{
|
||||
// Set up next response
|
||||
VerifyOrExit((response = NewMessage()) != nullptr, error = OT_ERROR_FAILED);
|
||||
response->Init(kTypeAck, kCodeContinue);
|
||||
response->SetMessageId(aMessage.GetMessageId());
|
||||
IgnoreReturnValue(
|
||||
response->SetToken(static_cast<const Message &>(aMessage).GetToken(), aMessage.GetTokenLength()));
|
||||
|
||||
response->SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber());
|
||||
response->SetMoreBlocksFlag(aMessage.IsMoreBlocksFlagSet());
|
||||
response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
|
||||
|
||||
SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType1, response->GetBlockWiseBlockNumber(),
|
||||
response->IsMoreBlocksFlagSet(),
|
||||
response->GetBlockWiseBlockSize()));
|
||||
|
||||
SuccessOrExit(error = CacheLastBlockResponse(response));
|
||||
|
||||
otLogInfoCoap("Acknowledge Block1 Nr. %d, Size: %d bytes", response->GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()));
|
||||
|
||||
SuccessOrExit(error = SendMessage(*response, aMessageInfo));
|
||||
|
||||
error = OT_ERROR_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Conclude block-wise transfer if last block has been received
|
||||
FreeLastBlockResponse();
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE && error != OT_ERROR_BUSY && response != nullptr)
|
||||
{
|
||||
response->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapBase::ProcessBlock2Request(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const ResourceBlockWise &aResource)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message * response = nullptr;
|
||||
uint8_t buf[kMaxBlockLength] = {0};
|
||||
uint16_t bufLen = kMaxBlockLength;
|
||||
bool moreBlocks = false;
|
||||
uint64_t optionBuf = 0;
|
||||
Option::Iterator iterator;
|
||||
|
||||
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
|
||||
|
||||
otLogInfoCoap("Request for Block2 Nr. %d, Size: %d bytes received", aMessage.GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()));
|
||||
|
||||
if (aMessage.GetBlockWiseBlockNumber() == 0)
|
||||
{
|
||||
aResource.HandleRequest(aMessage, aMessageInfo);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Set up next response
|
||||
VerifyOrExit((response = NewMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
response->Init(kTypeAck, kCodeContent);
|
||||
response->SetMessageId(aMessage.GetMessageId());
|
||||
|
||||
VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = aResource.HandleBlockTransmit(buf,
|
||||
otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
|
||||
aMessage.GetBlockWiseBlockNumber(),
|
||||
&bufLen, &moreBlocks));
|
||||
|
||||
response->SetMoreBlocksFlag(moreBlocks);
|
||||
if (moreBlocks)
|
||||
{
|
||||
switch (bufLen)
|
||||
{
|
||||
case 1024:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_1024);
|
||||
break;
|
||||
case 512:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_512);
|
||||
break;
|
||||
case 256:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_256);
|
||||
break;
|
||||
case 128:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_128);
|
||||
break;
|
||||
case 64:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_64);
|
||||
break;
|
||||
case 32:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_32);
|
||||
break;
|
||||
case 16:
|
||||
response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_16);
|
||||
break;
|
||||
default:
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
ExitNow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Verify that buffer length is not larger than requested block size
|
||||
VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
|
||||
}
|
||||
|
||||
response->SetBlockWiseBlockNumber(
|
||||
(otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber()) /
|
||||
(otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize())));
|
||||
|
||||
// Copy options from last response
|
||||
SuccessOrExit(error = iterator.Init(*mLastResponse));
|
||||
|
||||
while (!iterator.IsDone())
|
||||
{
|
||||
uint16_t optionNumber = iterator.GetOption()->GetNumber();
|
||||
|
||||
if (optionNumber == kOptionBlock2)
|
||||
{
|
||||
SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType2, response->GetBlockWiseBlockNumber(),
|
||||
response->IsMoreBlocksFlagSet(),
|
||||
response->GetBlockWiseBlockSize()));
|
||||
}
|
||||
else if (optionNumber == kOptionBlock1)
|
||||
{
|
||||
SuccessOrExit(error = iterator.ReadOptionValue(&optionBuf));
|
||||
SuccessOrExit(error = response->AppendOption(optionNumber, iterator.GetOption()->GetLength(), &optionBuf));
|
||||
}
|
||||
|
||||
SuccessOrExit(error = iterator.Advance());
|
||||
}
|
||||
|
||||
SuccessOrExit(error = response->SetPayloadMarker());
|
||||
SuccessOrExit(error = response->AppendBytes(buf, bufLen));
|
||||
|
||||
if (response->IsMoreBlocksFlagSet())
|
||||
{
|
||||
SuccessOrExit(error = CacheLastBlockResponse(response));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Conclude block-wise transfer if last block has been received
|
||||
FreeLastBlockResponse();
|
||||
}
|
||||
|
||||
otLogInfoCoap("Send Block2 Nr. %d, Size: %d bytes, More Blocks Flag %d", response->GetBlockWiseBlockNumber(),
|
||||
otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()), response->IsMoreBlocksFlagSet());
|
||||
|
||||
SuccessOrExit(error = SendMessage(*response, aMessageInfo));
|
||||
|
||||
exit:
|
||||
FreeMessageOnError(response, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
void CoapBase::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
otError error;
|
||||
@@ -567,6 +1038,10 @@ void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
bool responseObserve = false;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
uint8_t blockOptionType = 0;
|
||||
uint32_t totalTransfereSize = 0;
|
||||
#endif
|
||||
|
||||
request = FindRelatedRequest(aMessage, aMessageInfo, metadata);
|
||||
VerifyOrExit(request != nullptr);
|
||||
@@ -642,9 +1117,89 @@ void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
{
|
||||
if (metadata.mBlockwiseTransmitHook != nullptr || metadata.mBlockwiseReceiveHook != nullptr)
|
||||
{
|
||||
// Search for CoAP Block-Wise Option [RFC7959]
|
||||
Option::Iterator iterator;
|
||||
|
||||
SuccessOrExit(error = iterator.Init(aMessage));
|
||||
while (!iterator.IsDone())
|
||||
{
|
||||
switch (iterator.GetOption()->GetNumber())
|
||||
{
|
||||
case kOptionBlock1:
|
||||
blockOptionType += 1;
|
||||
break;
|
||||
|
||||
case kOptionBlock2:
|
||||
blockOptionType += 2;
|
||||
break;
|
||||
|
||||
case kOptionSize2:
|
||||
// ToDo: wait for method to read uint option values
|
||||
totalTransfereSize = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = iterator.Advance());
|
||||
}
|
||||
}
|
||||
switch (blockOptionType)
|
||||
{
|
||||
case 0:
|
||||
// Piggybacked response.
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, OT_ERROR_NONE);
|
||||
break;
|
||||
case 1: // Block1 option
|
||||
if (aMessage.GetCode() == kCodeContinue && metadata.mBlockwiseTransmitHook != nullptr)
|
||||
{
|
||||
error = SendNextBlock1Request(*request, aMessage, aMessageInfo, metadata);
|
||||
}
|
||||
|
||||
if (aMessage.GetCode() != kCodeContinue || metadata.mBlockwiseTransmitHook == nullptr ||
|
||||
error != OT_ERROR_NONE)
|
||||
{
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
|
||||
}
|
||||
break;
|
||||
case 2: // Block2 option
|
||||
if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
|
||||
{
|
||||
error = SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransfereSize,
|
||||
false);
|
||||
}
|
||||
|
||||
if (aMessage.GetCode() >= kCodeBadRequest || metadata.mBlockwiseReceiveHook == nullptr ||
|
||||
error != OT_ERROR_NONE)
|
||||
{
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
|
||||
}
|
||||
break;
|
||||
case 3: // Block1 & Block2 option
|
||||
if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
|
||||
{
|
||||
error =
|
||||
SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransfereSize, true);
|
||||
}
|
||||
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
|
||||
break;
|
||||
default:
|
||||
error = OT_ERROR_ABORT;
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
{
|
||||
FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, OT_ERROR_NONE);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
}
|
||||
|
||||
// Silently ignore acknowledgments carrying requests (RFC 7252, p. 4.2)
|
||||
@@ -696,6 +1251,12 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo
|
||||
char uriPath[Message::kMaxReceivedUriPath + 1];
|
||||
Message *cachedResponse = nullptr;
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
Option::Iterator iterator;
|
||||
char * curUriPath = uriPath;
|
||||
uint8_t blockOptionType = 0;
|
||||
uint32_t totalTransfereSize = 0;
|
||||
#endif
|
||||
|
||||
if (mInterceptor != nullptr)
|
||||
{
|
||||
@@ -718,7 +1279,108 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo
|
||||
break;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
SuccessOrExit(error = iterator.Init(aMessage));
|
||||
|
||||
while (!iterator.IsDone())
|
||||
{
|
||||
switch (iterator.GetOption()->GetNumber())
|
||||
{
|
||||
case kOptionUriPath:
|
||||
if (curUriPath != uriPath)
|
||||
{
|
||||
*curUriPath++ = '/';
|
||||
}
|
||||
|
||||
VerifyOrExit(curUriPath + iterator.GetOption()->GetLength() < OT_ARRAY_END(uriPath),
|
||||
error = OT_ERROR_PARSE);
|
||||
|
||||
IgnoreError(iterator.ReadOptionValue(curUriPath));
|
||||
curUriPath += iterator.GetOption()->GetLength();
|
||||
break;
|
||||
|
||||
case kOptionBlock1:
|
||||
blockOptionType += 1;
|
||||
break;
|
||||
|
||||
case kOptionBlock2:
|
||||
blockOptionType += 2;
|
||||
break;
|
||||
|
||||
case kOptionSize1:
|
||||
// ToDo: wait for method to read uint option values
|
||||
totalTransfereSize = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = iterator.Advance());
|
||||
}
|
||||
|
||||
curUriPath[0] = '\0';
|
||||
|
||||
for (const ResourceBlockWise *resource = mBlockWiseResources.GetHead(); resource; resource = resource->GetNext())
|
||||
{
|
||||
if (strcmp(resource->GetUriPath(), uriPath) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((resource->mReceiveHook != nullptr || resource->mTransmitHook != nullptr) && blockOptionType != 0)
|
||||
{
|
||||
switch (blockOptionType)
|
||||
{
|
||||
case 1:
|
||||
if (resource->mReceiveHook != nullptr)
|
||||
{
|
||||
switch (ProcessBlock1Request(aMessage, aMessageInfo, *resource, totalTransfereSize))
|
||||
{
|
||||
case OT_ERROR_NONE:
|
||||
resource->HandleRequest(aMessage, aMessageInfo);
|
||||
// Fall through
|
||||
case OT_ERROR_BUSY:
|
||||
error = OT_ERROR_NONE;
|
||||
break;
|
||||
case OT_ERROR_NO_BUFS:
|
||||
IgnoreReturnValue(SendHeaderResponse(kCodeRequestTooLarge, aMessage, aMessageInfo));
|
||||
error = OT_ERROR_DROP;
|
||||
break;
|
||||
case OT_ERROR_NO_FRAME_RECEIVED:
|
||||
IgnoreReturnValue(SendHeaderResponse(kCodeRequestIncomplete, aMessage, aMessageInfo));
|
||||
error = OT_ERROR_DROP;
|
||||
break;
|
||||
default:
|
||||
IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
|
||||
error = OT_ERROR_DROP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (resource->mTransmitHook != nullptr)
|
||||
{
|
||||
if ((error = ProcessBlock2Request(aMessage, aMessageInfo, *resource)) != OT_ERROR_NONE)
|
||||
{
|
||||
IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
|
||||
error = OT_ERROR_DROP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
ExitNow();
|
||||
}
|
||||
else
|
||||
{
|
||||
resource->HandleRequest(aMessage, aMessageInfo);
|
||||
error = OT_ERROR_NONE;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
#else
|
||||
SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
for (const Resource *resource = mResources.GetHead(); resource; resource = resource->GetNext())
|
||||
{
|
||||
|
||||
+209
-1
@@ -169,13 +169,108 @@ public:
|
||||
*/
|
||||
const char *GetUriPath(void) const { return mUriPath; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
|
||||
{
|
||||
mHandler(mContext, &aMessage, &aMessageInfo);
|
||||
}
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This class implements CoAP block-wise resource handling.
|
||||
*
|
||||
*/
|
||||
class ResourceBlockWise : public otCoapBlockwiseResource
|
||||
{
|
||||
friend class CoapBase;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the resource.
|
||||
*
|
||||
* @param[in] aUriPath A pointer to a NULL-terminated string for the Uri-Path.
|
||||
* @param[in] aHandler A function pointer that is called when receiving a CoAP message for @p aUriPath.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aReceiveHook A function pointer that is called when receiving a CoAP block message for @p
|
||||
* aUriPath.
|
||||
* @param[in] aTransmitHook A function pointer that is called when transmitting a CoAP block message from @p
|
||||
* aUriPath.
|
||||
*/
|
||||
ResourceBlockWise(const char * aUriPath,
|
||||
otCoapRequestHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook)
|
||||
{
|
||||
mUriPath = aUriPath;
|
||||
mHandler = aHandler;
|
||||
mContext = aContext;
|
||||
mReceiveHook = aReceiveHook;
|
||||
mTransmitHook = aTransmitHook;
|
||||
mNext = nullptr;
|
||||
}
|
||||
|
||||
otError HandleBlockReceive(const uint8_t *aBlock,
|
||||
uint32_t aPosition,
|
||||
uint16_t aBlockLength,
|
||||
bool aMore,
|
||||
uint32_t aTotalLength) const
|
||||
{
|
||||
return mReceiveHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore, aTotalLength);
|
||||
}
|
||||
|
||||
otError HandleBlockTransmit(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore) const
|
||||
{
|
||||
return mTransmitHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the next entry in the linked list.
|
||||
*
|
||||
* @returns A pointer to the next entry in the linked list or nullptr if at the end of the list.
|
||||
*
|
||||
*/
|
||||
const ResourceBlockWise *GetNext(void) const
|
||||
{
|
||||
return static_cast<const ResourceBlockWise *>(static_cast<const ResourceBlockWise *>(this)->mNext);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the next entry in the linked list.
|
||||
*
|
||||
* @returns A pointer to the next entry in the linked list or nullptr if at the end of the list.
|
||||
*
|
||||
*/
|
||||
ResourceBlockWise *GetNext(void)
|
||||
{
|
||||
return static_cast<ResourceBlockWise *>(static_cast<ResourceBlockWise *>(this)->mNext);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the next pointer on the entry.
|
||||
*
|
||||
* @param[in] aNext A pointer to the next entry.
|
||||
*
|
||||
*/
|
||||
void SetNext(ResourceBlockWise *aNext) { static_cast<ResourceBlockWise *>(this)->mNext = aNext; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the URI path.
|
||||
*
|
||||
* @returns A pointer to the URI path.
|
||||
*
|
||||
*/
|
||||
const char *GetUriPath(void) const { return mUriPath; }
|
||||
|
||||
protected:
|
||||
void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
|
||||
{
|
||||
mHandler(mContext, &aMessage, &aMessageInfo);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This class caches CoAP responses to implement message deduplication.
|
||||
*
|
||||
@@ -269,6 +364,12 @@ class CoapBase : public InstanceLocator, private NonCopyable
|
||||
friend class ResponsesQueue;
|
||||
|
||||
public:
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
enum {
|
||||
kMaxBlockLength = OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function pointer is called before CoAP server processing a CoAP message.
|
||||
*
|
||||
@@ -298,6 +399,25 @@ public:
|
||||
*/
|
||||
void ClearRequests(const Ip6::Address &aAddress);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method adds a block-wise resource to the CoAP server.
|
||||
*
|
||||
* @param[in] aResource A reference to the resource.
|
||||
*
|
||||
*/
|
||||
void AddBlockWiseResource(ResourceBlockWise &aResource);
|
||||
|
||||
/**
|
||||
* This method removes a block-wise resource from the CoAP server.
|
||||
*
|
||||
* @param[in] aResource A reference to the resource.
|
||||
*
|
||||
*/
|
||||
void RemoveBlockWiseResource(ResourceBlockWise &aResource);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method adds a resource to the CoAP server.
|
||||
*
|
||||
@@ -343,6 +463,35 @@ public:
|
||||
return NewMessage(Message::Settings(Message::kWithLinkSecurity, Message::kPriorityNet));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This method sends a CoAP message block-wise with custom transmission parameters.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
|
||||
* @param[in] aTxParameters A reference to transmission parameters for this message.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
* @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
otError SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const TxParameters & aTxParameters,
|
||||
otCoapResponseHandler aHandler = nullptr,
|
||||
void * aContext = nullptr,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook = nullptr);
|
||||
#else // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message with custom transmission parameters.
|
||||
*
|
||||
@@ -365,6 +514,7 @@ public:
|
||||
const TxParameters & aTxParameters,
|
||||
ResponseHandler aHandler = nullptr,
|
||||
void * aContext = nullptr);
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message with default transmission parameters.
|
||||
@@ -453,6 +603,24 @@ public:
|
||||
*/
|
||||
otError SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This method sends a header-only CoAP message to indicate not all blocks have been sent or
|
||||
* were sent out of order.
|
||||
*
|
||||
* @param[in] aRequest A reference to the CoAP Message that was used in CoAP request.
|
||||
* @param[in] aMessageInfo The message info corresponding to the CoAP request.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
otError SendRequestEntityIncomplete(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
return SendHeaderResponse(kCodeRequestIncomplete, aRequest, aMessageInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method aborts CoAP transactions associated with given handler and context.
|
||||
*
|
||||
@@ -551,6 +719,12 @@ private:
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
bool mObserve : 1; // Information that this request involves Observations.
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otCoapBlockwiseReceiveHook mBlockwiseReceiveHook; // A function pointer that is called on Block2
|
||||
// response reception.
|
||||
otCoapBlockwiseTransmitHook mBlockwiseTransmitHook; // A function pointer that is called on Block1
|
||||
// response reception.
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -567,9 +741,38 @@ private:
|
||||
const Ip6::MessageInfo *aMessageInfo,
|
||||
otError aResult);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
void FreeLastBlockResponse(void);
|
||||
otError CacheLastBlockResponse(Message *aResponse);
|
||||
|
||||
otError PrepareNextBlockRequest(Message::BlockType aType,
|
||||
bool aMoreBlocks,
|
||||
Message & aRequestOld,
|
||||
Message & aRequest,
|
||||
Message & aMessage);
|
||||
otError ProcessBlock1Request(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const ResourceBlockWise &aResource,
|
||||
uint32_t aTotalLength);
|
||||
otError ProcessBlock2Request(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
const ResourceBlockWise &aResource);
|
||||
#endif
|
||||
void ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
void ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError SendNextBlock1Request(Message & aRequest,
|
||||
Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const Metadata & aCoapMetadata);
|
||||
otError SendNextBlock2Request(Message & aRequest,
|
||||
Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const Metadata & aCoapMetadata,
|
||||
uint32_t aTotalLength,
|
||||
bool aBeginBlock1Transfer);
|
||||
#endif
|
||||
void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
otError SendEmptyMessage(Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
@@ -589,6 +792,11 @@ private:
|
||||
void * mDefaultHandlerContext;
|
||||
|
||||
const Sender mSender;
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
LinkedList<ResourceBlockWise> mBlockWiseResources;
|
||||
Message * mLastResponse;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,11 @@ void Message::Init(void)
|
||||
GetHelpData().mHeaderLength = kMinHeaderLength;
|
||||
|
||||
IgnoreError(SetLength(GetHelpData().mHeaderLength));
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
SetBlockWiseBlockNumber(0);
|
||||
SetMoreBlocksFlag(false);
|
||||
SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_16);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Message::Init(Type aType, Code aCode)
|
||||
@@ -258,13 +263,13 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSize aSize)
|
||||
otError Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint32_t encoded = aSize;
|
||||
|
||||
VerifyOrExit(aType == kBlockType1 || aType == kBlockType2, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aSize <= OT_COAP_BLOCK_SIZE_1024, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aSize <= OT_COAP_OPTION_BLOCK_SZX_1024, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aNum < kBlockNumMax, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
encoded |= static_cast<uint32_t>(aMore << kBlockMOffset);
|
||||
@@ -276,6 +281,49 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError Message::ReadBlockOptionValues(uint16_t aBlockType)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t buf[kMaxOptionHeaderSize] = {0};
|
||||
Option::Iterator iterator;
|
||||
|
||||
VerifyOrExit((aBlockType == kOptionBlock1) || (aBlockType == kOptionBlock2), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = iterator.Init(*this, aBlockType));
|
||||
SuccessOrExit(error = iterator.ReadOptionValue(buf));
|
||||
|
||||
SetBlockWiseBlockNumber(0);
|
||||
SetMoreBlocksFlag(false);
|
||||
|
||||
switch (iterator.GetOption()->GetLength())
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] & 0xf0) >> 4));
|
||||
SetMoreBlocksFlag(static_cast<bool>((buf[0] & 0x08) >> 3 == 1));
|
||||
SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[0] & 0x07));
|
||||
break;
|
||||
case 2:
|
||||
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 4) + ((buf[1] & 0xf0) >> 4)));
|
||||
SetMoreBlocksFlag(static_cast<bool>((buf[1] & 0x08) >> 3 == 1));
|
||||
SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[1] & 0x07));
|
||||
break;
|
||||
case 3:
|
||||
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 12) + (buf[1] << 4) + ((buf[2] & 0xf0) >> 4)));
|
||||
SetMoreBlocksFlag(static_cast<bool>((buf[2] & 0x08) >> 3 == 1));
|
||||
SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[2] & 0x07));
|
||||
break;
|
||||
default:
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
otError Message::SetPayloadMarker(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
@@ -149,6 +149,7 @@ enum : uint16_t
|
||||
kOptionLocationQuery = OT_COAP_OPTION_LOCATION_QUERY, ///< Location-Query
|
||||
kOptionBlock2 = OT_COAP_OPTION_BLOCK2, ///< Block2 (RFC7959)
|
||||
kOptionBlock1 = OT_COAP_OPTION_BLOCK1, ///< Block1 (RFC7959)
|
||||
kOptionSize2 = OT_COAP_OPTION_SIZE2, ///< Size2 (RFC7959)
|
||||
kOptionProxyUri = OT_COAP_OPTION_PROXY_URI, ///< Proxy-Uri
|
||||
kOptionProxyScheme = OT_COAP_OPTION_PROXY_SCHEME, ///< Proxy-Scheme
|
||||
kOptionSize1 = OT_COAP_OPTION_SIZE1, ///< Size1
|
||||
@@ -507,7 +508,7 @@ public:
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
otError AppendBlockOption(BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSize aSize);
|
||||
otError AppendBlockOption(BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize);
|
||||
|
||||
/**
|
||||
* This method appends a Proxy-Uri option.
|
||||
@@ -558,6 +559,62 @@ public:
|
||||
*/
|
||||
otError AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This function reads the information contained in a Block1 or Block2 option and set it in
|
||||
* the HelpData of the message.
|
||||
*
|
||||
* @param[in] aBlockType Block1 or Block2 option value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The option has been found and is valid.
|
||||
* @retval OT_ERROR_NOT_FOUND The option has not been found.
|
||||
* @retval OT_ERROR_INVALID_ARGS The option is invalid.
|
||||
*/
|
||||
otError ReadBlockOptionValues(uint16_t aBlockType);
|
||||
|
||||
/**
|
||||
* This method returns the current header length of a message.
|
||||
*
|
||||
* @returns The length of the message header.
|
||||
*
|
||||
*/
|
||||
uint16_t GetHeaderLength(void) const { return GetHelpData().mHeaderLength; }
|
||||
|
||||
/**
|
||||
* This method returns the block number of a CoAP block-wise transfer message.
|
||||
*
|
||||
* @returns The block number.
|
||||
*
|
||||
*/
|
||||
uint32_t GetBlockWiseBlockNumber(void) const { return GetHelpData().mBlockWiseData.mBlockNumber; }
|
||||
|
||||
/**
|
||||
* This method checks if the More Blocks flag is set.
|
||||
*
|
||||
* @retval TRUE More Blocks flag is set.
|
||||
* @retval FALSE More Blocks flag is not set.
|
||||
*
|
||||
*/
|
||||
bool IsMoreBlocksFlagSet(void) const { return GetHelpData().mBlockWiseData.mMoreBlocks; }
|
||||
|
||||
/**
|
||||
* This method returns the block size of a CoAP block-wise transfer message.
|
||||
*
|
||||
* @returns The block size.
|
||||
*
|
||||
*/
|
||||
otCoapBlockSzx GetBlockWiseBlockSize(void) const { return GetHelpData().mBlockWiseData.mBlockSize; }
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This function reads and reassembles the URI path string and fills it into @p aUriPath.
|
||||
*
|
||||
* @retval OT_ERROR_NONE URI path string has been reassembled.
|
||||
* @retval OT_ERROR_NO_BUFS URI path string is too long.
|
||||
*
|
||||
*/
|
||||
otError GetUriPath(char *aUriPath) const;
|
||||
|
||||
/**
|
||||
* This method adds Payload Marker indicating beginning of the payload to the CoAP header.
|
||||
*
|
||||
@@ -597,6 +654,33 @@ public:
|
||||
*/
|
||||
otError SetDefaultResponseHeader(const Message &aRequest);
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method sets the block number value in the message HelpData.
|
||||
*
|
||||
* @param[in] aBlockNumber Block number value to set.
|
||||
*
|
||||
*/
|
||||
void SetBlockWiseBlockNumber(uint32_t aBlockNumber) { GetHelpData().mBlockWiseData.mBlockNumber = aBlockNumber; }
|
||||
|
||||
/**
|
||||
* This method sets the More Blocks falg in the message HelpData.
|
||||
*
|
||||
* @param[in] aMoreBlocks TRUE or FALSE.
|
||||
*
|
||||
*/
|
||||
void SetMoreBlocksFlag(bool aMoreBlocks) { GetHelpData().mBlockWiseData.mMoreBlocks = aMoreBlocks; }
|
||||
|
||||
/**
|
||||
* This method sets the block size value in the message HelpData.
|
||||
*
|
||||
* @param[in] aBlockSize Block size value to set.
|
||||
*
|
||||
*/
|
||||
void SetBlockWiseBlockSize(otCoapBlockSzx aBlockSize) { GetHelpData().mBlockWiseData.mBlockSize = aBlockSize; }
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method checks if a header is an empty message header.
|
||||
*
|
||||
@@ -845,6 +929,15 @@ private:
|
||||
kBlockNumMax = 0xffff,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
struct BlockWiseData
|
||||
{
|
||||
uint32_t mBlockNumber;
|
||||
bool mMoreBlocks;
|
||||
otCoapBlockSzx mBlockSize;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP header excluding CoAP options.
|
||||
*
|
||||
@@ -868,6 +961,9 @@ private:
|
||||
uint16_t mOptionLast;
|
||||
uint16_t mHeaderOffset; ///< The byte offset for the CoAP Header
|
||||
uint16_t mHeaderLength;
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
BlockWiseData mBlockWiseData;
|
||||
#endif
|
||||
};
|
||||
|
||||
const HelpData &GetHelpData(void) const
|
||||
|
||||
@@ -118,6 +118,35 @@ void CoapSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd)
|
||||
OT_ASSERT(error == OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError CoapSecure::SendMessage(Message & aMessage,
|
||||
ResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(IsConnected(), error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
error = CoapBase::SendMessage(aMessage, mDtls.GetMessageInfo(), TxParameters::GetDefault(), aHandler, aContext,
|
||||
aTransmitHook, aReceiveHook);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError CoapSecure::SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
ResponseHandler aHandler,
|
||||
void * aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook)
|
||||
{
|
||||
return CoapBase::SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext, aTransmitHook,
|
||||
aReceiveHook);
|
||||
}
|
||||
#else // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
otError CoapSecure::SendMessage(Message &aMessage, ResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -137,6 +166,7 @@ otError CoapSecure::SendMessage(Message & aMessage,
|
||||
{
|
||||
return CoapBase::SendMessage(aMessage, aMessageInfo, aHandler, aContext);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
otError CoapSecure::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
|
||||
@@ -272,6 +272,57 @@ public:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This method sends a CoAP message over secure DTLS connection.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
* @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
* @retval OT_ERROR_INVALID_STATE DTLS connection was not initialized.
|
||||
*
|
||||
*/
|
||||
otError SendMessage(Message & aMessage,
|
||||
ResponseHandler aHandler = nullptr,
|
||||
void * aContext = nullptr,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook = nullptr);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message over secure DTLS connection.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
|
||||
* @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
* @retval OT_ERROR_INVALID_STATE DTLS connection was not initialized.
|
||||
*
|
||||
*/
|
||||
otError SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo & aMessageInfo,
|
||||
ResponseHandler aHandler = nullptr,
|
||||
void * aContext = nullptr,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
|
||||
otCoapBlockwiseReceiveHook aReceiveHook = nullptr);
|
||||
#else // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
/**
|
||||
* This method sends a CoAP message over secure DTLS connection.
|
||||
*
|
||||
@@ -311,6 +362,7 @@ public:
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
ResponseHandler aHandler = nullptr,
|
||||
void * aContext = nullptr);
|
||||
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
|
||||
/**
|
||||
* This method is used to pass UDP messages to the secure CoAP server.
|
||||
|
||||
@@ -67,6 +67,26 @@
|
||||
#define OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
*
|
||||
* Define to 1 to enable the CoAP Block-Wise Transfer.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
|
||||
#define OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH
|
||||
*
|
||||
* This setting configures the maximum length of one block during a CoAP Block-Wise Transfer.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH
|
||||
#define OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH 1024
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
|
||||
*
|
||||
|
||||
@@ -154,6 +154,7 @@ EXTRA_DIST = \
|
||||
test_coap.py \
|
||||
test_coap_observe.py \
|
||||
test_coaps.py \
|
||||
test_coap_block.py \
|
||||
test_common.py \
|
||||
test_crypto.py \
|
||||
test_diag.py \
|
||||
@@ -205,6 +206,7 @@ check_SCRIPTS = \
|
||||
test_coap.py \
|
||||
test_coap_observe.py \
|
||||
test_coaps.py \
|
||||
test_coap_block.py \
|
||||
test_common.py \
|
||||
test_crypto.py \
|
||||
test_diag.py \
|
||||
|
||||
@@ -1884,6 +1884,12 @@ class NodeImpl:
|
||||
"""
|
||||
return self._coap_rq('get', ipaddr, uri, con, payload)
|
||||
|
||||
def coap_get_block(self, ipaddr, uri, size=16, count=0):
|
||||
"""
|
||||
Send a GET request via CoAP.
|
||||
"""
|
||||
return self._coap_rq_block('get', ipaddr, uri, size, count)
|
||||
|
||||
def coap_observe(self, ipaddr, uri, con=False, payload=None):
|
||||
"""
|
||||
Send a GET request via CoAP with Observe set.
|
||||
@@ -1896,12 +1902,24 @@ class NodeImpl:
|
||||
"""
|
||||
return self._coap_rq('post', ipaddr, uri, con, payload)
|
||||
|
||||
def coap_post_block(self, ipaddr, uri, size=16, count=0):
|
||||
"""
|
||||
Send a POST request via CoAP.
|
||||
"""
|
||||
return self._coap_rq_block('post', ipaddr, uri, size, count)
|
||||
|
||||
def coap_put(self, ipaddr, uri, con=False, payload=None):
|
||||
"""
|
||||
Send a PUT request via CoAP.
|
||||
"""
|
||||
return self._coap_rq('put', ipaddr, uri, con, payload)
|
||||
|
||||
def coap_put_block(self, ipaddr, uri, size=16, count=0):
|
||||
"""
|
||||
Send a PUT request via CoAP.
|
||||
"""
|
||||
return self._coap_rq_block('put', ipaddr, uri, size, count)
|
||||
|
||||
def _coap_rq(self, method, ipaddr, uri, con=False, payload=None):
|
||||
"""
|
||||
Issue a GET/POST/PUT/DELETE/GET OBSERVE request.
|
||||
@@ -1918,6 +1936,20 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
return self.coap_wait_response()
|
||||
|
||||
def _coap_rq_block(self, method, ipaddr, uri, size=16, count=0):
|
||||
"""
|
||||
Issue a GET/POST/PUT/DELETE/GET OBSERVE BLOCK request.
|
||||
"""
|
||||
cmd = 'coap %s %s %s' % (method, ipaddr, uri)
|
||||
|
||||
cmd += ' block-%d' % size
|
||||
|
||||
if count is not 0:
|
||||
cmd += ' %d' % count
|
||||
|
||||
self.send_command(cmd)
|
||||
return self.coap_wait_response()
|
||||
|
||||
def coap_wait_response(self):
|
||||
"""
|
||||
Wait for a CoAP response, and return it.
|
||||
@@ -1938,7 +1970,10 @@ class NodeImpl:
|
||||
observe = int(observe, base=10)
|
||||
|
||||
if payload is not None:
|
||||
payload = binascii.a2b_hex(payload).decode('UTF-8')
|
||||
try:
|
||||
payload = binascii.a2b_hex(payload).decode('UTF-8')
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
# Return the values received
|
||||
return dict(source=source, observe=observe, payload=payload)
|
||||
@@ -2004,6 +2039,14 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def coap_set_resource_path_block(self, path, count=0):
|
||||
"""
|
||||
Set the path for the CoAP resource and how many blocks can be received from this resource.
|
||||
"""
|
||||
cmd = 'coap resource %s %d' % (path, count)
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def coap_set_content(self, content):
|
||||
"""
|
||||
Set the content of the CoAP resource.
|
||||
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2020, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import pexpect
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
LEADER = 1
|
||||
ROUTER = 2
|
||||
|
||||
|
||||
class TestCoapBlockTransfer(thread_cert.TestCase):
|
||||
"""
|
||||
Test suite for CoAP Block-Wise Transfers (RFC7959).
|
||||
"""
|
||||
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'mode': 'rdn',
|
||||
'panid': 0xface,
|
||||
'whitelist': [ROUTER]
|
||||
},
|
||||
ROUTER: {
|
||||
'mode': 'rdn',
|
||||
'panid': 0xface,
|
||||
'router_selection_jitter': 1,
|
||||
'whitelist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def _do_transfer_test(self, method):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
|
||||
|
||||
mleid = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
|
||||
self.nodes[LEADER].coap_start()
|
||||
self.nodes[LEADER].coap_set_resource_path_block('test', 10)
|
||||
|
||||
self.nodes[ROUTER].coap_start()
|
||||
|
||||
if method == 'GET':
|
||||
response = self.nodes[ROUTER].coap_get_block(mleid, 'test', size=32)
|
||||
response_payload = response['payload']
|
||||
self.assertIsNotNone(response_payload)
|
||||
|
||||
if method == 'PUT':
|
||||
self.nodes[ROUTER].coap_put_block(mleid, 'test', size=256, count=2)
|
||||
request = self.nodes[ROUTER].coap_wait_request()
|
||||
request_payload = request['payload']
|
||||
self.assertIsNotNone(request_payload)
|
||||
|
||||
if method == 'POST':
|
||||
self.nodes[ROUTER].coap_post_block(mleid, 'test', size=1024, count=2)
|
||||
request = self.nodes[ROUTER].coap_wait_request()
|
||||
request_payload = request['payload']
|
||||
self.assertIsNotNone(request_payload)
|
||||
|
||||
self.simulator.go(10)
|
||||
|
||||
self.nodes[ROUTER].coap_stop()
|
||||
self.nodes[LEADER].coap_stop()
|
||||
|
||||
def test_get(self):
|
||||
"""
|
||||
Test block-wise transfer using GET method.
|
||||
"""
|
||||
for trial in range(0, 3):
|
||||
try:
|
||||
self._do_transfer_test(method='GET')
|
||||
break
|
||||
except (AssertionError, pexpect.exceptions.TIMEOUT):
|
||||
continue
|
||||
|
||||
def test_put(self):
|
||||
"""
|
||||
Test block-wise transfer using PUT method.
|
||||
"""
|
||||
for trial in range(0, 3):
|
||||
try:
|
||||
self._do_transfer_test(method='PUT')
|
||||
break
|
||||
except (AssertionError, pexpect.exceptions.TIMEOUT):
|
||||
continue
|
||||
|
||||
def test_post(self):
|
||||
"""
|
||||
Test block-wise transfer using POST method.
|
||||
"""
|
||||
for trial in range(0, 3):
|
||||
try:
|
||||
self._do_transfer_test(method='POST')
|
||||
break
|
||||
except (AssertionError, pexpect.exceptions.TIMEOUT):
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user