[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:
Aurelio Schellenbaum
2021-01-26 13:27:32 -08:00
committed by GitHub
parent a3b5e370be
commit 02d6d49a5e
26 changed files with 2310 additions and 63 deletions
+5
View File
@@ -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")
+1
View File
@@ -38,6 +38,7 @@ DEBUG ?= 0
BORDER_AGENT ?= 1
BORDER_ROUTER ?= 1
COAP ?= 1
COAP_BLOCK ?= 1
COAP_OBSERVE ?= 1
COAPS ?= 1
COMMISSIONER ?= 1
+5
View File
@@ -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
View File
@@ -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.
*
+69
View File
@@ -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.
*
+1 -1
View File
@@ -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
+1
View File
@@ -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"
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+28
View File
@@ -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
View File
@@ -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
+30 -2
View File
@@ -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
+63 -3
View File
@@ -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,
+46
View File
@@ -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);
+662
View File
@@ -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
View File
@@ -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
};
/**
+50 -2
View File
@@ -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;
+97 -1
View File
@@ -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
+30
View File
@@ -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)
{
+52
View File
@@ -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.
+20
View File
@@ -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
*
+2
View File
@@ -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 \
+44 -1
View File
@@ -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.
+134
View File
@@ -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()